diff --git a/examples/sokol_demo/sokol_demo.odin b/examples/sokol_demo/sokol_demo.odin index a8ba18b..3017e07 100644 --- a/examples/sokol_demo/sokol_demo.odin +++ b/examples/sokol_demo/sokol_demo.odin @@ -271,7 +271,7 @@ init :: proc "c" () case .DUMMY: fmt.println(">> using dummy backend") } - ve.startup( & demo_ctx.ve_ctx, .STB_TrueType, allocator = context.allocator, snap_shape_position = false, use_advanced_text_shaper = true ) + ve.startup( & demo_ctx.ve_ctx, .STB_TrueType, allocator = context.allocator ) ve_sokol.setup_gfx_objects( & demo_ctx.render_ctx, & demo_ctx.ve_ctx, vert_cap = 1024 * 1024, index_cap = 1024 * 1024 ) error : mem.Allocator_Error diff --git a/vefontcache/LRU.odin b/vefontcache/LRU.odin index c263c0b..3682ccf 100644 --- a/vefontcache/LRU.odin +++ b/vefontcache/LRU.odin @@ -63,6 +63,26 @@ pool_list_reload :: proc( pool : ^Pool_List, allocator : Allocator ) { reload_array( & pool.free_list, allocator ) } +pool_list_clear :: proc( pool: ^Pool_List ) { + using pool + clear(& items) + clear(& free_list) + resize( & pool.items, cap(pool.items) ) + resize( & pool.free_list, cap(pool.free_list) ) + + for id in 0 ..< capacity { + free_list[id] = i32(id) + items[id] = { + prev = -1, + next = -1, + } + } + + front = -1 + back = -1 + size = 0 +} + pool_list_push_front :: proc( pool : ^Pool_List, value : Pool_ListValue ) { using pool @@ -186,6 +206,12 @@ lru_reload :: #force_inline proc( cache : ^LRU_Cache, allocator : Allocator ) { pool_list_reload( & cache.key_queue, allocator ) } +lru_clear :: proc ( cache : ^LRU_Cache ) { + pool_list_clear( & cache.key_queue ) + clear(& cache.table) + cache.num = 0 +} + lru_find :: #force_inline proc "contextless" ( cache : ^LRU_Cache, key : u64, must_find := false ) -> (LRU_Link, bool) { link, success := cache.table[key] return link, success diff --git a/vefontcache/atlas.odin b/vefontcache/atlas.odin index a211026..33a2ceb 100644 --- a/vefontcache/atlas.odin +++ b/vefontcache/atlas.odin @@ -27,7 +27,8 @@ Atlas :: struct { width : i32, height : i32, - glyph_padding : i32, + glyph_padding : i32, // Padding to add to bounds__scaled for choosing which atlas region. + glyph_over_scalar : f32, // Scalar to apply to bounds__scaled for choosing which atlas region. region_a : Atlas_Region, region_b : Atlas_Region, @@ -98,8 +99,8 @@ decide_codepoint_region :: proc(ctx : ^Context, entry : ^Entry, glyph_index : Gl glyph_buffer := & ctx.glyph_buffer glyph_padding := f32( atlas.glyph_padding ) * 2 - bounds_width_scaled := i32(bounds_width * entry.size_scale + glyph_padding) - bounds_height_scaled := i32(bounds_height * entry.size_scale + glyph_padding) + bounds_width_scaled := i32(bounds_width * entry.size_scale * atlas.glyph_over_scalar + glyph_padding) + bounds_height_scaled := i32(bounds_height * entry.size_scale * atlas.glyph_over_scalar + glyph_padding) // Use a lookup table for faster region selection region_lookup := [4]struct { kind: Atlas_Region_Kind, region: ^Atlas_Region } { @@ -118,7 +119,7 @@ decide_codepoint_region :: proc(ctx : ^Context, entry : ^Entry, glyph_index : Gl over_sample = \ bounds_width_scaled <= glyph_buffer.width / 2 && bounds_height_scaled <= glyph_buffer.height / 2 ? \ - {2.0, 2.0} \ + {2.0, 2.0} \ : {1.0, 1.0} return .E, nil, over_sample } diff --git a/vefontcache/draw.odin b/vefontcache/draw.odin index f45e8b6..0a75744 100644 --- a/vefontcache/draw.odin +++ b/vefontcache/draw.odin @@ -174,9 +174,9 @@ cache_glyph_freetype :: proc(ctx: ^Context, font: Font_ID, glyph_index: Glyph, e start_index: int = 0 for contour_index in 0 ..< int(outline.n_contours) { - end_index := int(contours[contour_index]) + 1 - prev_point: Vec2 - first_point: Vec2 + end_index := int(contours[contour_index]) + 1 + prev_point : Vec2 + first_point : Vec2 for idx := start_index; idx < end_index; idx += 1 { @@ -272,6 +272,7 @@ cache_glyph :: proc(ctx : ^Context, font : Font_ID, glyph_index : Glyph, entry : path := &ctx.temp_path clear(path) + step := 1.0 / entry.curve_quality for edge in shape do #partial switch edge.type { case .Move: @@ -290,7 +291,6 @@ cache_glyph :: proc(ctx : ^Context, font : Font_ID, glyph_index : Glyph, entry : p1 := Vec2{ f32(edge.contour_x0), f32(edge.contour_y0) } p2 := Vec2{ f32(edge.x), f32(edge.y) } - step := 1.0 / entry.curve_quality for index : f32 = 1; index <= entry.curve_quality; index += 1 { alpha := index * step append( path, Vertex { pos = eval_point_on_bezier3(p0, p1, p2, alpha) } ) @@ -303,7 +303,6 @@ cache_glyph :: proc(ctx : ^Context, font : Font_ID, glyph_index : Glyph, entry : p2 := Vec2{ f32(edge.contour_x1), f32(edge.contour_y1) } p3 := Vec2{ f32(edge.x), f32(edge.y) } - step := 1.0 / entry.curve_quality for index : f32 = 1; index <= entry.curve_quality; index += 1 { alpha := index * step append( path, Vertex { pos = eval_point_on_bezier4(p0, p1, p2, p3, alpha) } ) @@ -342,10 +341,9 @@ cache_glyph_to_atlas :: proc( ctx : ^Context, // Get hb_font text metrics. These are unscaled! bounds_0, bounds_1 := parser_get_glyph_box( & entry.parser_info, glyph_index ) - bounds_size := Vec2 { - f32(bounds_1.x - bounds_0.x), - f32(bounds_1.y - bounds_0.y) - } + vbounds_0 := vec2(bounds_0) + vbounds_1 := vec2(bounds_1) + bounds_size := vbounds_1 - vbounds_0 // E region is special case and not cached to atlas. if region_kind == .None || region_kind == .E do return @@ -390,33 +388,31 @@ cache_glyph_to_atlas :: proc( ctx : ^Context, debug_total_cached += 1 } - // Draw oversized glyph to update FBO + // Draw oversized glyph to glyph render target (FBO) glyph_draw_scale := over_sample * entry.size_scale - glyph_draw_translate := -1 * vec2(bounds_0) * 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)) + glyph_draw_translate := -1 * vbounds_0 * glyph_draw_scale + vec2( glyph_padding ) - // Allocate a glyph_update_FBO region - gwidth_scaled_px := bounds_size.x * 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) { + // Allocate a glyph glyph render target region (FBO) + gwidth_scaled_px := bounds_size.x * glyph_draw_scale.x + over_sample.x * glyph_padding + 1.0 + if i32(f32(glyph_buffer.batch_x) + gwidth_scaled_px) >= i32(glyph_buffer.width) { flush_glyph_buffer_to_atlas( ctx ) } // Calculate the src and destination regions - slot_position, slot_szie := atlas_bbox( atlas, region_kind, atlas_index ) + slot_position, slot_size := atlas_bbox( atlas, region_kind, atlas_index ) dst_glyph_position := slot_position - dst_glyph_size := bounds_size * entry.size_scale + glyph_padding - dst_size := slot_szie + dst_glyph_size := (bounds_size * entry.size_scale + glyph_padding) + dst_size := (slot_size) screenspace_x_form( & dst_glyph_position, & dst_glyph_size, atlas_size ) screenspace_x_form( & slot_position, & dst_size, atlas_size ) src_position := Vec2 { f32(glyph_buffer.batch_x), 0 } - src_size := bounds_size * glyph_draw_scale + over_sample * glyph_padding + src_size := (bounds_size * glyph_draw_scale + over_sample * glyph_padding) textspace_x_form( & src_position, & src_size, glyph_buffer_size ) // Advance glyph_update_batch_x and calculate final glyph drawing transform - glyph_draw_translate.x += f32(glyph_buffer.batch_x) + glyph_draw_translate.x = (glyph_draw_translate.x + f32(glyph_buffer.batch_x)) glyph_buffer.batch_x += i32(gwidth_scaled_px) screenspace_x_form( & glyph_draw_translate, & glyph_draw_scale, glyph_buffer_size ) @@ -451,8 +447,8 @@ cache_glyph_to_atlas :: proc( ctx : ^Context, append( & glyph_buffer.clear_draw_list.calls, clear_target_region ) append( & glyph_buffer.draw_list.calls, blit_to_atlas ) - // Render glyph to glyph_update_FBO - cache_glyph( ctx, font, glyph_index, entry, vec2(bounds_0), vec2(bounds_1), glyph_draw_scale, glyph_draw_translate ) + // Render glyph to glyph render target (FBO) + cache_glyph( ctx, font, glyph_index, entry, vbounds_0, vbounds_1, glyph_draw_scale, glyph_draw_translate ) } // If the glyuph is found in the atlas, nothing occurs, otherwise, the glyph call is setup to catch it to the atlas @@ -525,17 +521,14 @@ directly_draw_massive_glyph :: proc( ctx : ^Context, // Figure out the source rect. glyph_position := Vec2 {} - glyph_size := vec2(glyph_padding_dbl) + glyph_size := vec2(glyph_padding) glyph_dst_size := glyph_size + bounds_scaled glyph_size += bounds_scaled * over_sample // Figure out the destination rect. - bounds_0_scaled := Vec2 { - cast(f32) i32(bounds_0.x * entry.size_scale - 0.5), - cast(f32) i32(bounds_0.y * entry.size_scale - 0.5), - } - dst := position + scale * bounds_0_scaled - glyph_padding * scale - dst_size := glyph_dst_size * scale + bounds_0_scaled := (bounds_0 * entry.size_scale) + dst := position + scale * bounds_0_scaled - glyph_padding * scale + dst_size := glyph_dst_size * scale textspace_x_form( & glyph_position, & glyph_size, glyph_buffer_size ) // Add the glyph Draw_Call. @@ -557,7 +550,7 @@ directly_draw_massive_glyph :: proc( ctx : ^Context, clear_glyph_update := & calls[1] { - // Clear glyph_update_FBO. + // Clear glyph render target (FBO) clear_glyph_update.pass = .Glyph clear_glyph_update.start_index = 0 clear_glyph_update.end_index = 0 @@ -638,7 +631,7 @@ draw_text_batch :: proc(ctx: ^Context, entry: ^Entry, shaped: ^Shaped_Text, bounds_0, bounds_1 := parser_get_glyph_box( & entry.parser_info, glyph_index ) vbounds_0 := vec2(bounds_0) vbounds_1 := vec2(bounds_1) - bounds_size := Vec2 { vbounds_1.x - vbounds_0.x, vbounds_1.y - vbounds_0.y } + bounds_size := vbounds_1 - vbounds_0 shaped_position := shaped.positions[index] glyph_translate := position + (shaped_position) * scale @@ -652,10 +645,10 @@ draw_text_batch :: proc(ctx: ^Context, entry: ^Entry, shaped: ^Shaped_Text, } else if atlas_index != -1 { - // Draw cacxhed glyph + // Draw cached glyph slot_position, _ := atlas_bbox( atlas, region_kind, atlas_index ) glyph_scale := bounds_size * entry.size_scale + glyph_padding - bounds_0_scaled := ceil(vbounds_0 * entry.size_scale) + bounds_0_scaled := ceil(vbounds_0 * entry.size_scale - 0.5 ) dst := glyph_translate + bounds_0_scaled * scale dst_scale := glyph_scale * scale textspace_x_form( & slot_position, & glyph_scale, atlas_size ) @@ -726,7 +719,7 @@ flush_glyph_buffer_to_atlas :: proc( ctx : ^Context ) clear_draw_list( & ctx.glyph_buffer.draw_list ) clear_draw_list( & ctx.glyph_buffer.clear_draw_list ) - // Clear glyph_update_FBO + // Clear glyph render target (FBO) if ctx.glyph_buffer.batch_x != 0 { call := Draw_Call_Default @@ -766,7 +759,8 @@ merge_draw_list :: proc( dst, src : ^Draw_List ) } } -optimize_draw_list :: proc(draw_list: ^Draw_List, call_offset: int) { +optimize_draw_list :: proc(draw_list: ^Draw_List, call_offset: int) +{ // profile(#procedure) assert(draw_list != nil) diff --git a/vefontcache/mappings.odin b/vefontcache/mappings.odin index 7cb620a..f6afc8d 100644 --- a/vefontcache/mappings.odin +++ b/vefontcache/mappings.odin @@ -33,6 +33,7 @@ import "core:mem" Arena :: mem.Arena arena_allocator :: mem.arena_allocator arena_init :: mem.arena_init +import "core:slice" //#region("Proc overload mappings") @@ -58,6 +59,7 @@ ceil :: proc { clear :: proc { clear_dynamic_array, + clear_map, } floor :: proc { @@ -74,6 +76,10 @@ floor :: proc { floor_vec2, } +fill :: proc { + slice.fill, +} + make :: proc { make_dynamic_array, make_dynamic_array_len, diff --git a/vefontcache/shaped_text.odin b/vefontcache/shaped_text.odin index ba5c80f..d23436e 100644 --- a/vefontcache/shaped_text.odin +++ b/vefontcache/shaped_text.odin @@ -74,7 +74,7 @@ shape_text_uncached :: proc( ctx : ^Context, font : Font_ID, text_utf8 : string, line_gap := f32(line_gap_i32) line_height := (ascent - descent + line_gap) * entry.size_scale - if ctx.text_shape_adv + if ctx.use_advanced_shaper { shaper_shape_from_text( & ctx.shaper_ctx, & entry.shaper_info, output, text_utf8, ascent_i32, descent_i32, line_gap_i32, entry.size, entry.size_scale ) return @@ -106,22 +106,19 @@ shape_text_uncached :: proc( ctx : ^Context, font : Font_ID, text_utf8 : string, prev_codepoint = rune(0) continue } - if abs( entry.size ) <= ADVANCE_SNAP_SMALLFONT_SIZE { - position.x = position.x + if abs( entry.size ) <= ctx.shaper_ctx.adv_snap_small_font_threshold { + position.x = ceil(position.x) } append( & output.glyphs, parser_find_glyph_index( & entry.parser_info, codepoint )) advance, _ := parser_get_codepoint_horizontal_metrics( & entry.parser_info, codepoint ) - if ctx.snap_shape_pos do position.x = ceil(position.x) - append( & output.positions, Vec2 { - position.x, - position.y + ceil(position.x), + ceil(position.y) }) position.x += f32(advance) * entry.size_scale - if ctx.snap_shape_pos do position.x = ceil(position.x) prev_codepoint = codepoint } diff --git a/vefontcache/shaper.odin b/vefontcache/shaper.odin index 6993e5f..309c4ec 100644 --- a/vefontcache/shaper.odin +++ b/vefontcache/shaper.odin @@ -13,6 +13,9 @@ Shaper_Kind :: enum { Shaper_Context :: struct { hb_buffer : harfbuzz.Buffer, + + snap_glyph_position : b32, + adv_snap_small_font_threshold : f32, } Shaper_Info :: struct { @@ -66,12 +69,13 @@ shaper_shape_from_text :: proc( ctx : ^Shaper_Context, info : ^Shaper_Info, outp max_line_width := f32(0) line_count := 1 - line_height := (ascent - descent + line_gap) * size_scale + line_height := ((ascent - descent + line_gap) * size_scale) position, vertical_position : f32 shape_run :: proc( buffer : harfbuzz.Buffer, script : harfbuzz.Script, font : harfbuzz.Font, output : ^Shaped_Text, position, vertical_position, max_line_width: ^f32, line_count: ^int, - ascent, descent, line_gap, size, size_scale: f32 ) + ascent, descent, line_gap, size, size_scale: f32, + snap_shape_pos : b32, adv_snap_small_font_threshold : f32 ) { // Set script and direction. We use the system's default langauge. // script = HB_SCRIPT_LATIN @@ -101,24 +105,29 @@ shaper_shape_from_text :: proc( ctx : ^Shaper_Context, info : ^Shaper_Info, outp (max_line_width^) = max( max_line_width^, position^ ) (position^) = 0.0 (vertical_position^) -= line_height - (vertical_position^) = cast(f32) i32(vertical_position^ + 0.5) + (vertical_position^) = floor(vertical_position^ + 0.5) (line_count^) += 1 continue } - if abs( size ) <= ADVANCE_SNAP_SMALLFONT_SIZE + if abs( size ) <= adv_snap_small_font_threshold { (position^) = ceil( position^ ) } append( & output.glyphs, glyph_id ) - pos := position^ + pos := position^ v_pos := vertical_position^ offset_x := f32(hb_gposition.x_offset) * size_scale offset_y := f32(hb_gposition.y_offset) * size_scale - append( & output.positions, Vec2 { cast(f32) i32( pos + offset_x + 0.5 ), - v_pos + offset_y, - }) + pos += offset_x + v_pos += offset_y + + if snap_shape_pos { + pos = ceil(pos) + v_pos = ceil(v_pos) + } + append( & output.positions, Vec2 {pos, v_pos}) (position^) += f32(hb_gposition.x_advance) * size_scale (vertical_position^) += f32(hb_gposition.y_advance) * size_scale @@ -151,13 +160,23 @@ shaper_shape_from_text :: proc( ctx : ^Shaper_Context, info : ^Shaper_Info, outp } // End current run since we've encountered a script change. - shape_run( ctx.hb_buffer, current_script, info.font, output, & position, & vertical_position, & max_line_width, & line_count, ascent, descent, line_gap, size, size_scale ) + shape_run( + ctx.hb_buffer, current_script, info.font, output, + & position, & vertical_position, & max_line_width, & line_count, + ascent, descent, line_gap, size, size_scale, + ctx.snap_glyph_position, ctx.adv_snap_small_font_threshold + ) harfbuzz.buffer_add( ctx.hb_buffer, hb_codepoint, codepoint == '\n' ? 1 : 0 ) current_script = script } // End the last run if needed - shape_run( ctx.hb_buffer, current_script, info.font, output, & position, & vertical_position, & max_line_width, & line_count, ascent, descent, line_gap, size, size_scale ) + shape_run( + ctx.hb_buffer, current_script, info.font, output, + & position, & vertical_position, & max_line_width, & line_count, + ascent, descent, line_gap, size, size_scale, + ctx.snap_glyph_position, ctx.adv_snap_small_font_threshold + ) // Set the final size output.size.x = max_line_width diff --git a/vefontcache/vefontcache.odin b/vefontcache/vefontcache.odin index a4b5df9..8ca238c 100644 --- a/vefontcache/vefontcache.odin +++ b/vefontcache/vefontcache.odin @@ -7,8 +7,6 @@ package vefontcache import "base:runtime" -ADVANCE_SNAP_SMALLFONT_SIZE :: 0 - Font_ID :: distinct i64 Glyph :: distinct i32 @@ -44,7 +42,6 @@ Context :: struct { snap_width : f32, snap_height : f32, - colour : Colour, cursor_pos : Vec2, @@ -60,14 +57,12 @@ Context :: struct { shape_cache : Shaped_Text_Cache, default_curve_quality : i32, - text_shape_adv : b32, - snap_shape_pos : b32, + use_advanced_shaper : b32, debug_print : b32, debug_print_verbose : b32, } -//#region("lifetime") Init_Atlas_Region_Params :: struct { width : u32, @@ -75,9 +70,10 @@ Init_Atlas_Region_Params :: struct { } Init_Atlas_Params :: struct { - width : u32, - height : u32, - glyph_padding : u32, + width : u32, + height : u32, + glyph_padding : u32, // Padding to add to bounds__scaled for choosing which atlas region. + glyph_over_scalar : f32, // Scalar to apply to bounds__scaled for choosing which atlas region. region_a : Init_Atlas_Region_Params, region_b : Init_Atlas_Region_Params, @@ -86,9 +82,10 @@ Init_Atlas_Params :: struct { } Init_Atlas_Params_Default :: Init_Atlas_Params { - width = 4096, - height = 2048, - glyph_padding = 4, + width = 4096, + height = 2048, + glyph_padding = 1, + glyph_over_scalar = 1, region_a = { width = 32, @@ -109,17 +106,29 @@ Init_Atlas_Params_Default :: Init_Atlas_Params { } Init_Glyph_Draw_Params :: struct { - over_sample : Vec2i, + over_sample : Vec2, buffer_batch : u32, draw_padding : u32, } Init_Glyph_Draw_Params_Default :: Init_Glyph_Draw_Params { - over_sample = { 8, 8 }, + over_sample = Vec2 { 4, 4 }, buffer_batch = 4, draw_padding = Init_Atlas_Params_Default.glyph_padding, } +Init_Shaper_Params :: struct { + use_advanced_text_shaper : b32, + snap_glyph_position : b32, + adv_snap_small_font_threshold : u32, +} + +Init_Shaper_Params_Default :: Init_Shaper_Params { + use_advanced_text_shaper = true, + snap_glyph_position = true, + adv_snap_small_font_threshold = 0, +} + Init_Shape_Cache_Params :: struct { capacity : u32, reserve_length : u32, @@ -130,14 +139,15 @@ Init_Shape_Cache_Params_Default :: Init_Shape_Cache_Params { reserve_length = 256, } +//#region("lifetime") + // ve_fontcache_init startup :: proc( ctx : ^Context, parser_kind : Parser_Kind = .STB_TrueType, allocator := context.allocator, atlas_params := Init_Atlas_Params_Default, glyph_draw_params := Init_Glyph_Draw_Params_Default, shape_cache_params := Init_Shape_Cache_Params_Default, - use_advanced_text_shaper : b32 = true, - snap_shape_position : b32 = true, + shaper_params := Init_Shaper_Params_Default, default_curve_quality : u32 = 3, entires_reserve : u32 = 512, temp_path_reserve : u32 = 1024, @@ -150,8 +160,9 @@ startup :: proc( ctx : ^Context, parser_kind : Parser_Kind = .STB_TrueType, ctx.backing = allocator context.allocator = ctx.backing - snap_shape_pos = snap_shape_position - text_shape_adv = use_advanced_text_shaper + use_advanced_shaper = shaper_params.use_advanced_text_shaper + shaper_ctx.adv_snap_small_font_threshold = f32(shaper_params.adv_snap_small_font_threshold) + shaper_ctx.snap_glyph_position = shaper_params.snap_glyph_position if default_curve_quality == 0 { default_curve_quality = 3 @@ -202,9 +213,10 @@ startup :: proc( ctx : ^Context, parser_kind : Parser_Kind = .STB_TrueType, init_atlas_region( & atlas.region_c, atlas_params, atlas_params.region_c, { 4, 1}, 512 ) init_atlas_region( & atlas.region_d, atlas_params, atlas_params.region_d, { 2, 1}, 256 ) - atlas.width = i32(atlas_params.width) - atlas.height = i32(atlas_params.height) - atlas.glyph_padding = i32(atlas_params.glyph_padding) + atlas.width = i32(atlas_params.width) + atlas.height = i32(atlas_params.height) + atlas.glyph_padding = i32(atlas_params.glyph_padding) + atlas.glyph_over_scalar = atlas_params.glyph_over_scalar atlas.region_a.offset = {0, 0} atlas.region_b.offset.x = 0 @@ -241,7 +253,7 @@ startup :: proc( ctx : ^Context, parser_kind : Parser_Kind = .STB_TrueType, // Note(From original author): We can actually go over VE_FONTCACHE_GLYPHDRAW_BUFFER_BATCH batches due to smart packing! { using glyph_buffer - over_sample = vec2(glyph_draw_params.over_sample) + over_sample = glyph_draw_params.over_sample batch = cast(i32) glyph_draw_params.buffer_batch width = atlas.region_d.width * i32(over_sample.x) * batch height = atlas.region_d.height * i32(over_sample.y) @@ -308,7 +320,6 @@ hot_reload :: proc( ctx : ^Context, allocator : Allocator ) reload_array( & glyph_buffer.clear_draw_list.vertices, allocator ) reload_array( & shape_cache.storage, allocator ) - lru_reload( & shape_cache.state, allocator ) } // ve_foncache_shutdown @@ -385,10 +396,8 @@ load_font :: proc( ctx : ^Context, label : string, data : []byte, size_px : f32, parser_info = parser_load_font( & parser_ctx, label, data ) shaper_info = shaper_load_font( & shaper_ctx, label, data, transmute(rawptr) id ) - size = size_px - size_scale = size_px < 0.0 ? \ - parser_scale_for_pixel_height( & parser_info, -size_px ) \ - : parser_scale_for_mapping_em_to_pixels( & parser_info, size_px ) + size = size_px + size_scale = parser_scale( & parser_info, size ) if glyph_curve_quality == 0 { curve_quality = f32(ctx.default_curve_quality) @@ -442,8 +451,8 @@ draw_text :: proc( ctx : ^Context, font : Font_ID, text_utf8 : string, position, ctx.cursor_pos = {} position := position - if ctx.snap_width > 0 do position.x = cast(f32) cast(u32) (position.x * ctx.snap_width + 0.5) / ctx.snap_width - if ctx.snap_height > 0 do position.y = cast(f32) cast(u32) (position.y * ctx.snap_height + 0.5) / ctx.snap_height + if ctx.snap_width > 0 do position.x = ceil(position.x * ctx.snap_width ) / ctx.snap_width + if ctx.snap_height > 0 do position.y = ceil(position.y * ctx.snap_height) / ctx.snap_height entry := & ctx.entries[ font ] @@ -520,10 +529,44 @@ get_font_vertical_metrics :: #force_inline proc ( ctx : ^Context, font : Font_ID entry := & ctx.entries[ font ] ascent_i32, descent_i32, line_gap_i32 := parser_get_font_vertical_metrics( & entry.parser_info ) - ascent = ceil(f32(ascent_i32) * entry.size_scale) - descent = ceil(f32(descent_i32) * entry.size_scale) - line_gap = ceil(f32(line_gap_i32) * entry.size_scale) + ascent = (f32(ascent_i32) * entry.size_scale) + descent = (f32(descent_i32) * entry.size_scale) + line_gap = (f32(line_gap_i32) * entry.size_scale) return } //#endregion("metrics") + +// Can be used with hot-reload +clear_atlas_region_caches :: proc(ctx : ^Context) +{ + lru_clear(& ctx.atlas.region_a.state) + lru_clear(& ctx.atlas.region_b.state) + lru_clear(& ctx.atlas.region_c.state) + lru_clear(& ctx.atlas.region_d.state) + + ctx.atlas.region_a.next_idx = 0 + ctx.atlas.region_b.next_idx = 0 + ctx.atlas.region_c.next_idx = 0 + ctx.atlas.region_d.next_idx = 0 +} + +// Can be used with hot-reload +clear_shape_cache :: proc (ctx : ^Context) +{ + using ctx + lru_clear(& shape_cache.state) + for idx : i32 = 0; idx < cast(i32) cap(shape_cache.storage); idx += 1 + { + stroage_entry := & shape_cache.storage[idx] + using stroage_entry + end_cursor_pos = {} + size = {} + clear(& glyphs) + clear(& positions) + clear(& draw_list.calls) + clear(& draw_list.indices) + clear(& draw_list.vertices) + } + ctx.shape_cache.next_cache_id = 0 +}