diff --git a/code/font/VEFontCache/VEFontCache.odin b/code/font/VEFontCache/VEFontCache.odin index 2ed74ed..7e8b08c 100644 --- a/code/font/VEFontCache/VEFontCache.odin +++ b/code/font/VEFontCache/VEFontCache.odin @@ -17,11 +17,13 @@ import "core:mem" Advance_Snap_Smallfont_Size :: 12 -Colour :: [4]f32 -Vec2 :: [2]f32 -Vec2i :: [2]i32 +Colour :: [4]f32 +Vec2 :: [2]f32 +Vec2i :: [2]i32 +Vec2_64 :: [2]f64 -vec2_from_scalar :: proc( scalar : f32 ) -> Vec2 { return { scalar, scalar } } +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) }} FontID :: distinct i64 Glyph :: distinct i32 @@ -98,7 +100,7 @@ InitAtlasParams :: struct { InitAtlasParams_Default :: InitAtlasParams { width = 4096, height = 2048, - glyph_padding = 1, + glyph_padding = 2, region_a = { width = 32, @@ -125,9 +127,10 @@ InitGlyphDrawParams :: struct { } InitGlyphDrawParams_Default :: InitGlyphDrawParams { - over_sample = { 8, 8 }, + over_sample = { 4, 4 }, buffer_batch = 4, draw_padding = InitAtlasParams_Default.glyph_padding, + // draw_padding = InitAtlasParams_Default.glyph_padding, } InitShapeCacheParams :: struct { @@ -159,7 +162,7 @@ init :: proc( ctx : ^Context, parser_kind : ParserKind, context.allocator = ctx.backing if curve_quality == 0 { - curve_quality = 6 + curve_quality = 12 } ctx.curve_quality = curve_quality @@ -525,8 +528,8 @@ cache_glyph_to_atlas :: proc( ctx : ^Context, font : FontID, glyph_index : Glyph // Get hb_font text metrics. These are unscaled! 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) region_kind, region, over_sample := decide_codepoint_region( ctx, entry, glyph_index ) @@ -560,8 +563,12 @@ cache_glyph_to_atlas :: proc( ctx : ^Context, font : FontID, glyph_index : Glyph assert( LRU_get( & region.state, lru_code ) != - 1 ) } - atlas := & ctx.atlas - glyph_padding := cast(f32) atlas.glyph_padding + atlas := & ctx.atlas + atlas_width := f32(atlas.width) + atlas_height := f32(atlas.height) + glyph_buffer_width := f32(atlas.buffer_width) + glyph_buffer_height := f32(atlas.buffer_height) + glyph_padding := cast(f32) atlas.glyph_padding if ctx.debug_print { @@ -572,42 +579,41 @@ cache_glyph_to_atlas :: proc( ctx : ^Context, font : FontID, glyph_index : Glyph // Draw oversized glyph to update FBO glyph_draw_scale := over_sample * entry.size_scale - glyph_draw_translate := Vec2 { -f32(bounds_0.x), -f32(bounds_0.y) } * glyph_draw_scale + Vec2{ glyph_padding, glyph_padding } + glyph_draw_translate := -1 * Vec2 { f32(bounds_0.x), f32(bounds_0.y) } * glyph_draw_scale + vec2( glyph_padding ) glyph_draw_translate.x = cast(f32) (i32(glyph_draw_translate.x + 0.9999999)) glyph_draw_translate.y = cast(f32) (i32(glyph_draw_translate.y + 0.9999999)) // Allocate a glyph_update_FBO region - gwidth_scaled_px := i32( f32(bounds_width) * f32(glyph_draw_scale.x) + 1.0 ) + i32(2 * over_sample.x * glyph_padding) + gwidth_scaled_px := i32( bounds_width * glyph_draw_scale.x + 1.0 ) + i32(over_sample.x * glyph_padding) if i32(atlas.update_batch_x + gwidth_scaled_px) >= i32(atlas.buffer_width) { flush_glyph_buffer_to_atlas( ctx ) } // Calculate the src and destination regions dst_position, dst_width, dst_height := atlas_bbox( atlas, region_kind, atlas_index ) - dst_glyph_position := dst_position + { glyph_padding, glyph_padding } - dst_glyph_width := f32(bounds_width) * entry.size_scale - dst_glyph_height := f32(bounds_height) * entry.size_scale - dst_glyph_position -= { glyph_padding, glyph_padding } - dst_glyph_width += 2 * glyph_padding - dst_glyph_height += 2 * glyph_padding + dst_glyph_position := dst_position + dst_glyph_width := bounds_width * entry.size_scale + dst_glyph_height := bounds_height * entry.size_scale + dst_glyph_width += glyph_padding + dst_glyph_height += glyph_padding dst_size := Vec2 { dst_width, dst_height } dst_glyph_size := Vec2 { dst_glyph_width, dst_glyph_height } - screenspace_x_form( & dst_glyph_position, & dst_glyph_size, f32(atlas.width), f32(atlas.height) ) - screenspace_x_form( & dst_position, & dst_size, f32(atlas.width), f32(atlas.height) ) + screenspace_x_form( & dst_glyph_position, & dst_glyph_size, atlas_width, atlas_height ) + screenspace_x_form( & dst_position, & dst_size, atlas_width, atlas_height ) src_position := Vec2 { f32(atlas.update_batch_x), 0 } src_size := Vec2 { - f32(bounds_width) * glyph_draw_scale.x, - f32(bounds_height) * glyph_draw_scale.y, + bounds_width * glyph_draw_scale.x, + bounds_height * glyph_draw_scale.y, } - src_size += 2 * over_sample * glyph_padding - textspace_x_form( & src_position, & src_size, f32(atlas.buffer_width), f32(atlas.buffer_height) ) + src_size += over_sample * glyph_padding + textspace_x_form( & src_position, & src_size, glyph_buffer_width, glyph_buffer_height ) // Advance glyph_update_batch_x and calculate final glyph drawing transform glyph_draw_translate.x += f32(atlas.update_batch_x) atlas.update_batch_x += gwidth_scaled_px - screenspace_x_form( & glyph_draw_translate, & glyph_draw_scale, f32(atlas.buffer_width), f32(atlas.buffer_height)) + screenspace_x_form( & glyph_draw_translate, & glyph_draw_scale, glyph_buffer_width, glyph_buffer_height ) call : DrawCall { @@ -652,7 +658,7 @@ measure_text_size :: proc( ctx : ^Context, font : FontID, text_utf8 : string ) - atlas := ctx.atlas shaped := shape_text_cached( ctx, font, text_utf8 ) entry := & ctx.entries.data[ font ] - padding := 2 * cast(f32) atlas.glyph_padding + padding := cast(f32) atlas.glyph_padding for index : i32 = 0; index < i32(shaped.glyphs.num); index += 1 { @@ -666,14 +672,14 @@ measure_text_size :: proc( ctx : ^Context, font : FontID, text_utf8 : string ) - // region_kind, region, over_sample := decide_codepoint_region( ctx, entry, glyph_index ) glyph_size := Vec2 { - f32(bounds_width) * entry.size_scale + padding, - f32(bounds_height) * entry.size_scale + padding, + f32(bounds_width) * entry.size_scale, //+ padding, + f32(bounds_height) * entry.size_scale, //+ padding, } dummy_position : Vec2 measured.y = max(measured.y, glyph_size.y) } - measured.x = shaped.end_cursor_pos.x - padding + measured.x = shaped.end_cursor_pos.x return measured } diff --git a/code/font/VEFontCache/draw.odin b/code/font/VEFontCache/draw.odin index 09781ba..b1a613c 100644 --- a/code/font/VEFontCache/draw.odin +++ b/code/font/VEFontCache/draw.odin @@ -1,5 +1,7 @@ package VEFontCache +import "core:math" + DrawCall :: struct { pass : FrameBufferPass, start_index : u32, @@ -123,8 +125,8 @@ directly_draw_massive_glyph :: proc( ctx : ^Context, entry : ^Entry, glyph : Gly dst := position + scale * bounds_scaled dst_width := scale.x * glyph_dst_width dst_height := scale.y * glyph_dst_height - dst.x -= scale.x * f32(ctx.atlas.glyph_padding) - dst.y -= scale.y * f32(ctx.atlas.glyph_padding) + dst.x -= scale.x * f32(ctx.atlas.draw_padding) + dst.y -= scale.y * f32(ctx.atlas.draw_padding) dst_size := Vec2{ dst_width, dst_height } glyph_size := Vec2 { glyph_width, glyph_height } @@ -158,8 +160,8 @@ draw_cached_glyph :: proc( ctx : ^Context, entry : ^Entry, glyph_index : Glyph, 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) // Decide which atlas to target region_kind, region, over_sample := decide_codepoint_region( ctx, entry, glyph_index ) @@ -167,7 +169,7 @@ draw_cached_glyph :: proc( ctx : ^Context, entry : ^Entry, glyph_index : Glyph, // E region is special case and not cached to atlas if region_kind == .E { - directly_draw_massive_glyph( ctx, entry, glyph_index, bounds_0, bounds_width, bounds_height, over_sample, position, scale ) + directly_draw_massive_glyph( ctx, entry, glyph_index, bounds_0, cast(i32) bounds_width, cast(i32) bounds_height, over_sample, position, scale ) return true } @@ -180,32 +182,36 @@ draw_cached_glyph :: proc( ctx : ^Context, entry : ^Entry, glyph_index : Glyph, } atlas := & ctx.atlas + atlas_width := f32(atlas.width) + atlas_height := f32(atlas.height) + glyph_padding := f32(atlas.glyph_padding) // Figure out the source bounding box in the atlas texture - atlas_position, atlas_width, atlas_height := atlas_bbox( atlas, region_kind, atlas_index ) + glyph_atlas_position, glyph_atlas_width, glyph_atlas_height := atlas_bbox( atlas, region_kind, atlas_index ) - glyph_position := atlas_position //* {1, 2} - glyph_width := f32(bounds_width) * entry.size_scale - glyph_height := f32(bounds_height) * entry.size_scale + glyph_width := bounds_width * entry.size_scale + glyph_height := bounds_height * entry.size_scale - glyph_width += 2 * f32(atlas.glyph_padding) - glyph_height += 2 * f32(atlas.glyph_padding) + glyph_width += glyph_padding + glyph_height += glyph_padding glyph_scale := Vec2 { glyph_width, glyph_height } - bounds_0_scaled := Vec2{ f32(bounds_0.x), f32(bounds_0.y) } * entry.size_scale - { 0.5, 0.5 } + bounds_0_scaled := Vec2{ f32(bounds_0.x), f32(bounds_0.y) } * entry.size_scale //- { 0.5, 0.5 } bounds_0_scaled = { - cast(f32) cast(i32) bounds_0_scaled.x, - cast(f32) cast(i32) bounds_0_scaled.y, + math.ceil(bounds_0_scaled.x), + math.ceil(bounds_0_scaled.y), } + // dst := position * scale * bounds_0_scaled dst := Vec2 { - position.x + scale.x * bounds_0_scaled.x, - position.y + scale.y * bounds_0_scaled.y, + position.x + bounds_0_scaled.x * scale.x, + position.y + bounds_0_scaled.y * scale.y, } dst_width := scale.x * glyph_width dst_height := scale.y * glyph_height - dst -= scale * { f32(atlas.glyph_padding), f32(atlas.glyph_padding) } + dst -= scale * glyph_padding dst_scale := Vec2 { dst_width, dst_height } - textspace_x_form( & glyph_position, & glyph_scale, f32(atlas.width), f32(atlas.height) ) + + textspace_x_form( & glyph_atlas_position, & glyph_scale, atlas_width, atlas_height ) // Add the glyph drawcall call := DrawCall_Default @@ -215,7 +221,7 @@ draw_cached_glyph :: proc( ctx : ^Context, entry : ^Entry, glyph_index : Glyph, colour = ctx.colour start_index = cast(u32) ctx.draw_list.indices.num - blit_quad( & ctx.draw_list, dst, dst + dst_scale, glyph_position, glyph_position + glyph_scale ) + blit_quad( & ctx.draw_list, dst, dst + dst_scale, glyph_atlas_position, glyph_atlas_position + glyph_scale ) end_index = cast(u32) ctx.draw_list.indices.num } append( & ctx.draw_list.calls, call ) diff --git a/code/font/VEFontCache/misc.odin b/code/font/VEFontCache/misc.odin index 8276fe4..585eac5 100644 --- a/code/font/VEFontCache/misc.odin +++ b/code/font/VEFontCache/misc.odin @@ -31,6 +31,11 @@ shape_lru_hash :: #force_inline proc( label : string ) -> u64 { // ve_fontcache_eval_bezier (quadratic) eval_point_on_bezier3 :: proc( 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) + weight_start := (1 - alpha) * (1 - alpha) weight_control := 2.0 * (1 - alpha) * alpha weight_end := alpha * alpha @@ -40,7 +45,7 @@ eval_point_on_bezier3 :: proc( p0, p1, p2 : Vec2, alpha : f32 ) -> Vec2 end_point := p2 * weight_end point := starting_point + control_point + end_point - return point + return { f32(point.x), f32(point.y) } } // For a provided alpha value, @@ -48,6 +53,12 @@ eval_point_on_bezier3 :: proc( p0, p1, p2 : Vec2, alpha : f32 ) -> Vec2 // ve_fontcache_eval_bezier (cubic) eval_point_on_bezier4 :: proc( 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) + weight_start := (1 - alpha) * (1 - alpha) * (1 - alpha) weight_c_a := 3 * (1 - alpha) * (1 - alpha) * alpha weight_c_b := 3 * (1 - alpha) * alpha * alpha @@ -59,7 +70,7 @@ eval_point_on_bezier4 :: proc( p0, p1, p2, p3 : Vec2, alpha : f32 ) -> Vec2 end_point := p3 * weight_end point := start_point + control_a + control_b + end_point - return point + return { f32(point.x), f32(point.y) } } reset_batch_codepoint_state :: proc( ctx : ^Context ) { @@ -68,13 +79,31 @@ reset_batch_codepoint_state :: proc( ctx : ^Context ) { } screenspace_x_form :: proc( position, scale : ^Vec2, width, height : f32 ) { - quotient := 1.0 / Vec2 { width, height } - (position^) = (position^) * quotient * 2.0 - 1.0 - (scale^) = (scale^) * quotient * 2.0 + pos_64 := vec2_64_from_vec2(position^) + scale_64 := vec2_64_from_vec2(scale^) + width := f64(width) + height := f64(height) + + quotient : Vec2_64 = 1.0 / { width, height } + // quotient : Vec2 = 1.0 / { width, height } + pos_64 = pos_64 * quotient * 2.0 - 1.0 + scale_64 = scale_64 * quotient * 2.0 + + (position^) = { f32(pos_64.x), f32(pos_64.y) } + (scale^) = { f32(scale_64.x), f32(scale_64.y) } } textspace_x_form :: proc( position, scale : ^Vec2, width, height : f32 ) { - quotient := 1.0 / Vec2 { width, height } - (position^) *= quotient - (scale^) *= quotient + pos_64 := vec2_64_from_vec2(position^) + scale_64 := vec2_64_from_vec2(scale^) + width := f64(width) + height := f64(height) + + quotient : Vec2_64 = 1.0 / { width, height } + // quotient : Vec2 = 1.0 / { width, height } + pos_64 *= quotient + scale_64 *= quotient + + (position^) = { f32(pos_64.x), f32(pos_64.y) } + (scale^) = { f32(scale_64.x), f32(scale_64.y) } } diff --git a/code/font/VEFontCache/parser.odin b/code/font/VEFontCache/parser.odin index 2e175f8..3c0ee44 100644 --- a/code/font/VEFontCache/parser.odin +++ b/code/font/VEFontCache/parser.odin @@ -438,8 +438,8 @@ parser_scale_for_mapping_em_to_pixels :: proc( font : ^ParserFontInfo, size : f3 FT_Point_10 :: 64.0 points_per_em := (size / system_dpi ) * DPT_DPI - freetype.set_char_size( font.freetype_info, 0, cast(freetype.F26Dot6) (f32(points_per_em) * FT_Point_10), cast(u32) DPT_DPI, cast(u32) DPT_DPI ) - size_scale := size / cast(f32) font.freetype_info.units_per_em; + freetype.set_char_size( font.freetype_info, 0, cast(freetype.F26Dot6) f32(points_per_em * FT_Point_10), cast(u32) DPT_DPI, cast(u32) DPT_DPI ) + size_scale := f32(f64(size) / cast(f64) font.freetype_info.units_per_em) return size_scale case .STB_TrueType: