diff --git a/Readme.md b/Readme.md index fa70c01..b959d44 100644 --- a/Readme.md +++ b/Readme.md @@ -25,28 +25,19 @@ Note: freetype and harfbuzz could technically be gutted if the user removes thei ## TODOs -### Documentation: - -* Pureref outline of draw_text exectuion -* Markdown general documentation - -### Content: - -* Port over the original demo utilizing sokol libraries instead - ### Additional Features: * Support for freetype (WIP, Currently a mess... and slow) * Add ability to conditionally compile dependencies (so that the user may not need to resolve those packages). - * Related to usage of //+build tags? * Ability to set a draw transform, viewport and projection * By default the library's position is in unsigned normalized render space * Could implement a similar design to sokol_gp's interface ### Optimization: +* Check if its better to store the generated glyph vertices if they need to be re-cached or directly drawn. * Look into setting up multi-threading by giving each thread a context - * There is a heavy performance bottleneck in iterating the text/shape/glyphs on the cpu (single-thread) vs the actual rendering + * There is a heavy performance bottleneck in iterating the text/shape/glyphs on the cpu (single-thread) vs the actual rendering *(if doing thousands of drawing commands)* * draw_text can provide in the context a job list per thread for the user to thenk hookup to their own threading solution to handle. * Context would need to be segregated into staged data structures for each thread to utilize * Each should have their own? diff --git a/examples/sokol_demo/sokol_demo.odin b/examples/sokol_demo/sokol_demo.odin index da47211..63fee47 100644 --- a/examples/sokol_demo/sokol_demo.odin +++ b/examples/sokol_demo/sokol_demo.odin @@ -62,7 +62,7 @@ FontDef :: struct { size_table : [FONT_LARGEST_PIXEL_SIZE / FONT_SIZE_INTERVAL] ve.FontID, } -Demo_Context :: struct { +DemoContext :: struct { ve_ctx : ve.Context, render_ctx : ve_sokol.Context, font_ids : map[string]FontDef, @@ -93,7 +93,7 @@ Demo_Context :: struct { screen_size : [2]f32, } -demo_ctx : Demo_Context +demo_ctx : DemoContext font_load :: proc(path_file : string, default_size : i32 = FONT_LOAD_USE_DEFAULT_SIZE, diff --git a/vefontcache/atlas.odin b/vefontcache/atlas.odin index 8b7b0c5..47876b0 100644 --- a/vefontcache/atlas.odin +++ b/vefontcache/atlas.odin @@ -86,8 +86,7 @@ atlas_bbox :: proc( atlas : ^Atlas, region : AtlasRegionKind, local_idx : i32 ) 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 : AtlasRegionKind, region : ^AtlasRegion, over_sample : Vec2) { if parser_is_glyph_empty(&entry.parser_info, glyph_index) { return .None, nil, {} diff --git a/vefontcache/draw.odin b/vefontcache/draw.odin index 0641a6b..5fcd883 100644 --- a/vefontcache/draw.odin +++ b/vefontcache/draw.odin @@ -91,7 +91,6 @@ 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 { - draw_filled_path_freetype :: proc( draw_list : ^DrawList, outside_point : Vec2, path : []Vertex, scale := Vec2 { 1, 1 }, translate := Vec2 { 0, 0 }, @@ -244,6 +243,7 @@ cache_glyph_freetype :: proc(ctx: ^Context, font: FontID, glyph_index: Glyph, en return true } +// 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 { // profile(#procedure) diff --git a/vefontcache/misc.odin b/vefontcache/misc.odin index f0b7393..0b1e860 100644 --- a/vefontcache/misc.odin +++ b/vefontcache/misc.odin @@ -21,20 +21,20 @@ vec2i_from_vec2 :: #force_inline proc "contextless" ( v2 : Vec2 ) -> Vec2 // This buffer is used below excluisvely to prevent any allocator recusion when verbose logging from allocators. // This means a single line is limited to 4k buffer -Logger_Allocator_Buffer : [4 * Kilobyte]u8 +// Logger_Allocator_Buffer : [4 * Kilobyte]u8 log :: proc( msg : string, level := core_log.Level.Info, loc := #caller_location ) { - temp_arena : Arena; arena_init(& temp_arena, Logger_Allocator_Buffer[:]) - context.allocator = arena_allocator(& temp_arena) - context.temp_allocator = arena_allocator(& temp_arena) + // temp_arena : Arena; arena_init(& temp_arena, Logger_Allocator_Buffer[:]) + // context.allocator = arena_allocator(& temp_arena) + // context.temp_allocator = arena_allocator(& temp_arena) core_log.log( level, msg, location = loc ) } logf :: proc( fmt : string, args : ..any, level := core_log.Level.Info, loc := #caller_location ) { - temp_arena : Arena; arena_init(& temp_arena, Logger_Allocator_Buffer[:]) - context.allocator = arena_allocator(& temp_arena) - context.temp_allocator = arena_allocator(& temp_arena) + // temp_arena : Arena; arena_init(& temp_arena, Logger_Allocator_Buffer[:]) + // context.allocator = arena_allocator(& temp_arena) + // context.temp_allocator = arena_allocator(& temp_arena) core_log.logf( level, fmt, ..args, location = loc ) } @@ -130,10 +130,10 @@ when ! Use_SIMD_For_Bezier_Ops // ve_fontcache_eval_bezier (quadratic) eval_point_on_bezier3 :: #force_inline proc "contextless" ( p0, p1, p2 : Vec2, alpha : f32 ) -> Vec2 { - p0 := vec2_64(p0) - p1 := vec2_64(p1) - p2 := vec2_64(p2) - alpha := f64(alpha) + // p0 := vec2_64(p0) + // p1 := vec2_64(p1) + // p2 := vec2_64(p2) + // alpha := f64(alpha) weight_start := (1 - alpha) * (1 - alpha) weight_control := 2.0 * (1 - alpha) * alpha @@ -152,11 +152,11 @@ when ! Use_SIMD_For_Bezier_Ops // ve_fontcache_eval_bezier (cubic) eval_point_on_bezier4 :: #force_inline proc "contextless" ( p0, p1, p2, p3 : Vec2, alpha : f32 ) -> Vec2 { - p0 := vec2_64(p0) - p1 := vec2_64(p1) - p2 := vec2_64(p2) - p3 := vec2_64(p3) - alpha := f64(alpha) + // p0 := vec2_64(p0) + // p1 := vec2_64(p1) + // p2 := vec2_64(p2) + // p3 := vec2_64(p3) + // alpha := f64(alpha) weight_start := (1 - alpha) * (1 - alpha) * (1 - alpha) weight_c_a := 3 * (1 - alpha) * (1 - alpha) * alpha diff --git a/vefontcache/parser.odin b/vefontcache/parser.odin index 26e5966..1eef70d 100644 --- a/vefontcache/parser.odin +++ b/vefontcache/parser.odin @@ -53,8 +53,6 @@ ParserGlyphShape :: [dynamic]ParserGlyphVertex ParserContext :: struct { kind : ParserKind, ft_library : freetype.Library, - - // fonts : HMapChained(ParserFontInfo), } parser_init :: proc( ctx : ^ParserContext, kind : ParserKind ) @@ -70,10 +68,6 @@ parser_init :: proc( ctx : ^ParserContext, kind : ParserKind ) } ctx.kind = kind - - // error : AllocatorError - // ctx.fonts, error = make( HMapChained(ParserFontInfo), 256 ) - // assert( error == .None, "VEFontCache.parser_init: Failed to allocate fonts array" ) } parser_shutdown :: proc( ctx : ^ParserContext ) { @@ -82,13 +76,6 @@ parser_shutdown :: proc( ctx : ^ParserContext ) { parser_load_font :: proc( ctx : ^ParserContext, label : string, data : []byte ) -> (font : ParserFontInfo) { - // key := font_key_from_label(label) - // font = get( ctx.fonts, key ) - // if font != nil do return - - // error : AllocatorError - // font, error = set( ctx.fonts, key, ParserFontInfo {} ) - // assert( error == .None, "VEFontCache.parser_load_font: Failed to set a new parser font info" ) switch ctx.kind { case .Freetype: @@ -230,22 +217,11 @@ parser_get_glyph_box :: #force_inline proc ( font : ^ParserFontInfo, glyph_index parser_get_glyph_shape :: proc( font : ^ParserFontInfo, glyph_index : Glyph ) -> (shape : ParserGlyphShape, error : AllocatorError) { - quad_to_cubic :: proc(p0, p1, p2: freetype.Vector) -> (c1, c2: freetype.Vector) { - c1 = freetype.Vector{ - x = p0.x + ((p1.x - p0.x) * 2 + 1) / 3, - y = p0.y + ((p1.y - p0.y) * 2 + 1) / 3, - } - c2 = freetype.Vector{ - x = p2.x + ((p1.x - p2.x) * 2 + 1) / 3, - y = p2.y + ((p1.y - p2.y) * 2 + 1) / 3, - } - return - } - switch font.kind { case .Freetype: - // TODO(Ed): Don't do this we're going a completely different route for handling shapes + // TODO(Ed): Don't do this, going a completely different route for handling shapes. + // This abstraction fails to be time-saving or performant. case .STB_TrueType: stb_shape : [^]stbtt.vertex diff --git a/vefontcache/shaped_text.odin b/vefontcache/shaped_text.odin index b891757..5e7e9bd 100644 --- a/vefontcache/shaped_text.odin +++ b/vefontcache/shaped_text.odin @@ -76,9 +76,7 @@ shape_text_uncached :: proc( ctx : ^Context, font : FontID, text_utf8 : string, if ctx.text_shape_adv { - // assert( entry.shaper_info != nil ) 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 ) - // TODO(Ed): Need to be able to provide the text height as well return } else