From 86d6adc93120355c5e4a6c1c9d835f01092e3ae2 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Wed, 26 Jun 2024 17:02:15 -0400 Subject: [PATCH] Set glyph_padding to 4 (when using 8x8 over_sample we need more padding) --- code/font/VEFontCache/Readme.md | 2 -- code/font/VEFontCache/VEFontCache.odin | 6 ++--- code/font/VEFontCache/atlas.odin | 14 +++++----- code/font/VEFontCache/docs/Readme.md | 2 ++ code/font/VEFontCache/draw.odin | 14 +++++----- code/font/VEFontCache/misc.odin | 37 +++++++++++--------------- code/font/VEFontCache/shaped_text.odin | 13 ++++----- 7 files changed, 42 insertions(+), 46 deletions(-) diff --git a/code/font/VEFontCache/Readme.md b/code/font/VEFontCache/Readme.md index d9e78e8..44c6ea8 100644 --- a/code/font/VEFontCache/Readme.md +++ b/code/font/VEFontCache/Readme.md @@ -6,8 +6,6 @@ Its original purpose was for use in game engines, however its rendeirng quality TODO (Making it a more idiomatic library): -* Use Odin's builtin dynamic arrays -* Use Odin's builtin map type * Setup freetype, harfbuzz, depedency management within the library TODO Documentation: diff --git a/code/font/VEFontCache/VEFontCache.odin b/code/font/VEFontCache/VEFontCache.odin index fa946ff..b35bc32 100644 --- a/code/font/VEFontCache/VEFontCache.odin +++ b/code/font/VEFontCache/VEFontCache.odin @@ -21,8 +21,8 @@ Vec2 :: [2]f32 Vec2i :: [2]i32 Vec2_64 :: [2]f64 -vec2_from_scalar :: #force_inline proc( scalar : f32 ) -> Vec2 { return { scalar, scalar } } -vec2_64_from_vec2 :: #force_inline proc( v2 : Vec2 ) -> Vec2_64 { return { f64(v2.x), f64(v2.y) }} +vec2_from_scalar :: #force_inline proc "contextless" ( scalar : f32 ) -> Vec2 { return { scalar, scalar } } +vec2_64_from_vec2 :: #force_inline proc "contextless" ( v2 : Vec2 ) -> Vec2_64 { return { f64(v2.x), f64(v2.y) }} vec2_from_vec2i :: #force_inline proc( v2i : Vec2i ) -> Vec2 { return { f32(v2i.x), f32(v2i.y) }} FontID :: distinct i64 @@ -104,7 +104,7 @@ InitAtlasParams :: struct { InitAtlasParams_Default :: InitAtlasParams { width = 4096, height = 2048, - glyph_padding = 1, + glyph_padding = 4, region_a = { width = 32, diff --git a/code/font/VEFontCache/atlas.odin b/code/font/VEFontCache/atlas.odin index 554f4cf..88c4f05 100644 --- a/code/font/VEFontCache/atlas.odin +++ b/code/font/VEFontCache/atlas.odin @@ -41,7 +41,7 @@ atlas_bbox :: proc( atlas : ^Atlas, region : AtlasRegionKind, local_idx : i32 ) { case .A: width = f32(atlas.region_a.width) - height = f32(atlas.region_b.height) + height = f32(atlas.region_a.height) position.x = cast(f32) (( local_idx % atlas.region_a.capacity.x ) * i32(atlas.region_a.width)) position.y = cast(f32) (( local_idx / atlas.region_a.capacity.x ) * i32(atlas.region_a.height)) @@ -123,7 +123,7 @@ can_batch_glyph :: #force_inline proc( ctx : ^Context, font : FontID, entry : ^E return true } -decide_codepoint_region :: #force_inline proc( ctx : ^Context, entry : ^Entry, glyph_index : Glyph +decide_codepoint_region :: proc( ctx : ^Context, entry : ^Entry, glyph_index : Glyph ) -> (region_kind : AtlasRegionKind, region : ^AtlasRegion, over_sample : Vec2) { if parser_is_glyph_empty( & entry.parser_info, glyph_index ) { @@ -131,14 +131,16 @@ decide_codepoint_region :: #force_inline proc( ctx : ^Context, entry : ^Entry, g } bounds_0, bounds_1 := parser_get_glyph_box( & entry.parser_info, glyph_index ) - bounds_width := bounds_1.x - bounds_0.x - bounds_height := bounds_1.y - bounds_0.y + bounds_width := f32(bounds_1.x - bounds_0.x) + bounds_height := f32(bounds_1.y - bounds_0.y) atlas := & ctx.atlas glyph_buffer := & ctx.glyph_buffer - bounds_width_scaled := cast(u32) (f32(bounds_width) * entry.size_scale + 2.0 * f32(atlas.glyph_padding)) - bounds_height_scaled := cast(u32) (f32(bounds_height) * entry.size_scale + 2.0 * f32(atlas.glyph_padding)) + glyph_padding := f32(atlas.glyph_padding) * 2 + + bounds_width_scaled := cast(u32) (bounds_width * entry.size_scale + glyph_padding) + bounds_height_scaled := cast(u32) (bounds_height * entry.size_scale + glyph_padding) if bounds_width_scaled <= atlas.region_a.width && bounds_height_scaled <= atlas.region_a.height { diff --git a/code/font/VEFontCache/docs/Readme.md b/code/font/VEFontCache/docs/Readme.md index 9a9f4aa..7a3c91a 100644 --- a/code/font/VEFontCache/docs/Readme.md +++ b/code/font/VEFontCache/docs/Readme.md @@ -70,4 +70,6 @@ Will update the draw list layer with the latest offset based on the current leng Provides a Vec2 the width and height occupied by the provided text string. The y is measured to be the the largest glyph box bounds height of the text. The width is derived from the `end_cursor_pos` field from a `ShapedText` entry. +## get_font_vertical_metrics +A wrapper for `parser_get_font_vertical_metrics`. Will provide the ascent, descent, and line_gap for a font entry. diff --git a/code/font/VEFontCache/draw.odin b/code/font/VEFontCache/draw.odin index 8391bd7..2db2e8f 100644 --- a/code/font/VEFontCache/draw.odin +++ b/code/font/VEFontCache/draw.odin @@ -224,7 +224,7 @@ cache_glyph_to_atlas :: proc( ctx : ^Context, region : ^AtlasRegion, over_sample : Vec2 ) { - // profile(#procedure) + profile(#procedure) // Get hb_font text metrics. These are unscaled! bounds_0, bounds_1 := parser_get_glyph_box( & entry.parser_info, glyph_index ) @@ -283,8 +283,8 @@ cache_glyph_to_atlas :: proc( ctx : ^Context, glyph_draw_translate.y = cast(f32) (i32(glyph_draw_translate.y + 0.9999999)) // Allocate a glyph_update_FBO region - gwidth_scaled_px := i32( bounds_width * glyph_draw_scale.x + 1.0 ) + i32(over_sample.x * glyph_padding) - if i32(glyph_buffer.batch_x + gwidth_scaled_px) >= i32(glyph_buffer.width) { + gwidth_scaled_px := bounds_width * glyph_draw_scale.x + 1.0 + over_sample.x * glyph_padding + if i32(f32(glyph_buffer.batch_x) + gwidth_scaled_px) >= i32(glyph_buffer.width) { flush_glyph_buffer_to_atlas( ctx ) } @@ -311,7 +311,7 @@ cache_glyph_to_atlas :: proc( ctx : ^Context, // Advance glyph_update_batch_x and calculate final glyph drawing transform glyph_draw_translate.x += f32(glyph_buffer.batch_x) - glyph_buffer.batch_x += gwidth_scaled_px + glyph_buffer.batch_x += i32(gwidth_scaled_px) screenspace_x_form( & glyph_draw_translate, & glyph_draw_scale, glyph_buffer_width, glyph_buffer_height ) call : DrawCall @@ -524,7 +524,7 @@ draw_filled_path :: proc( draw_list : ^DrawList, outside_point : Vec2, path : [] append( & draw_list.vertices, vertex ) } - for index : u32 = 1; index < u32(len(path)); index += 1 { + for index : u32 = 1; index < cast(u32) len(path); index += 1 { indices := & draw_list.indices append( indices, outside_vertex ) append( indices, v_offset + index - 1 ) @@ -577,7 +577,7 @@ draw_text_shape :: proc( ctx : ^Context, // position := position //+ ctx.cursor_pos * scale // profile(#procedure) batch_start_idx : i32 = 0 - for index : i32 = 0; index < i32(len(shaped.glyphs)); index += 1 + for index : i32 = 0; index < cast(i32) len(shaped.glyphs); index += 1 { glyph_index := shaped.glyphs[ index ] if is_empty( ctx, entry, glyph_index ) do continue @@ -602,7 +602,7 @@ draw_text_shape :: proc( ctx : ^Context, } // flush_glyph_buffer_to_atlas(ctx) - draw_text_batch( ctx, entry, shaped, batch_start_idx, i32(len(shaped.glyphs)), position, scale, snap_width , snap_height ) + draw_text_batch( ctx, entry, shaped, batch_start_idx, cast(i32) len(shaped.glyphs), position, scale, snap_width , snap_height ) reset_batch_codepoint_state( ctx ) cursor_pos = shaped.end_cursor_pos return diff --git a/code/font/VEFontCache/misc.odin b/code/font/VEFontCache/misc.odin index 860c57a..aae2ee6 100644 --- a/code/font/VEFontCache/misc.odin +++ b/code/font/VEFontCache/misc.odin @@ -30,10 +30,10 @@ shape_lru_hash :: #force_inline proc "contextless" ( label : string ) -> u64 { // ve_fontcache_eval_bezier (quadratic) eval_point_on_bezier3 :: #force_inline proc "contextless" ( p0, p1, p2 : Vec2, alpha : f32 ) -> Vec2 { - // p0 := vec2_64_from_vec2(p0) - // p1 := vec2_64_from_vec2(p1) - // p2 := vec2_64_from_vec2(p2) - // alpha := f64(alpha) + p0 := vec2_64(p0) + p1 := vec2_64(p1) + p2 := vec2_64(p2) + alpha := f64(alpha) weight_start := (1 - alpha) * (1 - alpha) weight_control := 2.0 * (1 - alpha) * alpha @@ -52,11 +52,11 @@ eval_point_on_bezier3 :: #force_inline proc "contextless" ( p0, p1, p2 : Vec2, a // ve_fontcache_eval_bezier (cubic) eval_point_on_bezier4 :: #force_inline proc "contextless" ( p0, p1, p2, p3 : Vec2, alpha : f32 ) -> Vec2 { - // p0 := vec2_64_from_vec2(p0) - // p1 := vec2_64_from_vec2(p1) - // p2 := vec2_64_from_vec2(p2) - // p3 := vec2_64_from_vec2(p3) - // alpha := f64(alpha) + p0 := vec2_64(p0) + p1 := vec2_64(p1) + p2 := vec2_64(p2) + p3 := vec2_64(p3) + alpha := f64(alpha) weight_start := (1 - alpha) * (1 - alpha) * (1 - alpha) weight_c_a := 3 * (1 - alpha) * (1 - alpha) * alpha @@ -91,7 +91,7 @@ reset_batch_codepoint_state :: #force_inline proc( ctx : ^Context ) { } screenspace_x_form :: #force_inline proc "contextless" ( position, scale : ^Vec2, width, height : f32 ) { - when false + when true { pos_64 := vec2_64_from_vec2(position^) scale_64 := vec2_64_from_vec2(scale^) @@ -108,15 +108,13 @@ screenspace_x_form :: #force_inline proc "contextless" ( position, scale : ^Vec2 else { quotient : Vec2 = 1.0 / { width, height } - pos := position^ * quotient * 2.0 - 1.0 - s := scale^ * quotient * 2.0 - (position^) = { f32(pos.x), f32(pos.y) } - (scale^) = { f32(s.x), f32(s.y) } + (position^) *= quotient * 2.0 - 1.0 + (scale^) *= quotient * 2.0 } } textspace_x_form :: #force_inline proc "contextless" ( position, scale : ^Vec2, width, height : f32 ) { - when false + when true { pos_64 := vec2_64_from_vec2(position^) scale_64 := vec2_64_from_vec2(scale^) @@ -132,13 +130,8 @@ textspace_x_form :: #force_inline proc "contextless" ( position, scale : ^Vec2, } else { - pos := position^ - s := scale^ - quotient : Vec2 = 1.0 / { width, height } - pos *= quotient - s *= quotient - (position^) = { f32(pos.x), f32(pos.y) } - (scale^) = { f32(s.x), f32(s.y) } + (position^) *= quotient + (scale^) *= quotient } } diff --git a/code/font/VEFontCache/shaped_text.odin b/code/font/VEFontCache/shaped_text.odin index dc318b2..510ed30 100644 --- a/code/font/VEFontCache/shaped_text.odin +++ b/code/font/VEFontCache/shaped_text.odin @@ -62,6 +62,7 @@ shape_text_cached :: proc( ctx : ^Context, font : FontID, text_utf8 : string, en return & shape_cache.storage[ shape_cache_idx ] } +// TODO(Ed): Make position rounding an option shape_text_uncached :: proc( ctx : ^Context, font : FontID, text_utf8 : string, entry : ^Entry, output : ^ShapedText ) { // profile(#procedure) @@ -105,7 +106,7 @@ shape_text_uncached :: proc( ctx : ^Context, font : FontID, text_utf8 : string, { position.x = 0.0 position.y -= (ascent - descent + line_gap) * entry.size_scale - position.y = cast(f32) i32( position.y + 0.5 ) + position.y = ceil(position.y) prev_codepoint = rune(0) continue } @@ -116,11 +117,11 @@ shape_text_uncached :: proc( ctx : ^Context, font : FontID, text_utf8 : string, append( & output.glyphs, parser_find_glyph_index( & entry.parser_info, codepoint )) advance, to_left_side_glyph = parser_get_codepoint_horizontal_metrics( & entry.parser_info, codepoint ) - // append( & output.positions, Vec2 { - // cast(f32) i32(position.x + 0.5), - // position.y - // }) - append( & output.positions, position ) + append( & output.positions, Vec2 { + ceil(position.x), + position.y + }) + // append( & output.positions, position ) position.x += f32(advance) * entry.size_scale prev_codepoint = codepoint