mirror of
https://github.com/Ed94/VEFontCache-Odin.git
synced 2025-08-06 06:52:44 -07:00
last cleanup for this dev pass
This commit is contained in:
13
Readme.md
13
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?
|
||||
|
@@ -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,
|
||||
|
@@ -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, {}
|
||||
|
@@ -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)
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user