last cleanup for this dev pass

This commit is contained in:
2024-07-02 10:34:36 -04:00
parent 0f4ad9bdd1
commit a930fc00d4
7 changed files with 24 additions and 60 deletions

View File

@@ -25,28 +25,19 @@ Note: freetype and harfbuzz could technically be gutted if the user removes thei
## TODOs ## TODOs
### Documentation:
* Pureref outline of draw_text exectuion
* Markdown general documentation
### Content:
* Port over the original demo utilizing sokol libraries instead
### Additional Features: ### Additional Features:
* Support for freetype (WIP, Currently a mess... and slow) * 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). * 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 * Ability to set a draw transform, viewport and projection
* By default the library's position is in unsigned normalized render space * By default the library's position is in unsigned normalized render space
* Could implement a similar design to sokol_gp's interface * Could implement a similar design to sokol_gp's interface
### Optimization: ### 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 * 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. * 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 * Context would need to be segregated into staged data structures for each thread to utilize
* Each should have their own? * Each should have their own?

View File

@@ -62,7 +62,7 @@ FontDef :: struct {
size_table : [FONT_LARGEST_PIXEL_SIZE / FONT_SIZE_INTERVAL] ve.FontID, size_table : [FONT_LARGEST_PIXEL_SIZE / FONT_SIZE_INTERVAL] ve.FontID,
} }
Demo_Context :: struct { DemoContext :: struct {
ve_ctx : ve.Context, ve_ctx : ve.Context,
render_ctx : ve_sokol.Context, render_ctx : ve_sokol.Context,
font_ids : map[string]FontDef, font_ids : map[string]FontDef,
@@ -93,7 +93,7 @@ Demo_Context :: struct {
screen_size : [2]f32, screen_size : [2]f32,
} }
demo_ctx : Demo_Context demo_ctx : DemoContext
font_load :: proc(path_file : string, font_load :: proc(path_file : string,
default_size : i32 = FONT_LOAD_USE_DEFAULT_SIZE, default_size : i32 = FONT_LOAD_USE_DEFAULT_SIZE,

View File

@@ -86,8 +86,7 @@ atlas_bbox :: proc( atlas : ^Atlas, region : AtlasRegionKind, local_idx : i32 )
return return
} }
decide_codepoint_region :: proc(ctx : ^Context, entry : ^Entry, glyph_index : Glyph decide_codepoint_region :: proc(ctx : ^Context, entry : ^Entry, glyph_index : Glyph ) -> (region_kind : AtlasRegionKind, region : ^AtlasRegion, over_sample : Vec2)
) -> (region_kind : AtlasRegionKind, region : ^AtlasRegion, over_sample : Vec2)
{ {
if parser_is_glyph_empty(&entry.parser_info, glyph_index) { if parser_is_glyph_empty(&entry.parser_info, glyph_index) {
return .None, nil, {} return .None, nil, {}

View File

@@ -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... // 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: 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, draw_filled_path_freetype :: proc( draw_list : ^DrawList, outside_point : Vec2, path : []Vertex,
scale := Vec2 { 1, 1 }, scale := Vec2 { 1, 1 },
translate := Vec2 { 0, 0 }, translate := Vec2 { 0, 0 },
@@ -244,6 +243,7 @@ cache_glyph_freetype :: proc(ctx: ^Context, font: FontID, glyph_index: Glyph, en
return true 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 cache_glyph :: proc(ctx : ^Context, font : FontID, glyph_index : Glyph, entry : ^Entry, bounds_0, bounds_1 : Vec2, scale, translate : Vec2) -> b32
{ {
// profile(#procedure) // profile(#procedure)

View File

@@ -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 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 // 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 ) { log :: proc( msg : string, level := core_log.Level.Info, loc := #caller_location ) {
temp_arena : Arena; arena_init(& temp_arena, Logger_Allocator_Buffer[:]) // temp_arena : Arena; arena_init(& temp_arena, Logger_Allocator_Buffer[:])
context.allocator = arena_allocator(& temp_arena) // context.allocator = arena_allocator(& temp_arena)
context.temp_allocator = arena_allocator(& temp_arena) // context.temp_allocator = arena_allocator(& temp_arena)
core_log.log( level, msg, location = loc ) core_log.log( level, msg, location = loc )
} }
logf :: proc( fmt : string, args : ..any, level := core_log.Level.Info, loc := #caller_location ) { logf :: proc( fmt : string, args : ..any, level := core_log.Level.Info, loc := #caller_location ) {
temp_arena : Arena; arena_init(& temp_arena, Logger_Allocator_Buffer[:]) // temp_arena : Arena; arena_init(& temp_arena, Logger_Allocator_Buffer[:])
context.allocator = arena_allocator(& temp_arena) // context.allocator = arena_allocator(& temp_arena)
context.temp_allocator = arena_allocator(& temp_arena) // context.temp_allocator = arena_allocator(& temp_arena)
core_log.logf( level, fmt, ..args, location = loc ) core_log.logf( level, fmt, ..args, location = loc )
} }
@@ -130,10 +130,10 @@ when ! Use_SIMD_For_Bezier_Ops
// ve_fontcache_eval_bezier (quadratic) // ve_fontcache_eval_bezier (quadratic)
eval_point_on_bezier3 :: #force_inline proc "contextless" ( p0, p1, p2 : Vec2, alpha : f32 ) -> Vec2 eval_point_on_bezier3 :: #force_inline proc "contextless" ( p0, p1, p2 : Vec2, alpha : f32 ) -> Vec2
{ {
p0 := vec2_64(p0) // p0 := vec2_64(p0)
p1 := vec2_64(p1) // p1 := vec2_64(p1)
p2 := vec2_64(p2) // p2 := vec2_64(p2)
alpha := f64(alpha) // alpha := f64(alpha)
weight_start := (1 - alpha) * (1 - alpha) weight_start := (1 - alpha) * (1 - alpha)
weight_control := 2.0 * (1 - alpha) * alpha weight_control := 2.0 * (1 - alpha) * alpha
@@ -152,11 +152,11 @@ when ! Use_SIMD_For_Bezier_Ops
// ve_fontcache_eval_bezier (cubic) // ve_fontcache_eval_bezier (cubic)
eval_point_on_bezier4 :: #force_inline proc "contextless" ( p0, p1, p2, p3 : Vec2, alpha : f32 ) -> Vec2 eval_point_on_bezier4 :: #force_inline proc "contextless" ( p0, p1, p2, p3 : Vec2, alpha : f32 ) -> Vec2
{ {
p0 := vec2_64(p0) // p0 := vec2_64(p0)
p1 := vec2_64(p1) // p1 := vec2_64(p1)
p2 := vec2_64(p2) // p2 := vec2_64(p2)
p3 := vec2_64(p3) // p3 := vec2_64(p3)
alpha := f64(alpha) // alpha := f64(alpha)
weight_start := (1 - alpha) * (1 - alpha) * (1 - alpha) weight_start := (1 - alpha) * (1 - alpha) * (1 - alpha)
weight_c_a := 3 * (1 - alpha) * (1 - alpha) * alpha weight_c_a := 3 * (1 - alpha) * (1 - alpha) * alpha

View File

@@ -53,8 +53,6 @@ ParserGlyphShape :: [dynamic]ParserGlyphVertex
ParserContext :: struct { ParserContext :: struct {
kind : ParserKind, kind : ParserKind,
ft_library : freetype.Library, ft_library : freetype.Library,
// fonts : HMapChained(ParserFontInfo),
} }
parser_init :: proc( ctx : ^ParserContext, kind : ParserKind ) parser_init :: proc( ctx : ^ParserContext, kind : ParserKind )
@@ -70,10 +68,6 @@ parser_init :: proc( ctx : ^ParserContext, kind : ParserKind )
} }
ctx.kind = kind 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 ) { 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) 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 switch ctx.kind
{ {
case .Freetype: 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) 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 switch font.kind
{ {
case .Freetype: 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: case .STB_TrueType:
stb_shape : [^]stbtt.vertex stb_shape : [^]stbtt.vertex

View File

@@ -76,9 +76,7 @@ shape_text_uncached :: proc( ctx : ^Context, font : FontID, text_utf8 : string,
if ctx.text_shape_adv 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 ) 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 return
} }
else else