diff --git a/examples/sokol_demo/sokol_demo.odin b/examples/sokol_demo/sokol_demo.odin index 63fee47..b1b2659 100644 --- a/examples/sokol_demo/sokol_demo.odin +++ b/examples/sokol_demo/sokol_demo.odin @@ -41,7 +41,7 @@ COLOR_WHITE :: RGBA8 { 255, 255, 255, 255 } FONT_LARGEST_PIXEL_SIZE :: 400 FONT_SIZE_INTERVAL :: 2 -FONT_DEFAULT :: FontID { "" } +FONT_DEFAULT :: Font_ID { "" } FONT_DEFAULT_SIZEZ :: 12.0 FONT_LOAD_USE_DEFAULT_SIZE :: -1 @@ -52,17 +52,17 @@ PATH_FONTS :: "../fonts/" OVER_SAMPLE_ZOOM : f32 : 2.0 // Adjust this value as needed, used by draw_text_zoomed_norm -FontID :: struct { +Font_ID :: struct { label : string, } FontDef :: struct { path_file : string, default_size : i32, - size_table : [FONT_LARGEST_PIXEL_SIZE / FONT_SIZE_INTERVAL] ve.FontID, + size_table : [FONT_LARGEST_PIXEL_SIZE / FONT_SIZE_INTERVAL] ve.Font_ID, } -DemoContext :: struct { +Demo_Context :: struct { ve_ctx : ve.Context, render_ctx : ve_sokol.Context, font_ids : map[string]FontDef, @@ -70,43 +70,43 @@ DemoContext :: struct { // Values between 1, & -1 on Y axis mouse_scroll : Vec2, - font_firacode : FontID, - font_logo : FontID, - font_title : FontID, - font_print : FontID, - font_mono : FontID, - font_small : FontID, - font_demo_sans : FontID, - font_demo_serif : FontID, - font_demo_script : FontID, - font_demo_mono : FontID, - font_demo_chinese : FontID, - font_demo_japanese : FontID, - font_demo_korean : FontID, - font_demo_thai : FontID, - font_demo_arabic : FontID, - font_demo_hebrew : FontID, - font_demo_raincode : FontID, - font_demo_grid2 : FontID, - font_demo_grid3 : FontID, + font_firacode : Font_ID, + font_logo : Font_ID, + font_title : Font_ID, + font_print : Font_ID, + font_mono : Font_ID, + font_small : Font_ID, + font_demo_sans : Font_ID, + font_demo_serif : Font_ID, + font_demo_script : Font_ID, + font_demo_mono : Font_ID, + font_demo_chinese : Font_ID, + font_demo_japanese : Font_ID, + font_demo_korean : Font_ID, + font_demo_thai : Font_ID, + font_demo_arabic : Font_ID, + font_demo_hebrew : Font_ID, + font_demo_raincode : Font_ID, + font_demo_grid2 : Font_ID, + font_demo_grid3 : Font_ID, screen_size : [2]f32, } -demo_ctx : DemoContext +demo_ctx : Demo_Context font_load :: proc(path_file : string, default_size : i32 = FONT_LOAD_USE_DEFAULT_SIZE, desired_id : string = FONT_LOAD_GEN_ID, curve_quality : u32 = 3, -) -> FontID +) -> Font_ID { msg := fmt.println("Loading font: %v", path_file) font_data, read_succeded : = os.read_entire_file( path_file ) assert( bool(read_succeded), fmt.tprintf("Failed to read font file for: %v", path_file) ) font_data_size := cast(i32) len(font_data) -font_firacode : FontID +font_firacode : Font_ID desired_id := desired_id @@ -134,13 +134,13 @@ font_firacode : FontID (ve_id^) = ve_ret_id } - fid := FontID { desired_id } + fid := Font_ID { desired_id } return fid } Font_Use_Default_Size :: f32(0.0) -font_resolve_draw_id :: proc( id : FontID, size := Font_Use_Default_Size ) -> ( ve_id : ve.FontID, resolved_size : i32 ) +font_resolve_draw_id :: proc( id : Font_ID, size := Font_Use_Default_Size ) -> ( ve_id : ve.Font_ID, resolved_size : i32 ) { def := demo_ctx.font_ids[ id.label ] size := size == 0.0 ? f32(def.default_size) : size @@ -152,14 +152,14 @@ font_resolve_draw_id :: proc( id : FontID, size := Font_Use_Default_Size ) -> ( return } -measure_text_size :: proc( text : string, font : FontID, font_size := Font_Use_Default_Size, spacing : f32 ) -> Vec2 +measure_text_size :: proc( text : string, font : Font_ID, font_size := Font_Use_Default_Size, spacing : f32 ) -> Vec2 { ve_id, size := font_resolve_draw_id( font, font_size ) measured := ve.measure_text_size( & demo_ctx.ve_ctx, ve_id, text ) return measured } -get_font_vertical_metrics :: #force_inline proc ( font : FontID, font_size := Font_Use_Default_Size ) -> ( ascent, descent, line_gap : f32 ) +get_font_vertical_metrics :: #force_inline proc ( font : Font_ID, font_size := Font_Use_Default_Size ) -> ( ascent, descent, line_gap : f32 ) { ve_id, size := font_resolve_draw_id( font, font_size ) ascent, descent, line_gap = ve.get_font_vertical_metrics( & demo_ctx.ve_ctx, ve_id ) @@ -167,7 +167,7 @@ get_font_vertical_metrics :: #force_inline proc ( font : FontID, font_size := Fo } // Draw text using a string and normalized render coordinates -draw_text_string_pos_norm :: proc( content : string, id : FontID, size : f32, pos : Vec2, color := COLOR_WHITE, scale : f32 = 1.0 ) +draw_text_string_pos_norm :: proc( content : string, id : Font_ID, size : f32, pos : Vec2, color := COLOR_WHITE, scale : f32 = 1.0 ) { width := demo_ctx.screen_size.x height := demo_ctx.screen_size.y @@ -181,14 +181,14 @@ draw_text_string_pos_norm :: proc( content : string, id : FontID, size : f32, po } // Draw text using a string and extent-based screen coordinates -draw_text_string_pos_extent :: proc( content : string, id : FontID, size : f32, pos : Vec2, color := COLOR_WHITE ) { +draw_text_string_pos_extent :: proc( content : string, id : Font_ID, size : f32, pos : Vec2, color := COLOR_WHITE ) { render_pos := pos + demo_ctx.screen_size * 0.5 normalized_pos := render_pos * (1.0 / demo_ctx.screen_size) draw_text_string_pos_norm( content, id, size, normalized_pos, color ) } // Adapt the draw_text_string_pos_extent_zoomed procedure -draw_text_zoomed_norm :: proc(content : string, id : FontID, size : f32, pos : Vec2, zoom : f32, color := COLOR_WHITE) +draw_text_zoomed_norm :: proc(content : string, id : Font_ID, size : f32, pos : Vec2, zoom : f32, color := COLOR_WHITE) { screen_size := demo_ctx.screen_size screen_scale := Vec2{1.0 / screen_size.x, 1.0 / screen_size.y} diff --git a/vefontcache/LRU.odin b/vefontcache/LRU.odin index 69b2615..c263c0b 100644 --- a/vefontcache/LRU.odin +++ b/vefontcache/LRU.odin @@ -6,33 +6,33 @@ The choice was made to keep the LRU cache implementation as close to the origina import "base:runtime" -PoolListIter :: i32 -PoolListValue :: u64 +Pool_ListIter :: i32 +Pool_ListValue :: u64 -PoolListItem :: struct { - prev : PoolListIter, - next : PoolListIter, - value : PoolListValue, +Pool_List_Item :: struct { + prev : Pool_ListIter, + next : Pool_ListIter, + value : Pool_ListValue, } -PoolList :: struct { - items : [dynamic]PoolListItem, - free_list : [dynamic]PoolListIter, - front : PoolListIter, - back : PoolListIter, +Pool_List :: struct { + items : [dynamic]Pool_List_Item, + free_list : [dynamic]Pool_ListIter, + front : Pool_ListIter, + back : Pool_ListIter, size : i32, capacity : i32, dbg_name : string, } -pool_list_init :: proc( pool : ^PoolList, capacity : i32, dbg_name : string = "" ) +pool_list_init :: proc( pool : ^Pool_List, capacity : i32, dbg_name : string = "" ) { - error : AllocatorError - pool.items, error = make( [dynamic]PoolListItem, int(capacity) ) + error : Allocator_Error + pool.items, error = make( [dynamic]Pool_List_Item, int(capacity) ) assert( error == .None, "VEFontCache.pool_list_init : Failed to allocate items array") resize( & pool.items, capacity ) - pool.free_list, error = make( [dynamic]PoolListIter, len = 0, cap = int(capacity) ) + pool.free_list, error = make( [dynamic]Pool_ListIter, len = 0, cap = int(capacity) ) assert( error == .None, "VEFontCache.pool_list_init : Failed to allocate free_list array") resize( & pool.free_list, capacity ) @@ -53,17 +53,17 @@ pool_list_init :: proc( pool : ^PoolList, capacity : i32, dbg_name : string = "" back = -1 } -pool_list_free :: proc( pool : ^PoolList ) { +pool_list_free :: proc( pool : ^Pool_List ) { delete( pool.items) delete( pool.free_list) } -pool_list_reload :: proc( pool : ^PoolList, allocator : Allocator ) { +pool_list_reload :: proc( pool : ^Pool_List, allocator : Allocator ) { reload_array( & pool.items, allocator ) reload_array( & pool.free_list, allocator ) } -pool_list_push_front :: proc( pool : ^PoolList, value : PoolListValue ) +pool_list_push_front :: proc( pool : ^Pool_List, value : Pool_ListValue ) { using pool if size >= capacity do return @@ -90,7 +90,7 @@ pool_list_push_front :: proc( pool : ^PoolList, value : PoolListValue ) size += 1 } -pool_list_erase :: proc( pool : ^PoolList, iter : PoolListIter ) +pool_list_erase :: proc( pool : ^Pool_List, iter : Pool_ListIter ) { using pool if size <= 0 do return @@ -119,7 +119,7 @@ pool_list_erase :: proc( pool : ^PoolList, iter : PoolListIter ) } } -pool_list_move_to_front :: #force_inline proc( pool : ^PoolList, iter : PoolListIter ) +pool_list_move_to_front :: #force_inline proc( pool : ^Pool_List, iter : Pool_ListIter ) { using pool @@ -136,13 +136,13 @@ pool_list_move_to_front :: #force_inline proc( pool : ^PoolList, iter : PoolList front = iter } -pool_list_peek_back :: #force_inline proc ( pool : ^PoolList ) -> PoolListValue { +pool_list_peek_back :: #force_inline proc ( pool : ^Pool_List ) -> Pool_ListValue { assert( pool.back != - 1 ) value := pool.items[ pool.back ].value return value } -pool_list_pop_back :: #force_inline proc( pool : ^PoolList ) -> PoolListValue { +pool_list_pop_back :: #force_inline proc( pool : ^Pool_List ) -> Pool_ListValue { if pool.size <= 0 do return 0 assert( pool.back != -1 ) @@ -153,8 +153,10 @@ pool_list_pop_back :: #force_inline proc( pool : ^PoolList ) -> PoolListValue { LRU_Link :: struct { pad_top : u64, + value : i32, - ptr : PoolListIter, + ptr : Pool_ListIter, + pad_bottom : u64, } @@ -162,34 +164,34 @@ LRU_Cache :: struct { capacity : i32, num : i32, table : map[u64]LRU_Link, - key_queue : PoolList, + key_queue : Pool_List, } -LRU_init :: proc( cache : ^LRU_Cache, capacity : i32, dbg_name : string = "" ) { - error : AllocatorError +lru_init :: proc( cache : ^LRU_Cache, capacity : i32, dbg_name : string = "" ) { + error : Allocator_Error cache.capacity = capacity cache.table, error = make( map[u64]LRU_Link, uint(capacity) ) - assert( error == .None, "VEFontCache.LRU_init : Failed to allocate cache's table") + assert( error == .None, "VEFontCache.lru_init : Failed to allocate cache's table") pool_list_init( & cache.key_queue, capacity, dbg_name = dbg_name ) } -LRU_free :: proc( cache : ^LRU_Cache ) { +lru_free :: proc( cache : ^LRU_Cache ) { pool_list_free( & cache.key_queue ) delete( cache.table ) } -LRU_reload :: #force_inline proc( cache : ^LRU_Cache, allocator : Allocator ) { +lru_reload :: #force_inline proc( cache : ^LRU_Cache, allocator : Allocator ) { reload_map( & cache.table, allocator ) pool_list_reload( & cache.key_queue, allocator ) } -LRU_find :: #force_inline proc "contextless" ( cache : ^LRU_Cache, key : u64, must_find := false ) -> (LRU_Link, bool) { +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 } -LRU_get :: #force_inline proc( cache: ^LRU_Cache, key : u64 ) -> i32 { +lru_get :: #force_inline proc( cache: ^LRU_Cache, key : u64 ) -> i32 { if link, ok := &cache.table[ key ]; ok { pool_list_move_to_front(&cache.key_queue, link.ptr) return link.value @@ -197,7 +199,7 @@ LRU_get :: #force_inline proc( cache: ^LRU_Cache, key : u64 ) -> i32 { return -1 } -LRU_get_next_evicted :: #force_inline proc ( cache : ^LRU_Cache ) -> u64 { +lru_get_next_evicted :: #force_inline proc ( cache : ^LRU_Cache ) -> u64 { if cache.key_queue.size >= cache.capacity { evict := pool_list_peek_back( & cache.key_queue ) return evict @@ -205,15 +207,15 @@ LRU_get_next_evicted :: #force_inline proc ( cache : ^LRU_Cache ) -> u64 { return 0xFFFFFFFFFFFFFFFF } -LRU_peek :: #force_inline proc ( cache : ^LRU_Cache, key : u64, must_find := false ) -> i32 { - iter, success := LRU_find( cache, key, must_find ) +lru_peek :: #force_inline proc ( cache : ^LRU_Cache, key : u64, must_find := false ) -> i32 { + iter, success := lru_find( cache, key, must_find ) if success == false { return -1 } return iter.value } -LRU_put :: #force_inline proc( cache : ^LRU_Cache, key : u64, value : i32 ) -> u64 +lru_put :: #force_inline proc( cache : ^LRU_Cache, key : u64, value : i32 ) -> u64 { if link, ok := & cache.table[ key ]; ok { pool_list_move_to_front( & cache.key_queue, link.ptr ) @@ -237,8 +239,8 @@ LRU_put :: #force_inline proc( cache : ^LRU_Cache, key : u64, value : i32 ) -> u return evict } -LRU_refresh :: proc( cache : ^LRU_Cache, key : u64 ) { - link, success := LRU_find( cache, key ) +lru_refresh :: proc( cache : ^LRU_Cache, key : u64 ) { + link, success := lru_find( cache, key ) pool_list_erase( & cache.key_queue, link.ptr ) pool_list_push_front( & cache.key_queue, key ) link.ptr = cache.key_queue.front diff --git a/vefontcache/atlas.odin b/vefontcache/atlas.odin index 47876b0..a211026 100644 --- a/vefontcache/atlas.odin +++ b/vefontcache/atlas.odin @@ -1,6 +1,6 @@ package vefontcache -AtlasRegionKind :: enum u8 { +Atlas_Region_Kind :: enum u8 { None = 0x00, A = 0x41, B = 0x42, @@ -10,7 +10,7 @@ AtlasRegionKind :: enum u8 { Ignore = 0xFF, // ve_fontcache_cache_glyph_to_atlas uses a -1 value in clear draw call } -AtlasRegion :: struct { +Atlas_Region :: struct { state : LRU_Cache, width : i32, @@ -29,13 +29,13 @@ Atlas :: struct { glyph_padding : i32, - region_a : AtlasRegion, - region_b : AtlasRegion, - region_c : AtlasRegion, - region_d : AtlasRegion, + region_a : Atlas_Region, + region_b : Atlas_Region, + region_c : Atlas_Region, + region_d : Atlas_Region, } -atlas_bbox :: proc( atlas : ^Atlas, region : AtlasRegionKind, local_idx : i32 ) -> (position, size: Vec2) +atlas_bbox :: proc( atlas : ^Atlas, region : Atlas_Region_Kind, local_idx : i32 ) -> (position, size: Vec2) { switch region { @@ -79,14 +79,12 @@ atlas_bbox :: proc( atlas : ^Atlas, region : AtlasRegionKind, local_idx : i32 ) position.x += f32(atlas.region_d.offset.x) position.y += f32(atlas.region_d.offset.y) - case .Ignore: fallthrough - case .None: fallthrough - case .E: + case .Ignore, .None, .E: } return } -decide_codepoint_region :: proc(ctx : ^Context, entry : ^Entry, glyph_index : Glyph ) -> (region_kind : AtlasRegionKind, region : ^AtlasRegion, over_sample : Vec2) +decide_codepoint_region :: proc(ctx : ^Context, entry : ^Entry, glyph_index : Glyph ) -> (region_kind : Atlas_Region_Kind, region : ^Atlas_Region, over_sample : Vec2) { if parser_is_glyph_empty(&entry.parser_info, glyph_index) { return .None, nil, {} @@ -104,11 +102,11 @@ decide_codepoint_region :: proc(ctx : ^Context, entry : ^Entry, glyph_index : Gl bounds_height_scaled := i32(bounds_height * entry.size_scale + glyph_padding) // Use a lookup table for faster region selection - region_lookup := [4]struct { kind: AtlasRegionKind, region: ^AtlasRegion } { - { .A, & atlas.region_a }, - { .B, & atlas.region_b }, - { .C, & atlas.region_c }, - { .D, & atlas.region_d }, + region_lookup := [4]struct { kind: Atlas_Region_Kind, region: ^Atlas_Region } { + { .A, & atlas.region_a }, + { .B, & atlas.region_b }, + { .C, & atlas.region_c }, + { .D, & atlas.region_d }, } for region in region_lookup do if bounds_width_scaled <= region.region.width && bounds_height_scaled <= region.region.height { diff --git a/vefontcache/draw.odin b/vefontcache/draw.odin index 5fcd883..f45e8b6 100644 --- a/vefontcache/draw.odin +++ b/vefontcache/draw.odin @@ -8,16 +8,16 @@ Vertex :: struct { u, v : f32, } -DrawCall :: struct { - pass : FrameBufferPass, +Draw_Call :: struct { + pass : Frame_Buffer_Pass, start_index : u32, end_index : u32, clear_before_draw : b32, - region : AtlasRegionKind, + region : Atlas_Region_Kind, colour : Colour, } -DrawCall_Default :: DrawCall { +Draw_Call_Default :: Draw_Call { pass = .None, start_index = 0, end_index = 0, @@ -26,14 +26,14 @@ DrawCall_Default :: DrawCall { colour = { 1.0, 1.0, 1.0, 1.0 } } -DrawList :: struct { +Draw_List :: struct { vertices : [dynamic]Vertex, indices : [dynamic]u32, - calls : [dynamic]DrawCall, + calls : [dynamic]Draw_Call, } // TODO(Ed): This was a rough translation of the raw values the orignal was using, need to give better names... -FrameBufferPass :: enum u32 { +Frame_Buffer_Pass :: enum u32 { None = 0, Glyph = 1, Atlas = 2, @@ -41,7 +41,7 @@ FrameBufferPass :: enum u32 { Target_Uncached = 4, } -GlyphDrawBuffer :: struct { +Glyph_Draw_Buffer :: struct { over_sample : Vec2, batch : i32, width : i32, @@ -49,11 +49,11 @@ GlyphDrawBuffer :: struct { draw_padding : i32, batch_x : i32, - clear_draw_list : DrawList, - draw_list : DrawList, + clear_draw_list : Draw_List, + draw_list : Draw_List, } -blit_quad :: proc( draw_list : ^DrawList, p0 : Vec2 = {0, 0}, p1 : Vec2 = {1, 1}, uv0 : Vec2 = {0, 0}, uv1 : Vec2 = {1, 1} ) +blit_quad :: proc( draw_list : ^Draw_List, p0 : Vec2 = {0, 0}, p1 : Vec2 = {1, 1}, uv0 : Vec2 = {0, 0}, uv1 : Vec2 = {1, 1} ) { // profile(#procedure) // logf("Blitting: xy0: %0.2f, %0.2f xy1: %0.2f, %0.2f uv0: %0.2f, %0.2f uv1: %0.2f, %0.2f", @@ -89,9 +89,9 @@ blit_quad :: proc( draw_list : ^DrawList, p0 : Vec2 = {0, 0}, p1 : Vec2 = {1, 1} } // TODO(Ed): glyph caching cannot be handled in a 'font parser' abstraction. Just going to have explicit procedures to grab info neatly... -cache_glyph_freetype :: proc(ctx: ^Context, font: FontID, glyph_index: Glyph, entry: ^Entry, bounds_0, bounds_1: Vec2, scale, translate: Vec2) -> b32 +cache_glyph_freetype :: proc(ctx: ^Context, font: Font_ID, glyph_index: Glyph, entry: ^Entry, bounds_0, bounds_1: Vec2, scale, translate: Vec2) -> b32 { - draw_filled_path_freetype :: proc( draw_list : ^DrawList, outside_point : Vec2, path : []Vertex, + draw_filled_path_freetype :: proc( draw_list : ^Draw_List, outside_point : Vec2, path : []Vertex, scale := Vec2 { 1, 1 }, translate := Vec2 { 0, 0 }, debug_print_verbose : b32 = false @@ -106,7 +106,7 @@ cache_glyph_freetype :: proc(ctx: ^Context, font: FontID, glyph_index: Glyph, en } v_offset := cast(u32) len(draw_list.vertices) - for point in path + for point in path { transformed_point := Vertex { pos = point.pos * scale + translate, @@ -130,9 +130,9 @@ cache_glyph_freetype :: proc(ctx: ^Context, font: FontID, glyph_index: Glyph, en // Close the path by connecting the last vertex to the first two to_add := [3]u32 { - v_offset, - v_offset + cast(u32)(len(path) - 1), - v_offset + 1 + v_offset, + v_offset + cast(u32)(len(path) - 1), + v_offset + 1 } append( indices, ..to_add[:] ) } @@ -158,8 +158,8 @@ cache_glyph_freetype :: proc(ctx: ^Context, font: FontID, glyph_index: Glyph, en return false } - draw := DrawCall_Default - draw.pass = FrameBufferPass.Glyph + draw := Draw_Call_Default + draw.pass = Frame_Buffer_Pass.Glyph draw.start_index = cast(u32) len(ctx.draw_list.indices) contours := slice.from_ptr(cast( [^]i16) outline.contours, int(outline.n_contours)) @@ -178,57 +178,57 @@ cache_glyph_freetype :: proc(ctx: ^Context, font: FontID, glyph_index: Glyph, en prev_point: Vec2 first_point: Vec2 - for idx := start_index; idx < end_index; idx += 1 + for idx := start_index; idx < end_index; idx += 1 + { + current_pos := Vec2 { f32( points[idx].x ), f32( points[idx].y ) } + if ( tags[idx] & 1 ) == 0 { - current_pos := Vec2 { f32( points[idx].x ), f32( points[idx].y ) } - if ( tags[idx] & 1 ) == 0 + // If current point is off-curve + if (idx == start_index || (tags[ idx - 1 ] & 1) != 0) { - // If current point is off-curve - if (idx == start_index || (tags[ idx - 1 ] & 1) != 0) - { - // current is the first or following an on-curve point - prev_point = current_pos - } - else - { - // current and previous are off-curve, calculate midpoint - midpoint := (prev_point + current_pos) * 0.5 - append( path, Vertex { pos = midpoint } ) // Add midpoint as on-curve point - if idx < end_index - 1 - { - // perform interp from prev_point to current_pos via midpoint - step := 1.0 / entry.curve_quality - for alpha : f32 = 0.0; alpha <= 1.0; alpha += step - { - bezier_point := eval_point_on_bezier3( prev_point, midpoint, current_pos, alpha ) - append( path, Vertex{ pos = bezier_point } ) - } - } - - prev_point = current_pos - } + // current is the first or following an on-curve point + prev_point = current_pos } else { - if idx == start_index { - first_point = current_pos + // current and previous are off-curve, calculate midpoint + midpoint := (prev_point + current_pos) * 0.5 + append( path, Vertex { pos = midpoint } ) // Add midpoint as on-curve point + if idx < end_index - 1 + { + // perform interp from prev_point to current_pos via midpoint + step := 1.0 / entry.curve_quality + for alpha : f32 = 0.0; alpha <= 1.0; alpha += step + { + bezier_point := eval_point_on_bezier3( prev_point, midpoint, current_pos, alpha ) + append( path, Vertex{ pos = bezier_point } ) + } } - if prev_point != (Vec2{}) { - // there was an off-curve point before this - append(path, Vertex{ pos = prev_point}) // Ensure previous off-curve is handled - } - append(path, Vertex{ pos = current_pos}) - prev_point = {} + + prev_point = current_pos } } - - // ensure the contour is closed - if path[0].pos != path[ len(path) - 1 ].pos { - append(path, Vertex{pos = path[0].pos}) + else + { + if idx == start_index { + first_point = current_pos + } + if prev_point != (Vec2{}) { + // there was an off-curve point before this + append(path, Vertex{ pos = prev_point}) // Ensure previous off-curve is handled + } + append(path, Vertex{ pos = current_pos}) + prev_point = {} } - draw_filled_path(&ctx.draw_list, bounds_0, path[:], scale, translate, ctx.debug_print_verbose) - clear(path) - start_index = end_index + } + + // ensure the contour is closed + if path[0].pos != path[ len(path) - 1 ].pos { + append(path, Vertex{pos = path[0].pos}) + } + draw_filled_path(&ctx.draw_list, bounds_0, path[:], scale, translate, ctx.debug_print_verbose) + clear(path) + start_index = end_index } if len(path) > 0 { @@ -244,7 +244,7 @@ cache_glyph_freetype :: proc(ctx: ^Context, font: FontID, glyph_index: Glyph, en } // TODO(Ed): Is it better to cache the glyph vertices for when it must be re-drawn (directly or two atlas)? -cache_glyph :: proc(ctx : ^Context, font : FontID, glyph_index : Glyph, entry : ^Entry, bounds_0, bounds_1 : Vec2, scale, translate : Vec2) -> b32 +cache_glyph :: proc(ctx : ^Context, font : Font_ID, glyph_index : Glyph, entry : ^Entry, bounds_0, bounds_1 : Vec2, scale, translate : Vec2) -> b32 { // profile(#procedure) if glyph_index == Glyph(0) { @@ -265,8 +265,8 @@ cache_glyph :: proc(ctx : ^Context, font : FontID, glyph_index : Glyph, entry : outside := Vec2{bounds_0.x - 21, bounds_0.y - 33} - draw := DrawCall_Default - draw.pass = FrameBufferPass.Glyph + draw := Draw_Call_Default + draw.pass = Frame_Buffer_Pass.Glyph draw.start_index = u32(len(ctx.draw_list.indices)) path := &ctx.temp_path @@ -276,8 +276,8 @@ cache_glyph :: proc(ctx : ^Context, font : FontID, glyph_index : Glyph, entry : { case .Move: if len(path) > 0 { - draw_filled_path(&ctx.draw_list, outside, path[:], scale, translate, ctx.debug_print_verbose) - clear(path) + draw_filled_path(&ctx.draw_list, outside, path[:], scale, translate, ctx.debug_print_verbose) + clear(path) } fallthrough @@ -329,13 +329,13 @@ cache_glyph :: proc(ctx : ^Context, font : FontID, glyph_index : Glyph, entry : * draw_text_shape : Glyph */ cache_glyph_to_atlas :: proc( ctx : ^Context, - font : FontID, + font : Font_ID, glyph_index : Glyph, lru_code : u64, atlas_index : i32, entry : ^Entry, - region_kind : AtlasRegionKind, - region : ^AtlasRegion, + region_kind : Atlas_Region_Kind, + region : ^Atlas_Region, over_sample : Vec2 ) { // profile(#procedure) @@ -356,24 +356,24 @@ cache_glyph_to_atlas :: proc( ctx : ^Context, { if region.next_idx < region.state.capacity { - evicted := LRU_put( & region.state, lru_code, i32(region.next_idx) ) + evicted := lru_put( & region.state, lru_code, i32(region.next_idx) ) atlas_index = i32(region.next_idx) region.next_idx += 1 assert( evicted == lru_code ) } else { - next_evict_codepoint := LRU_get_next_evicted( & region.state ) + next_evict_codepoint := lru_get_next_evicted( & region.state ) assert( next_evict_codepoint != 0xFFFFFFFFFFFFFFFF ) - atlas_index = LRU_peek( & region.state, next_evict_codepoint, must_find = true ) + atlas_index = lru_peek( & region.state, next_evict_codepoint, must_find = true ) assert( atlas_index != -1 ) - evicted := LRU_put( & region.state, lru_code, atlas_index ) + evicted := lru_put( & region.state, lru_code, atlas_index ) assert( evicted == next_evict_codepoint ) } - assert( LRU_get( & region.state, lru_code ) != - 1 ) + assert( lru_get( & region.state, lru_code ) != - 1 ) } atlas := & ctx.atlas @@ -420,7 +420,7 @@ cache_glyph_to_atlas :: proc( ctx : ^Context, glyph_buffer.batch_x += i32(gwidth_scaled_px) screenspace_x_form( & glyph_draw_translate, & glyph_draw_scale, glyph_buffer_size ) - clear_target_region : DrawCall + clear_target_region : Draw_Call { using clear_target_region pass = .Atlas @@ -434,7 +434,7 @@ cache_glyph_to_atlas :: proc( ctx : ^Context, end_index = cast(u32) len(glyph_buffer.clear_draw_list.indices) } - blit_to_atlas : DrawCall + blit_to_atlas : Draw_Call { using blit_to_atlas pass = .Atlas @@ -456,11 +456,11 @@ cache_glyph_to_atlas :: proc( ctx : ^Context, } // If the glyuph is found in the atlas, nothing occurs, otherwise, the glyph call is setup to catch it to the atlas -check_glyph_in_atlas :: #force_inline proc( ctx : ^Context, font : FontID, entry : ^Entry, glyph_index : Glyph, +check_glyph_in_atlas :: #force_inline proc( ctx : ^Context, font : Font_ID, entry : ^Entry, glyph_index : Glyph, lru_code : u64, atlas_index : i32, - region_kind : AtlasRegionKind, - region : ^AtlasRegion, + region_kind : Atlas_Region_Kind, + region : ^Atlas_Region, over_sample : Vec2 ) -> b32 { @@ -476,7 +476,7 @@ check_glyph_in_atlas :: #force_inline proc( ctx : ^Context, font : FontID, entry { if region.next_idx > region.state.capacity { // We will evict LRU. We must predict which LRU will get evicted, and if it's something we've seen then we need to take slowpath and flush batch. - next_evict_codepoint := LRU_get_next_evicted( & region.state ) + next_evict_codepoint := lru_get_next_evicted( & region.state ) seen, success := ctx.temp_codepoint_seen[next_evict_codepoint] assert(success != false) @@ -488,13 +488,13 @@ check_glyph_in_atlas :: #force_inline proc( ctx : ^Context, font : FontID, entry cache_glyph_to_atlas( ctx, font, glyph_index, lru_code, atlas_index, entry, region_kind, region, over_sample ) } - assert( LRU_get( & region.state, lru_code ) != -1 ) + assert( lru_get( & region.state, lru_code ) != -1 ) mark_batch_codepoint_seen( ctx, lru_code) return true } -// ve_fontcache_clear_drawlist -clear_draw_list :: #force_inline proc ( draw_list : ^DrawList ) { +// ve_fontcache_clear_Draw_List +clear_draw_list :: #force_inline proc ( draw_list : ^Draw_List ) { clear( & draw_list.calls ) clear( & draw_list.indices ) clear( & draw_list.vertices ) @@ -538,8 +538,8 @@ directly_draw_massive_glyph :: proc( ctx : ^Context, dst_size := glyph_dst_size * scale textspace_x_form( & glyph_position, & glyph_size, glyph_buffer_size ) - // Add the glyph drawcall. - calls : [2]DrawCall + // Add the glyph Draw_Call. + calls : [2]Draw_Call draw_to_target := & calls[0] { @@ -549,8 +549,8 @@ directly_draw_massive_glyph :: proc( ctx : ^Context, start_index = u32(len(ctx.draw_list.indices)) blit_quad( & ctx.draw_list, - dst, dst + dst_size, - glyph_position, glyph_position + glyph_size ) + dst, dst + dst_size, + glyph_position, glyph_position + glyph_size ) end_index = u32(len(ctx.draw_list.indices)) } @@ -570,9 +570,9 @@ directly_draw_massive_glyph :: proc( ctx : ^Context, // outside_point represents the center point of the fan. // // Note(Original Author): -// WARNING: doesn't actually append drawcall; caller is responsible for actually appending the drawcall. +// WARNING: doesn't actually append Draw_Call; caller is responsible for actually appending the Draw_Call. // ve_fontcache_draw_filled_path -draw_filled_path :: proc( draw_list : ^DrawList, outside_point : Vec2, path : []Vertex, +draw_filled_path :: proc( draw_list : ^Draw_List, outside_point : Vec2, path : []Vertex, scale := Vec2 { 1, 1 }, translate := Vec2 { 0, 0 }, debug_print_verbose : b32 = false @@ -615,7 +615,7 @@ draw_filled_path :: proc( draw_list : ^DrawList, outside_point : Vec2, path : [] } } -draw_text_batch :: proc(ctx: ^Context, entry: ^Entry, shaped: ^ShapedText, +draw_text_batch :: proc(ctx: ^Context, entry: ^Entry, shaped: ^Shaped_Text, batch_start_idx, batch_end_idx : i32, position, scale : Vec2, snap_width, snap_height : f32 ) @@ -634,7 +634,7 @@ draw_text_batch :: proc(ctx: ^Context, entry: ^Entry, shaped: ^ShapedText, region_kind, region, over_sample := decide_codepoint_region( ctx, entry, glyph_index ) lru_code := font_glyph_lru_code( entry.id, glyph_index ) - atlas_index := region_kind != .E ? LRU_get( & region.state, lru_code ) : -1 + atlas_index := region_kind != .E ? lru_get( & region.state, lru_code ) : -1 bounds_0, bounds_1 := parser_get_glyph_box( & entry.parser_info, glyph_index ) vbounds_0 := vec2(bounds_0) vbounds_1 := vec2(bounds_1) @@ -660,7 +660,7 @@ draw_text_batch :: proc(ctx: ^Context, entry: ^Entry, shaped: ^ShapedText, dst_scale := glyph_scale * scale textspace_x_form( & slot_position, & glyph_scale, atlas_size ) - call := DrawCall_Default + call := Draw_Call_Default call.pass = .Target call.colour = ctx.colour call.start_index = u32(len(ctx.draw_list.indices)) @@ -677,9 +677,9 @@ draw_text_batch :: proc(ctx: ^Context, entry: ^Entry, shaped: ^ShapedText, // Helper for draw_text, all raw text content should be confirmed to be either formatting or visible shapes before getting cached. draw_text_shape :: proc( ctx : ^Context, - font : FontID, + font : Font_ID, entry : ^Entry, - shaped : ^ShapedText, + shaped : ^Shaped_Text, position, scale : Vec2, snap_width, snap_height : f32 ) -> (cursor_pos : Vec2) @@ -695,7 +695,7 @@ draw_text_shape :: proc( ctx : ^Context, lru_code := font_glyph_lru_code(entry.id, glyph_index) atlas_index := cast(i32) -1 - if region_kind != .E do atlas_index = LRU_get( & region.state, lru_code ) + if region_kind != .E do atlas_index = lru_get( & region.state, lru_code ) if check_glyph_in_atlas( ctx, font, entry, glyph_index, lru_code, atlas_index, region_kind, region, over_sample ) do continue // We can no longer directly append the shape as it has missing glyphs in the atlas @@ -720,7 +720,7 @@ draw_text_shape :: proc( ctx : ^Context, flush_glyph_buffer_to_atlas :: proc( ctx : ^Context ) { // profile(#procedure) - // Flush drawcalls to draw list + // Flush Draw_Calls to draw list merge_draw_list( & ctx.draw_list, & ctx.glyph_buffer.clear_draw_list ) merge_draw_list( & ctx.draw_list, & ctx.glyph_buffer.draw_list) clear_draw_list( & ctx.glyph_buffer.draw_list ) @@ -729,7 +729,7 @@ flush_glyph_buffer_to_atlas :: proc( ctx : ^Context ) // Clear glyph_update_FBO if ctx.glyph_buffer.batch_x != 0 { - call := DrawCall_Default + call := Draw_Call_Default call.pass = .Glyph call.start_index = 0 call.end_index = 0 @@ -739,11 +739,11 @@ flush_glyph_buffer_to_atlas :: proc( ctx : ^Context ) } } -// ve_fontcache_merge_drawlist -merge_draw_list :: proc( dst, src : ^DrawList ) +// ve_fontcache_merge_Draw_List +merge_draw_list :: proc( dst, src : ^Draw_List ) { // profile(#procedure) - error : AllocatorError + error : Allocator_Error v_offset := cast(u32) len( dst.vertices ) num_appended : int @@ -766,11 +766,11 @@ merge_draw_list :: proc( dst, src : ^DrawList ) } } -optimize_draw_list :: proc(draw_list: ^DrawList, call_offset: int) { +optimize_draw_list :: proc(draw_list: ^Draw_List, call_offset: int) { // profile(#procedure) assert(draw_list != nil) - can_merge_draw_calls :: #force_inline proc "contextless" ( a, b : ^DrawCall ) -> bool { + can_merge_draw_calls :: #force_inline proc "contextless" ( a, b : ^Draw_Call ) -> bool { result := \ a.pass == b.pass && a.end_index == b.start_index && diff --git a/vefontcache/mappings.odin b/vefontcache/mappings.odin index 6acd64b..83e67bb 100644 --- a/vefontcache/mappings.odin +++ b/vefontcache/mappings.odin @@ -27,8 +27,8 @@ import "core:mem" Kilobyte :: mem.Kilobyte slice_ptr :: mem.slice_ptr - Allocator :: mem.Allocator - AllocatorError :: mem.Allocator_Error + Allocator :: mem.Allocator + Allocator_Error :: mem.Allocator_Error Arena :: mem.Arena arena_allocator :: mem.arena_allocator diff --git a/vefontcache/misc.odin b/vefontcache/misc.odin index 0b1e860..e34fbf0 100644 --- a/vefontcache/misc.odin +++ b/vefontcache/misc.odin @@ -49,7 +49,7 @@ reload_map :: proc( self : ^map [$KeyType] $EntryType, allocator : Allocator ) { raw.allocator = allocator } -font_glyph_lru_code :: #force_inline proc "contextless" ( font : FontID, glyph_index : Glyph ) -> (lru_code : u64) { +font_glyph_lru_code :: #force_inline proc "contextless" ( font : Font_ID, glyph_index : Glyph ) -> (lru_code : u64) { lru_code = u64(glyph_index) + ( ( 0x100000000 * u64(font) ) & 0xFFFFFFFF00000000 ) return } @@ -71,9 +71,11 @@ reset_batch_codepoint_state :: #force_inline proc( ctx : ^Context ) { ctx.temp_codepoint_seen_num = 0 } +USE_F64_PRECISION_ON_X_FORM_OPS :: false + screenspace_x_form :: #force_inline proc "contextless" ( position, scale : ^Vec2, size : Vec2 ) { - if true + when USE_F64_PRECISION_ON_X_FORM_OPS { pos_64 := vec2_64_from_vec2(position^) scale_64 := vec2_64_from_vec2(scale^) @@ -101,7 +103,7 @@ screenspace_x_form :: #force_inline proc "contextless" ( position, scale : ^Vec2 textspace_x_form :: #force_inline proc "contextless" ( position, scale : ^Vec2, size : Vec2 ) { - if true + when USE_F64_PRECISION_ON_X_FORM_OPS { pos_64 := vec2_64_from_vec2(position^) scale_64 := vec2_64_from_vec2(scale^) @@ -121,9 +123,9 @@ textspace_x_form :: #force_inline proc "contextless" ( position, scale : ^Vec2, } } -Use_SIMD_For_Bezier_Ops :: false +USE_MANUAL_SIMD_FOR_BEZIER_OPS :: false -when ! Use_SIMD_For_Bezier_Ops +when ! USE_MANUAL_SIMD_FOR_BEZIER_OPS { // For a provided alpha value, // allows the function to calculate the position of a point along the curve at any given fraction of its total length diff --git a/vefontcache/parser.odin b/vefontcache/parser.odin index 1eef70d..d71ab07 100644 --- a/vefontcache/parser.odin +++ b/vefontcache/parser.odin @@ -16,14 +16,14 @@ import "core:slice" import stbtt "vendor:stb/truetype" import freetype "thirdparty:freetype" -ParserKind :: enum u32 { +Parser_Kind :: enum u32 { STB_TrueType, Freetype, } -ParserFontInfo :: struct { +Parser_Font_Info :: struct { label : string, - kind : ParserKind, + kind : Parser_Kind, using _ : struct #raw_union { stbtt_info : stbtt.fontinfo, freetype_info : freetype.Face @@ -31,7 +31,7 @@ ParserFontInfo :: struct { data : []byte, } -GlyphVertType :: enum u8 { +Glyph_Vert_Type :: enum u8 { None, Move = 1, Line, @@ -40,22 +40,22 @@ GlyphVertType :: enum u8 { } // Based directly off of stb_truetype's vertex -ParserGlyphVertex :: struct { +Parser_Glyph_Vertex :: struct { x, y : i16, contour_x0, contour_y0 : i16, contour_x1, contour_y1 : i16, - type : GlyphVertType, + type : Glyph_Vert_Type, padding : u8, } // A shape can be a dynamic array free_type or an opaque set of data handled by stb_truetype -ParserGlyphShape :: [dynamic]ParserGlyphVertex +Parser_Glyph_Shape :: [dynamic]Parser_Glyph_Vertex -ParserContext :: struct { - kind : ParserKind, +Parser_Context :: struct { + kind : Parser_Kind, ft_library : freetype.Library, } -parser_init :: proc( ctx : ^ParserContext, kind : ParserKind ) +parser_init :: proc( ctx : ^Parser_Context, kind : Parser_Kind ) { switch kind { @@ -70,11 +70,11 @@ parser_init :: proc( ctx : ^ParserContext, kind : ParserKind ) ctx.kind = kind } -parser_shutdown :: proc( ctx : ^ParserContext ) { +parser_shutdown :: proc( ctx : ^Parser_Context ) { // TODO(Ed): Implement } -parser_load_font :: proc( ctx : ^ParserContext, label : string, data : []byte ) -> (font : ParserFontInfo) +parser_load_font :: proc( ctx : ^Parser_Context, label : string, data : []byte ) -> (font : Parser_Font_Info) { switch ctx.kind { @@ -93,7 +93,7 @@ parser_load_font :: proc( ctx : ^ParserContext, label : string, data : []byte ) return } -parser_unload_font :: proc( font : ^ParserFontInfo ) +parser_unload_font :: proc( font : ^Parser_Font_Info ) { switch font.kind { case .Freetype: @@ -105,7 +105,7 @@ parser_unload_font :: proc( font : ^ParserFontInfo ) } } -parser_find_glyph_index :: #force_inline proc "contextless" ( font : ^ParserFontInfo, codepoint : rune ) -> (glyph_index : Glyph) +parser_find_glyph_index :: #force_inline proc "contextless" ( font : ^Parser_Font_Info, codepoint : rune ) -> (glyph_index : Glyph) { switch font.kind { @@ -120,7 +120,7 @@ parser_find_glyph_index :: #force_inline proc "contextless" ( font : ^ParserFont return Glyph(-1) } -parser_free_shape :: proc( font : ^ParserFontInfo, shape : ParserGlyphShape ) +parser_free_shape :: proc( font : ^Parser_Font_Info, shape : Parser_Glyph_Shape ) { switch font.kind { @@ -132,7 +132,7 @@ parser_free_shape :: proc( font : ^ParserFontInfo, shape : ParserGlyphShape ) } } -parser_get_codepoint_horizontal_metrics :: #force_inline proc "contextless" ( font : ^ParserFontInfo, codepoint : rune ) -> ( advance, to_left_side_glyph : i32 ) +parser_get_codepoint_horizontal_metrics :: #force_inline proc "contextless" ( font : ^Parser_Font_Info, codepoint : rune ) -> ( advance, to_left_side_glyph : i32 ) { switch font.kind { @@ -156,7 +156,7 @@ parser_get_codepoint_horizontal_metrics :: #force_inline proc "contextless" ( fo return } -parser_get_codepoint_kern_advance :: #force_inline proc "contextless" ( font : ^ParserFontInfo, prev_codepoint, codepoint : rune ) -> i32 +parser_get_codepoint_kern_advance :: #force_inline proc "contextless" ( font : ^Parser_Font_Info, prev_codepoint, codepoint : rune ) -> i32 { switch font.kind { @@ -176,7 +176,7 @@ parser_get_codepoint_kern_advance :: #force_inline proc "contextless" ( font : ^ return -1 } -parser_get_font_vertical_metrics :: #force_inline proc "contextless" ( font : ^ParserFontInfo ) -> (ascent, descent, line_gap : i32 ) +parser_get_font_vertical_metrics :: #force_inline proc "contextless" ( font : ^Parser_Font_Info ) -> (ascent, descent, line_gap : i32 ) { switch font.kind { @@ -192,7 +192,7 @@ parser_get_font_vertical_metrics :: #force_inline proc "contextless" ( font : ^P return } -parser_get_glyph_box :: #force_inline proc ( font : ^ParserFontInfo, glyph_index : Glyph ) -> (bounds_0, bounds_1 : Vec2i) +parser_get_glyph_box :: #force_inline proc ( font : ^Parser_Font_Info, glyph_index : Glyph ) -> (bounds_0, bounds_1 : Vec2i) { switch font.kind { @@ -215,7 +215,7 @@ parser_get_glyph_box :: #force_inline proc ( font : ^ParserFontInfo, glyph_index return } -parser_get_glyph_shape :: proc( font : ^ParserFontInfo, glyph_index : Glyph ) -> (shape : ParserGlyphShape, error : AllocatorError) +parser_get_glyph_shape :: proc( font : ^Parser_Font_Info, glyph_index : Glyph ) -> (shape : Parser_Glyph_Shape, error : Allocator_Error) { switch font.kind { @@ -232,14 +232,14 @@ parser_get_glyph_shape :: proc( font : ^ParserFontInfo, glyph_index : Glyph ) -> shape_raw.len = int(nverts) shape_raw.cap = int(nverts) shape_raw.allocator = runtime.nil_allocator() - error = AllocatorError.None + error = Allocator_Error.None return } return } -parser_is_glyph_empty :: #force_inline proc "contextless" ( font : ^ParserFontInfo, glyph_index : Glyph ) -> b32 +parser_is_glyph_empty :: #force_inline proc "contextless" ( font : ^Parser_Font_Info, glyph_index : Glyph ) -> b32 { switch font.kind { @@ -262,7 +262,7 @@ parser_is_glyph_empty :: #force_inline proc "contextless" ( font : ^ParserFontIn return false } -parser_scale :: #force_inline proc "contextless" ( font : ^ParserFontInfo, size : f32 ) -> f32 +parser_scale :: #force_inline proc "contextless" ( font : ^Parser_Font_Info, size : f32 ) -> f32 { size_scale := size < 0.0 ? \ parser_scale_for_pixel_height( font, -size ) \ @@ -271,7 +271,7 @@ parser_scale :: #force_inline proc "contextless" ( font : ^ParserFontInfo, size return size_scale } -parser_scale_for_pixel_height :: #force_inline proc "contextless" ( font : ^ParserFontInfo, size : f32 ) -> f32 +parser_scale_for_pixel_height :: #force_inline proc "contextless" ( font : ^Parser_Font_Info, size : f32 ) -> f32 { switch font.kind { case .Freetype: @@ -285,7 +285,7 @@ parser_scale_for_pixel_height :: #force_inline proc "contextless" ( font : ^Pars return 0 } -parser_scale_for_mapping_em_to_pixels :: #force_inline proc "contextless" ( font : ^ParserFontInfo, size : f32 ) -> f32 +parser_scale_for_mapping_em_to_pixels :: #force_inline proc "contextless" ( font : ^Parser_Font_Info, size : f32 ) -> f32 { switch font.kind { case .Freetype: diff --git a/vefontcache/shaped_text.odin b/vefontcache/shaped_text.odin index 5e7e9bd..ba5c80f 100644 --- a/vefontcache/shaped_text.odin +++ b/vefontcache/shaped_text.odin @@ -1,14 +1,14 @@ package vefontcache -ShapedText :: struct { +Shaped_Text :: struct { glyphs : [dynamic]Glyph, positions : [dynamic]Vec2, end_cursor_pos : Vec2, size : Vec2, } -ShapedTextCache :: struct { - storage : [dynamic]ShapedText, +Shaped_Text_Cache :: struct { + storage : [dynamic]Shaped_Text, state : LRU_Cache, next_cache_id : i32, } @@ -19,11 +19,11 @@ shape_lru_hash :: #force_inline proc "contextless" ( hash : ^u64, bytes : []byte } } -shape_text_cached :: proc( ctx : ^Context, font : FontID, text_utf8 : string, entry : ^Entry ) -> ^ShapedText +shape_text_cached :: proc( ctx : ^Context, font : Font_ID, text_utf8 : string, entry : ^Entry ) -> ^Shaped_Text { // profile(#procedure) font := font - font_bytes := slice_ptr( transmute(^byte) & font, size_of(FontID) ) + font_bytes := slice_ptr( transmute(^byte) & font, size_of(Font_ID) ) text_bytes := transmute( []byte) text_utf8 lru_code : u64 @@ -33,23 +33,23 @@ shape_text_cached :: proc( ctx : ^Context, font : FontID, text_utf8 : string, en shape_cache := & ctx.shape_cache state := & ctx.shape_cache.state - shape_cache_idx := LRU_get( state, lru_code ) + shape_cache_idx := lru_get( state, lru_code ) if shape_cache_idx == -1 { if shape_cache.next_cache_id < i32(state.capacity) { shape_cache_idx = shape_cache.next_cache_id shape_cache.next_cache_id += 1 - evicted := LRU_put( state, lru_code, shape_cache_idx ) + evicted := lru_put( state, lru_code, shape_cache_idx ) } else { - next_evict_idx := LRU_get_next_evicted( state ) + next_evict_idx := lru_get_next_evicted( state ) assert( next_evict_idx != 0xFFFFFFFFFFFFFFFF ) - shape_cache_idx = LRU_peek( state, next_evict_idx, must_find = true ) + shape_cache_idx = lru_peek( state, next_evict_idx, must_find = true ) assert( shape_cache_idx != - 1 ) - LRU_put( state, lru_code, shape_cache_idx ) + lru_put( state, lru_code, shape_cache_idx ) } shape_entry := & shape_cache.storage[ shape_cache_idx ] @@ -59,7 +59,7 @@ shape_text_cached :: proc( ctx : ^Context, font : FontID, text_utf8 : string, en return & shape_cache.storage[ shape_cache_idx ] } -shape_text_uncached :: proc( ctx : ^Context, font : FontID, text_utf8 : string, entry : ^Entry, output : ^ShapedText ) +shape_text_uncached :: proc( ctx : ^Context, font : Font_ID, text_utf8 : string, entry : ^Entry, output : ^Shaped_Text ) { // profile(#procedure) assert( ctx != nil ) @@ -106,7 +106,7 @@ shape_text_uncached :: proc( ctx : ^Context, font : FontID, text_utf8 : string, prev_codepoint = rune(0) continue } - if abs( entry.size ) <= Advance_Snap_Smallfont_Size { + if abs( entry.size ) <= ADVANCE_SNAP_SMALLFONT_SIZE { position.x = position.x } diff --git a/vefontcache/shaper.odin b/vefontcache/shaper.odin index ecc8495..6993e5f 100644 --- a/vefontcache/shaper.odin +++ b/vefontcache/shaper.odin @@ -6,35 +6,35 @@ Note(Ed): The only reason I didn't directly use harfbuzz is because hamza exists import "core:c" import "thirdparty:harfbuzz" -ShaperKind :: enum { +Shaper_Kind :: enum { Naive = 0, Harfbuzz = 1, } -ShaperContext :: struct { +Shaper_Context :: struct { hb_buffer : harfbuzz.Buffer, } -ShaperInfo :: struct { +Shaper_Info :: struct { blob : harfbuzz.Blob, face : harfbuzz.Face, font : harfbuzz.Font, } -shaper_init :: proc( ctx : ^ShaperContext ) +shaper_init :: proc( ctx : ^Shaper_Context ) { ctx.hb_buffer = harfbuzz.buffer_create() assert( ctx.hb_buffer != nil, "VEFontCache.shaper_init: Failed to create harfbuzz buffer") } -shaper_shutdown :: proc( ctx : ^ShaperContext ) +shaper_shutdown :: proc( ctx : ^Shaper_Context ) { if ctx.hb_buffer != nil { harfbuzz.buffer_destroy( ctx.hb_buffer ) } } -shaper_load_font :: proc( ctx : ^ShaperContext, label : string, data : []byte, user_data : rawptr ) -> (info : ShaperInfo) +shaper_load_font :: proc( ctx : ^Shaper_Context, label : string, data : []byte, user_data : rawptr ) -> (info : Shaper_Info) { using info blob = harfbuzz.blob_create( raw_data(data), cast(c.uint) len(data), harfbuzz.Memory_Mode.READONLY, user_data, nil ) @@ -43,7 +43,7 @@ shaper_load_font :: proc( ctx : ^ShaperContext, label : string, data : []byte, u return } -shaper_unload_font :: proc( ctx : ^ShaperInfo ) +shaper_unload_font :: proc( ctx : ^Shaper_Info ) { using ctx if blob != nil do harfbuzz.font_destroy( font ) @@ -51,7 +51,7 @@ shaper_unload_font :: proc( ctx : ^ShaperInfo ) if blob != nil do harfbuzz.blob_destroy( blob ) } -shaper_shape_from_text :: proc( ctx : ^ShaperContext, info : ^ShaperInfo, output :^ShapedText, text_utf8 : string, +shaper_shape_from_text :: proc( ctx : ^Shaper_Context, info : ^Shaper_Info, output :^Shaped_Text, text_utf8 : string, ascent, descent, line_gap : i32, size, size_scale : f32 ) { // profile(#procedure) @@ -69,7 +69,7 @@ shaper_shape_from_text :: proc( ctx : ^ShaperContext, info : ^ShaperInfo, output 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 : ^ShapedText, + 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 ) { @@ -105,7 +105,7 @@ shaper_shape_from_text :: proc( ctx : ^ShaperContext, info : ^ShaperInfo, output (line_count^) += 1 continue } - if abs( size ) <= Advance_Snap_Smallfont_Size + if abs( size ) <= ADVANCE_SNAP_SMALLFONT_SIZE { (position^) = ceil( position^ ) } diff --git a/vefontcache/vefontcache.odin b/vefontcache/vefontcache.odin index ddd84de..a4b5df9 100644 --- a/vefontcache/vefontcache.odin +++ b/vefontcache/vefontcache.odin @@ -7,15 +7,15 @@ package vefontcache import "base:runtime" -Advance_Snap_Smallfont_Size :: 0 +ADVANCE_SNAP_SMALLFONT_SIZE :: 0 -FontID :: distinct i64 +Font_ID :: distinct i64 Glyph :: distinct i32 Entry :: struct { - parser_info : ParserFontInfo, - shaper_info : ShaperInfo, - id : FontID, + parser_info : Parser_Font_Info, + shaper_info : Shaper_Info, + id : Font_ID, used : b32, curve_quality : f32, size : f32, @@ -32,8 +32,8 @@ Entry_Default :: Entry { Context :: struct { backing : Allocator, - parser_ctx : ParserContext, - shaper_ctx : ShaperContext, + parser_ctx : Parser_Context, + shaper_ctx : Shaper_Context, entries : [dynamic]Entry, @@ -54,10 +54,10 @@ Context :: struct { calls_offset : int, }, - draw_list : DrawList, + draw_list : Draw_List, atlas : Atlas, - glyph_buffer : GlyphDrawBuffer, - shape_cache : ShapedTextCache, + glyph_buffer : Glyph_Draw_Buffer, + shape_cache : Shaped_Text_Cache, default_curve_quality : i32, text_shape_adv : b32, @@ -69,23 +69,23 @@ Context :: struct { //#region("lifetime") -InitAtlasRegionParams :: struct { +Init_Atlas_Region_Params :: struct { width : u32, height : u32, } -InitAtlasParams :: struct { - width : u32, - height : u32, - glyph_padding : u32, +Init_Atlas_Params :: struct { + width : u32, + height : u32, + glyph_padding : u32, - region_a : InitAtlasRegionParams, - region_b : InitAtlasRegionParams, - region_c : InitAtlasRegionParams, - region_d : InitAtlasRegionParams, + region_a : Init_Atlas_Region_Params, + region_b : Init_Atlas_Region_Params, + region_c : Init_Atlas_Region_Params, + region_d : Init_Atlas_Region_Params, } -InitAtlasParams_Default :: InitAtlasParams { +Init_Atlas_Params_Default :: Init_Atlas_Params { width = 4096, height = 2048, glyph_padding = 4, @@ -108,34 +108,34 @@ InitAtlasParams_Default :: InitAtlasParams { } } -InitGlyphDrawParams :: struct { - over_sample : Vec2i, - buffer_batch : u32, - draw_padding : u32, +Init_Glyph_Draw_Params :: struct { + over_sample : Vec2i, + buffer_batch : u32, + draw_padding : u32, } -InitGlyphDrawParams_Default :: InitGlyphDrawParams { +Init_Glyph_Draw_Params_Default :: Init_Glyph_Draw_Params { over_sample = { 8, 8 }, buffer_batch = 4, - draw_padding = InitAtlasParams_Default.glyph_padding, + draw_padding = Init_Atlas_Params_Default.glyph_padding, } -InitShapeCacheParams :: struct { +Init_Shape_Cache_Params :: struct { capacity : u32, reserve_length : u32, } -InitShapeCacheParams_Default :: InitShapeCacheParams { - capacity = 8 * 1024, - reserve_length = 256, +Init_Shape_Cache_Params_Default :: Init_Shape_Cache_Params { + capacity = 8 * 1024, + reserve_length = 256, } // ve_fontcache_init -startup :: proc( ctx : ^Context, parser_kind : ParserKind, +startup :: proc( ctx : ^Context, parser_kind : Parser_Kind = .STB_TrueType, allocator := context.allocator, - atlas_params := InitAtlasParams_Default, - glyph_draw_params := InitGlyphDrawParams_Default, - shape_cache_params := InitShapeCacheParams_Default, + 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, default_curve_quality : u32 = 3, @@ -158,7 +158,7 @@ startup :: proc( ctx : ^Context, parser_kind : ParserKind, } ctx.default_curve_quality = default_curve_quality - error : AllocatorError + error : Allocator_Error entries, error = make( [dynamic]Entry, len = 0, cap = entires_reserve ) assert(error == .None, "VEFontCache.init : Failed to allocate entries") @@ -174,10 +174,10 @@ startup :: proc( ctx : ^Context, parser_kind : ParserKind, draw_list.indices, error = make( [dynamic]u32, len = 0, cap = 8 * Kilobyte ) assert(error == .None, "VEFontCache.init : Failed to allocate draw_list.indices") - draw_list.calls, error = make( [dynamic]DrawCall, len = 0, cap = 512 ) + draw_list.calls, error = make( [dynamic]Draw_Call, len = 0, cap = 512 ) assert(error == .None, "VEFontCache.init : Failed to allocate draw_list.calls") - init_atlas_region :: proc( region : ^AtlasRegion, params : InitAtlasParams, region_params : InitAtlasRegionParams, factor : Vec2i, expected_cap : i32 ) + init_atlas_region :: proc( region : ^Atlas_Region, params : Init_Atlas_Params, region_params : Init_Atlas_Region_Params, factor : Vec2i, expected_cap : i32 ) { using region @@ -194,8 +194,8 @@ startup :: proc( ctx : ^Context, parser_kind : ParserKind, } assert( capacity.x * capacity.y == expected_cap ) - error : AllocatorError - LRU_init( & state, capacity.x * capacity.y ) + error : Allocator_Error + lru_init( & state, capacity.x * capacity.y ) } init_atlas_region( & atlas.region_a, atlas_params, atlas_params.region_a, { 4, 2}, 1024 ) init_atlas_region( & atlas.region_b, atlas_params, atlas_params.region_b, { 4, 2}, 512 ) @@ -214,9 +214,9 @@ startup :: proc( ctx : ^Context, parser_kind : ParserKind, atlas.region_d.offset.x = atlas.width / 2 atlas.region_d.offset.y = 0 - LRU_init( & shape_cache.state, i32(shape_cache_params.capacity) ) + lru_init( & shape_cache.state, i32(shape_cache_params.capacity) ) - shape_cache.storage, error = make( [dynamic]ShapedText, shape_cache_params.capacity ) + shape_cache.storage, error = make( [dynamic]Shaped_Text, shape_cache_params.capacity ) assert(error == .None, "VEFontCache.init : Failed to allocate shape_cache.storage") for idx : u32 = 0; idx < shape_cache_params.capacity; idx += 1 { @@ -228,7 +228,7 @@ startup :: proc( ctx : ^Context, parser_kind : ParserKind, positions, error = make( [dynamic]Vec2, len = 0, cap = shape_cache_params.reserve_length ) assert( error == .None, "VEFontCache.init : Failed to allocate positions array for shape cache storage" ) - draw_list.calls, error = make( [dynamic]DrawCall, len = 0, cap = glyph_draw_params.buffer_batch * 2 ) + draw_list.calls, error = make( [dynamic]Draw_Call, len = 0, cap = glyph_draw_params.buffer_batch * 2 ) assert( error == .None, "VEFontCache.init : Failed to allocate calls for draw_list" ) draw_list.indices, error = make( [dynamic]u32, len = 0, cap = glyph_draw_params.buffer_batch * 2 * 6 ) @@ -247,7 +247,7 @@ startup :: proc( ctx : ^Context, parser_kind : ParserKind, height = atlas.region_d.height * i32(over_sample.y) draw_padding = cast(i32) glyph_draw_params.draw_padding - draw_list.calls, error = make( [dynamic]DrawCall, len = 0, cap = glyph_draw_params.buffer_batch * 2 ) + draw_list.calls, error = make( [dynamic]Draw_Call, len = 0, cap = glyph_draw_params.buffer_batch * 2 ) assert( error == .None, "VEFontCache.init : Failed to allocate calls for draw_list" ) draw_list.indices, error = make( [dynamic]u32, len = 0, cap = glyph_draw_params.buffer_batch * 2 * 6 ) @@ -256,7 +256,7 @@ startup :: proc( ctx : ^Context, parser_kind : ParserKind, draw_list.vertices, error = make( [dynamic]Vertex, len = 0, cap = glyph_draw_params.buffer_batch * 2 * 4 ) assert( error == .None, "VEFontCache.init : Failed to allocate vertices array for draw_list" ) - clear_draw_list.calls, error = make( [dynamic]DrawCall, len = 0, cap = glyph_draw_params.buffer_batch * 2 ) + clear_draw_list.calls, error = make( [dynamic]Draw_Call, len = 0, cap = glyph_draw_params.buffer_batch * 2 ) assert( error == .None, "VEFontCache.init : Failed to allocate calls for calls for clear_draw_list" ) clear_draw_list.indices, error = make( [dynamic]u32, len = 0, cap = glyph_draw_params.buffer_batch * 2 * 4 ) @@ -285,12 +285,12 @@ hot_reload :: proc( ctx : ^Context, allocator : Allocator ) reload_array( & draw_list.indices, allocator ) reload_array( & draw_list.calls, allocator ) - LRU_reload( & atlas.region_a.state, allocator) - LRU_reload( & atlas.region_b.state, allocator) - LRU_reload( & atlas.region_c.state, allocator) - LRU_reload( & atlas.region_d.state, allocator) + lru_reload( & atlas.region_a.state, allocator) + lru_reload( & atlas.region_b.state, allocator) + lru_reload( & atlas.region_c.state, allocator) + lru_reload( & atlas.region_d.state, allocator) - LRU_reload( & shape_cache.state, allocator ) + lru_reload( & shape_cache.state, allocator ) for idx : i32 = 0; idx < i32(len(shape_cache.storage)); idx += 1 { stroage_entry := & shape_cache.storage[idx] using stroage_entry @@ -308,7 +308,7 @@ 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 ) + lru_reload( & shape_cache.state, allocator ) } // ve_foncache_shutdown @@ -330,10 +330,10 @@ shutdown :: proc( ctx : ^Context ) delete( draw_list.indices ) delete( draw_list.calls ) - LRU_free( & atlas.region_a.state ) - LRU_free( & atlas.region_b.state ) - LRU_free( & atlas.region_c.state ) - LRU_free( & atlas.region_d.state ) + lru_free( & atlas.region_a.state ) + lru_free( & atlas.region_b.state ) + lru_free( & atlas.region_c.state ) + lru_free( & atlas.region_d.state ) for idx : i32 = 0; idx < i32(len(shape_cache.storage)); idx += 1 { stroage_entry := & shape_cache.storage[idx] @@ -342,7 +342,7 @@ shutdown :: proc( ctx : ^Context ) delete( glyphs ) delete( positions ) } - LRU_free( & shape_cache.state ) + lru_free( & shape_cache.state ) delete( glyph_buffer.draw_list.vertices ) delete( glyph_buffer.draw_list.indices ) @@ -357,7 +357,7 @@ shutdown :: proc( ctx : ^Context ) } // ve_fontcache_load -load_font :: proc( ctx : ^Context, label : string, data : []byte, size_px : f32, glyph_curve_quality : u32 = 0 ) -> (font_id : FontID) +load_font :: proc( ctx : ^Context, label : string, data : []byte, size_px : f32, glyph_curve_quality : u32 = 0 ) -> (font_id : Font_ID) { assert( ctx != nil ) assert( len(data) > 0 ) @@ -386,9 +386,9 @@ load_font :: proc( ctx : ^Context, label : string, data : []byte, size_px : f32, shaper_info = shaper_load_font( & shaper_ctx, label, data, transmute(rawptr) id ) size = size_px - size_scale = size_px < 0.0 ? \ + 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 ) + : parser_scale_for_mapping_em_to_pixels( & parser_info, size_px ) if glyph_curve_quality == 0 { curve_quality = f32(ctx.default_curve_quality) @@ -397,15 +397,15 @@ load_font :: proc( ctx : ^Context, label : string, data : []byte, size_px : f32, curve_quality = f32(glyph_curve_quality) } } - entry.id = FontID(id) - ctx.entries[ id ].id = FontID(id) + entry.id = Font_ID(id) + ctx.entries[ id ].id = Font_ID(id) - font_id = FontID(id) + font_id = Font_ID(id) return } // ve_fontcache_unload -unload_font :: proc( ctx : ^Context, font : FontID ) +unload_font :: proc( ctx : ^Context, font : Font_ID ) { assert( ctx != nil ) assert( font >= 0 && int(font) < len(ctx.entries) ) @@ -430,10 +430,10 @@ configure_snap :: #force_inline proc( ctx : ^Context, snap_width, snap_height : ctx.snap_height = f32(snap_height) } -get_cursor_pos :: #force_inline proc "contextless" ( ctx : ^Context ) -> Vec2 { return ctx.cursor_pos } -set_colour :: #force_inline proc "contextless" ( ctx : ^Context, colour : Colour ) { ctx.colour = colour } +get_cursor_pos :: #force_inline proc( ctx : ^Context ) -> Vec2 { assert(ctx != nil); return ctx.cursor_pos } +set_colour :: #force_inline proc( ctx : ^Context, colour : Colour ) { assert(ctx != nil); ctx.colour = colour } -draw_text :: proc( ctx : ^Context, font : FontID, text_utf8 : string, position, scale : Vec2 ) -> b32 +draw_text :: proc( ctx : ^Context, font : Font_ID, text_utf8 : string, position, scale : Vec2 ) -> b32 { // profile(#procedure) assert( ctx != nil ) @@ -463,14 +463,14 @@ draw_text :: proc( ctx : ^Context, font : FontID, text_utf8 : string, position, return true } -// ve_fontcache_drawlist -get_draw_list :: proc( ctx : ^Context, optimize_before_returning := true ) -> ^DrawList { +// ve_fontcache_Draw_List +get_draw_list :: proc( ctx : ^Context, optimize_before_returning := true ) -> ^Draw_List { assert( ctx != nil ) if optimize_before_returning do optimize_draw_list( & ctx.draw_list, 0 ) return & ctx.draw_list } -get_draw_list_layer :: proc( ctx : ^Context, optimize_before_returning := true ) -> (vertices : []Vertex, indices : []u32, calls : []DrawCall) { +get_draw_list_layer :: proc( ctx : ^Context, optimize_before_returning := true ) -> (vertices : []Vertex, indices : []u32, calls : []Draw_Call) { assert( ctx != nil ) if optimize_before_returning do optimize_draw_list( & ctx.draw_list, ctx.draw_layer.calls_offset ) vertices = ctx.draw_list.vertices[ ctx.draw_layer.vertices_offset : ] @@ -479,7 +479,7 @@ get_draw_list_layer :: proc( ctx : ^Context, optimize_before_returning := true ) return } -// ve_fontcache_flush_drawlist +// ve_fontcache_flush_Draw_List flush_draw_list :: proc( ctx : ^Context ) { assert( ctx != nil ) using ctx @@ -501,7 +501,7 @@ flush_draw_list_layer :: proc( ctx : ^Context ) { //#region("metrics") -measure_text_size :: proc( ctx : ^Context, font : FontID, text_utf8 : string ) -> (measured : Vec2) +measure_text_size :: proc( ctx : ^Context, font : Font_ID, text_utf8 : string ) -> (measured : Vec2) { // profile(#procedure) assert( ctx != nil ) @@ -512,7 +512,7 @@ measure_text_size :: proc( ctx : ^Context, font : FontID, text_utf8 : string ) - return shaped.size } -get_font_vertical_metrics :: #force_inline proc ( ctx : ^Context, font : FontID ) -> ( ascent, descent, line_gap : f32 ) +get_font_vertical_metrics :: #force_inline proc ( ctx : ^Context, font : Font_ID ) -> ( ascent, descent, line_gap : f32 ) { assert( ctx != nil ) assert( font >= 0 && int(font) < len(ctx.entries) )