mirror of
https://github.com/Ed94/VEFontCache-Odin.git
synced 2025-08-05 14:42:42 -07:00
More cleanup, doc updates
This commit is contained in:
@@ -43,11 +43,11 @@ pool_list_init :: proc( pool : ^Pool_List($V_Type), capacity : i32, dbg_name : s
|
||||
{
|
||||
error : Allocator_Error
|
||||
pool.items, error = make( [dynamic]Pool_List_Item(V_Type), int(capacity) )
|
||||
assert( error == .None, "VEFontCache.pool_list_init : Failed to allocate items array")
|
||||
assert( error == .None, "VEFontCache.pool_list_inits: Failed to allocate items array")
|
||||
resize( & pool.items, 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")
|
||||
assert( error == .None, "VEFontCache.pool_list_init: Failed to allocate free_list array")
|
||||
resize( & pool.free_list, capacity )
|
||||
|
||||
pool.capacity = capacity
|
||||
@@ -106,16 +106,16 @@ pool_list_push_front :: proc( pool : ^Pool_List($V_Type), value : V_Type ) #no_b
|
||||
assert( length == int(pool.capacity - pool.size) )
|
||||
|
||||
id := pool.free_list[ len(pool.free_list) - 1 ]
|
||||
if pool.dbg_name != "" {
|
||||
logf("pool_list: back %v", id)
|
||||
}
|
||||
// if pool.dbg_name != "" {
|
||||
// logf("pool_list: back %v", id)
|
||||
// }
|
||||
pop( & pool.free_list )
|
||||
pool.items[ id ].prev = -1
|
||||
pool.items[ id ].next = pool.front
|
||||
pool.items[ id ].value = value
|
||||
if pool.dbg_name != "" {
|
||||
logf("pool_list: pushed %v into id %v", value, id)
|
||||
}
|
||||
// if pool.dbg_name != "" {
|
||||
// logf("pool_list: pushed %v into id %v", value, id)
|
||||
// }
|
||||
|
||||
if pool.front != -1 do pool.items[ pool.front ].prev = id
|
||||
if pool.back == -1 do pool.back = id
|
||||
|
@@ -109,7 +109,7 @@ Glyph_Draw_Buffer :: struct{
|
||||
cached : [dynamic]i32,
|
||||
}
|
||||
|
||||
// Contructs a quad mesh for bliting a texture from one render target (src uv0 & 1) to the destination rendertarget (p0, p1)
|
||||
// Contructs a quad mesh for bliting a texture from source render target (src uv0 & 1) to the destination render target (p0, p1)
|
||||
@(optimization_mode="favor_size")
|
||||
blit_quad :: #force_inline proc ( draw_list : ^Draw_List,
|
||||
p0 : Vec2 = {0, 0},
|
||||
@@ -279,24 +279,15 @@ generate_shapes_draw_list :: #force_inline proc ( ctx : ^Context,
|
||||
}
|
||||
|
||||
/* Generator pipeline for shapes
|
||||
|
||||
If you'd like to make a custom draw procedure, this can either be used directly or
|
||||
modified to create an augmented derivative for a specific code path.
|
||||
|
||||
This procedure has no awareness of layers. That should be handled by a higher-order codepath.
|
||||
For this level of codepaths what matters is maximizing memory locality for:
|
||||
* Dealing with shaping (essentially minimizing having to ever deal with it in a hot path if possible)
|
||||
* Dealing with atlas regioning (the expensive region resolution & parser calls are done on the shape pass)
|
||||
|
||||
Pipleine order:
|
||||
* Resolve the glyph's position offset from the target position
|
||||
* Segregate the glyphs into three slices: oversized, to_cache, cached.
|
||||
* If oversized is not necessary for your use case and your hitting a bottleneck, omit it with setting ENABLE_OVERSIZED_GLYPHS to false.
|
||||
* You have to to be drawing a px font size > ~140 px for it to trigger.
|
||||
* The atlas can be scaled with the size_multiplier parameter of startup so that it becomes more irrelevant if processing a larger atlas is a non-issue.
|
||||
* If oversized is not necessary for your use case and your hitting a bottleneck, omit it with setting ENABLE_OVERSIZED_GLYPHS to false.
|
||||
* The segregation will not allow slices to exceed the batch_cache capacity of the glyph_buffer (configurable within startup params)
|
||||
* When The capacity is reached batch_generate_glyphs_draw_list will be called which will do futher compute and then finally draw_list generation.
|
||||
* This may perform better with smaller shapes vs larger shapes, but having more shapes has a cache lookup penatly so keep that in mind.
|
||||
* When The capacity is reached batch_generate_glyphs_draw_list will be called which will do futher compute and then finally draw_list generation.
|
||||
* This may perform better with smaller shapes vs larger shapes, but having more shapes has a cache lookup penatly (if done per frame) so keep that in mind.
|
||||
*/
|
||||
generate_shape_draw_list :: proc( draw_list : ^Draw_List, shape : Shaped_Text,
|
||||
atlas : ^Atlas,
|
||||
@@ -463,16 +454,16 @@ generate_shape_draw_list :: proc( draw_list : ^Draw_List, shape : Shaped_Text,
|
||||
|
||||
/*
|
||||
The glyphs types have been segregated by this point into a batch slice of indices to the glyph_pack
|
||||
The transform and draw quads are computed first (getting the math done in one spot as possible...)
|
||||
Some of the math from to_cache pass for glyph generation was not moved over (it could be but I'm not sure its worth it...)
|
||||
The transform and draw quads are computed first (getting the math done in one spot as possible)
|
||||
Some of the math from to_cache pass for glyph generation was not moved over (it could be but I'm not sure its worth it)
|
||||
|
||||
Order: Oversized first, then to_cache, then cached.
|
||||
|
||||
Oversized and to_cache will both enqueue operations for rendering glyphs to the glyph buffer render target.
|
||||
The compute section will have operations reguarding how many glyphs they may alloate before a flush must occur.
|
||||
The compute section will have operations regarding how many glyphs they may alloate before a flush must occur.
|
||||
A flush will force one of the following:
|
||||
* Oversized will have a draw call setup to blit directly from the glyph buffer to the target.
|
||||
* to_cache will blit the glyphs rendered to the buffer to the atlas.
|
||||
* to_cache will blit the glyphs rendered from the buffer to the atlas.
|
||||
*/
|
||||
@(optimization_mode = "favor_size")
|
||||
batch_generate_glyphs_draw_list :: proc ( draw_list : ^Draw_List,
|
||||
|
@@ -61,7 +61,7 @@ vec2i_from_vec2 :: #force_inline proc "contextless" ( v2 : Vec2 ) -> Vec2
|
||||
@(require_results) ceil_vec2 :: proc "contextless" ( v : Vec2 ) -> Vec2 { return { ceil_f32(v.x), ceil_f32(v.y) } }
|
||||
@(require_results) floor_vec2 :: proc "contextless" ( v : Vec2 ) -> Vec2 { return { floor_f32(v.x), floor_f32(v.y) } }
|
||||
|
||||
// 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 recursion when verbose logging from allocators.
|
||||
// This means a single line is limited to 4k buffer
|
||||
// Logger_Allocator_Buffer : [4 * Kilobyte]u8
|
||||
|
||||
|
@@ -2,10 +2,10 @@ package vefontcache
|
||||
|
||||
/*
|
||||
Notes:
|
||||
This is a minimal wrapper I originally did incase something than stb_truetype is introduced in the future.
|
||||
This is a minimal wrapper I originally did incase a font parser other than stb_truetype is introduced in the future.
|
||||
Otherwise, its essentially 1:1 with it.
|
||||
|
||||
Freetype isn't really supported and its not a high priority (pretty sure its too slow).
|
||||
Freetype isn't really supported and its not a high priority.
|
||||
~~Freetype will do memory allocations and has an interface the user can implement.~~
|
||||
~~That interface is not exposed from this parser but could be added to parser_init.~~
|
||||
|
||||
@@ -19,7 +19,7 @@ import "base:runtime"
|
||||
import "core:c"
|
||||
import "core:math"
|
||||
import "core:slice"
|
||||
import stbtt "vendor:stb/truetype"
|
||||
import stbtt "thirdparty:stb/truetype"
|
||||
// import freetype "thirdparty:freetype"
|
||||
|
||||
Parser_Kind :: enum u32 {
|
||||
|
@@ -1,6 +1,8 @@
|
||||
package vefontcache
|
||||
/*
|
||||
Note(Ed): The only reason I didn't directly use harfbuzz is because hamza exists and seems to be under active development as an alternative.
|
||||
Note(Ed): The only reason I didn't directly use harfbuzz is:
|
||||
https://github.com/saidwho12/hamza
|
||||
and seems to be under active development as an alternative.
|
||||
*/
|
||||
|
||||
import "core:c"
|
||||
@@ -165,11 +167,11 @@ shaper_shape_harfbuzz :: proc( ctx : ^Shaper_Context, text_utf8 : string, entry
|
||||
|
||||
if hb_glyph.cluster > 0
|
||||
{
|
||||
(max_line_width^) = max( max_line_width^, position.x )
|
||||
position.x = 0.0
|
||||
position.y -= line_height
|
||||
position.y = floor(position.y)
|
||||
(line_count^) += 1
|
||||
(max_line_width^) = max( max_line_width^, position.x )
|
||||
position.x = 0.0
|
||||
position.y -= line_height
|
||||
position.y = floor(position.y)
|
||||
(line_count^) += 1
|
||||
continue
|
||||
}
|
||||
if abs( font_px_size ) <= adv_snap_small_font_threshold
|
||||
@@ -394,8 +396,8 @@ shaper_shape_text_latin :: proc( ctx : ^Shaper_Context,
|
||||
|
||||
// Shapes are tracked by the library's context using the shape cache
|
||||
// and the key is resolved using the font, the desired pixel size, and the text bytes to be shaped.
|
||||
// Thus this procedures cost will be proporitonal to how muh text it has to sift through.
|
||||
// djb8_hash is used as its been pretty good for thousands of hashed lines that around 6-120 charactes long
|
||||
// Thus this procedures cost will be proporitonal to how much text it has to sift through.
|
||||
// djb8_hash is used as its been pretty good for thousands of hashed lines that around 6-250 charactes long
|
||||
// (and its very fast).
|
||||
@(optimization_mode="favor_size")
|
||||
shaper_shape_text_cached :: proc( text_utf8 : string,
|
||||
|
@@ -105,6 +105,8 @@ Context :: struct {
|
||||
px_scalar : f32, // Improves hinting, positioning, etc. Can make zoomed out text too jagged.
|
||||
|
||||
default_curve_quality : i32,
|
||||
|
||||
|
||||
}
|
||||
|
||||
Init_Atlas_Params :: struct {
|
||||
@@ -657,6 +659,15 @@ get_snapped_position :: #force_inline proc "contextless" ( position : Vec2, view
|
||||
return snapped_position
|
||||
}
|
||||
|
||||
resolve_draw_px_size :: #force_inline proc "contextless" ( px_size, default_size, interval, min, max : f32 ) -> (resolved_size : f32)
|
||||
{
|
||||
interval_quotient := 1.0 / f32(interval)
|
||||
size := px_size == 0.0 ? default_size : px_size
|
||||
even_size := math.round(size * interval_quotient) * interval
|
||||
resolved_size = clamp( even_size, min, max )
|
||||
return
|
||||
}
|
||||
|
||||
set_alpha_scalar :: #force_inline proc( ctx : ^Context, scalar : f32 ) { assert(ctx != nil); ctx.alpha_sharpen = scalar }
|
||||
set_colour :: #force_inline proc( ctx : ^Context, colour : RGBAN ) { assert(ctx != nil); ctx.colour = colour }
|
||||
set_px_scalar :: #force_inline proc( ctx : ^Context, scalar : f32 ) { assert(ctx != nil); ctx.px_scalar = scalar }
|
||||
@@ -761,7 +772,7 @@ draw_text_normalized_space :: proc( ctx : ^Context,
|
||||
)
|
||||
}
|
||||
|
||||
// Equivalent to draw_text_shape_normalized_space, however position's units is scaled to view and must be normalized.
|
||||
// Equivalent to draw_text_shape_normalized_space, however position's unit convention is expected to be relative to the view
|
||||
// @(optimization_mode="favor_size")
|
||||
draw_text_shape_view_space :: #force_inline proc( ctx : ^Context,
|
||||
font : Font_ID,
|
||||
@@ -803,7 +814,7 @@ draw_text_shape_view_space :: #force_inline proc( ctx : ^Context,
|
||||
)
|
||||
}
|
||||
|
||||
// Equivalent to draw_text_normalized_space, however position's units is scaled to view and must be normalized.
|
||||
// Equivalent to draw_text_shape_normalized_space, however position's unit convention is expected to be relative to the view
|
||||
// @(optimization_mode = "favor_size")
|
||||
draw_text_view_space :: proc(ctx : ^Context,
|
||||
font : Font_ID,
|
||||
@@ -854,6 +865,7 @@ draw_text_view_space :: proc(ctx : ^Context,
|
||||
)
|
||||
}
|
||||
|
||||
// Uses the ctx.stack, position and scale are relative to the position and scale on the stack.
|
||||
// @(optimization_mode = "favor_size")
|
||||
draw_shape :: proc( ctx : ^Context, position, scale : Vec2, shape : Shaped_Text )
|
||||
{
|
||||
@@ -907,6 +919,7 @@ draw_shape :: proc( ctx : ^Context, position, scale : Vec2, shape : Shaped_Text
|
||||
)
|
||||
}
|
||||
|
||||
// Uses the ctx.stack, position and scale are relative to the position and scale on the stack.
|
||||
// @(optimization_mode = "favor_size")
|
||||
draw_text :: proc( ctx : ^Context, position, scale : Vec2, text_utf8 : string )
|
||||
{
|
||||
@@ -916,11 +929,11 @@ draw_text :: proc( ctx : ^Context, position, scale : Vec2, text_utf8 : string )
|
||||
|
||||
stack := & ctx.stack
|
||||
assert(len(stack.font) > 0)
|
||||
assert(len(stack.view) > 0)
|
||||
assert(len(stack.font_size) > 0)
|
||||
assert(len(stack.colour) > 0)
|
||||
assert(len(stack.view) > 0)
|
||||
assert(len(stack.position) > 0)
|
||||
assert(len(stack.scale) > 0)
|
||||
assert(len(stack.font_size) > 0)
|
||||
assert(len(stack.zoom) > 0)
|
||||
|
||||
font := peek(stack.font)
|
||||
|
Reference in New Issue
Block a user