VEFontCache: runtime bugfixes
This commit is contained in:
parent
566a90001b
commit
38be79d7a9
@ -118,7 +118,7 @@ LRU_init :: proc( cache : ^LRU_Cache, capacity : u32 ) {
|
||||
error : AllocatorError
|
||||
cache.capacity = capacity
|
||||
cache.table, error = make( HMapChained(LRU_Link), hmap_closest_prime( 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 )
|
||||
}
|
||||
|
@ -298,14 +298,18 @@ init :: proc( ctx : ^Context,
|
||||
atlas.region_d.offset.x = atlas.width / 2
|
||||
|
||||
LRU_init( & shape_cache.state, shape_cache_params.capacity )
|
||||
|
||||
shape_cache.storage, error = make( Array(ShapedText), u64(shape_cache_params.reserve_length) )
|
||||
assert(error == .None, "VEFontCache.init : Failed to allocate shape_cache.storage")
|
||||
|
||||
for idx : u32 = 0; idx < shape_cache_params.capacity; idx += 1 {
|
||||
stroage_entry := & shape_cache.storage.data[idx]
|
||||
using stroage_entry
|
||||
glyphs, error = make( Array(Glyph), cast(u64) shape_cache_params.reserve_length )
|
||||
assert( error != .None, "VEFontCache.init : Failed to allocate glyphs array for shape cache storage" )
|
||||
assert( error == .None, "VEFontCache.init : Failed to allocate glyphs array for shape cache storage" )
|
||||
|
||||
positions, error = make( Array(Vec2), cast(u64) shape_cache_params.reserve_length )
|
||||
assert( error != .None, "VEFontCache.init : Failed to allocate positions array for shape cache storage" )
|
||||
assert( error == .None, "VEFontCache.init : Failed to allocate positions array for shape cache storage" )
|
||||
}
|
||||
|
||||
// Note(From original author): We can actually go over VE_FONTCACHE_GLYPHDRAW_BUFFER_BATCH batches due to smart packing!
|
||||
@ -318,22 +322,22 @@ init :: proc( ctx : ^Context,
|
||||
draw_padding = glyph_draw_params.draw_padding
|
||||
|
||||
draw_list.calls, error = make( Array(DrawCall), cast(u64) glyph_draw_params.buffer_batch * 2 )
|
||||
assert( error != .None, "VEFontCache.init : Failed to allocate calls for draw_list" )
|
||||
assert( error == .None, "VEFontCache.init : Failed to allocate calls for draw_list" )
|
||||
|
||||
draw_list.indices, error = make( Array(u32), cast(u64) glyph_draw_params.buffer_batch * 2 * 6 )
|
||||
assert( error != .None, "VEFontCache.init : Failed to allocate indices array for draw_list" )
|
||||
assert( error == .None, "VEFontCache.init : Failed to allocate indices array for draw_list" )
|
||||
|
||||
draw_list.vertices, error = make( Array(Vertex), cast(u64) glyph_draw_params.buffer_batch * 2 * 4 )
|
||||
assert( error != .None, "VEFontCache.init : Failed to allocate vertices array for draw_list" )
|
||||
assert( error == .None, "VEFontCache.init : Failed to allocate vertices array for draw_list" )
|
||||
|
||||
clear_draw_list.calls, error = make( Array(DrawCall), cast(u64) glyph_draw_params.buffer_batch * 2 )
|
||||
assert( error != .None, "VEFontCache.init : Failed to allocate calls for calls for clear_draw_list" )
|
||||
assert( error == .None, "VEFontCache.init : Failed to allocate calls for calls for clear_draw_list" )
|
||||
|
||||
clear_draw_list.indices, error = make( Array(u32), cast(u64) glyph_draw_params.buffer_batch * 2 * 4 )
|
||||
assert( error != .None, "VEFontCache.init : Failed to allocate calls for indices array for clear_draw_list" )
|
||||
assert( error == .None, "VEFontCache.init : Failed to allocate calls for indices array for clear_draw_list" )
|
||||
|
||||
clear_draw_list.vertices, error = make( Array(Vertex), cast(u64) glyph_draw_params.buffer_batch * 2 * 4 )
|
||||
assert( error != .None, "VEFontCache.init : Failed to allocate vertices array for clear_draw_list" )
|
||||
assert( error == .None, "VEFontCache.init : Failed to allocate vertices array for clear_draw_list" )
|
||||
}
|
||||
|
||||
parser_init( & parser_ctx )
|
||||
@ -360,6 +364,7 @@ load_font :: proc( ctx : ^Context, label : string, data : []byte, size_px : f32
|
||||
assert( ctx != nil )
|
||||
assert( len(data) > 0 )
|
||||
using ctx
|
||||
context.allocator = backing
|
||||
|
||||
id : i32 = -1
|
||||
for index : i32 = 0; index < i32(entries.num); index += 1 {
|
||||
@ -398,6 +403,7 @@ unload_font :: proc( ctx : ^Context, font : FontID )
|
||||
{
|
||||
assert( ctx != nil )
|
||||
assert( font >= 0 && u64(font) < ctx.entries.num )
|
||||
context.allocator = ctx.backing
|
||||
|
||||
using ctx
|
||||
entry := & entries.data[ font ]
|
||||
@ -642,65 +648,10 @@ cache_glyph_to_atlas :: proc( ctx : ^Context, font : FontID, glyph_index : Glyph
|
||||
append( & atlas.draw_list.calls, call )
|
||||
}
|
||||
|
||||
|
||||
// Render glyph to glyph_update_FBO
|
||||
cache_glyph( ctx, font, glyph_index, glyph_draw_scale, glyph_draw_translate )
|
||||
}
|
||||
|
||||
directly_draw_massive_glyph :: proc( ctx : ^Context, entry : ^Entry, glyph : Glyph, bounds_0 : Vec2i, bounds_width, bounds_height : u32, over_sample, position, scale : Vec2 )
|
||||
{
|
||||
flush_glyph_buffer_to_atlas( ctx )
|
||||
|
||||
// Draw un-antialiased glyph to update FBO.
|
||||
glyph_draw_scale := over_sample * entry.size_scale
|
||||
glyph_draw_translate := - Vec2{ f32(bounds_0.x), f32(bounds_0.y)} * glyph_draw_scale + Vec2{ f32(ctx.atlas.glyph_padding), f32(ctx.atlas.glyph_padding) }
|
||||
screenspace_x_form( & glyph_draw_translate, & glyph_draw_scale, f32(ctx.atlas.buffer_width), f32(ctx.atlas.buffer_height) )
|
||||
|
||||
cache_glyph( ctx, entry.id, glyph, glyph_draw_scale, glyph_draw_translate )
|
||||
|
||||
// Figure out the source rect.
|
||||
glyph_position := Vec2 {}
|
||||
glyph_width := f32(bounds_width) * entry.size_scale * over_sample.x
|
||||
glyph_height := f32(bounds_height) * entry.size_scale * over_sample.y
|
||||
glyph_dst_width := f32(bounds_width) * entry.size_scale
|
||||
glyph_dst_height := f32(bounds_height) * entry.size_scale
|
||||
glyph_width += f32(2 * ctx.atlas.glyph_padding)
|
||||
glyph_height += f32(2 * ctx.atlas.glyph_padding)
|
||||
|
||||
// Figure out the destination rect.
|
||||
bounds_scaled := Vec2 {
|
||||
cast(f32) i32(f32(bounds_0.x) * entry.size_scale - 0.5),
|
||||
cast(f32) i32(f32(bounds_0.y) * entry.size_scale - 0.5),
|
||||
}
|
||||
dst := position + scale * bounds_scaled
|
||||
dst_width := scale.x * glyph_dst_width
|
||||
dst_height := scale.y * glyph_dst_height
|
||||
dst.x -= scale.x * f32(ctx.atlas.glyph_padding)
|
||||
dst.y -= scale.y * f32(ctx.atlas.glyph_padding)
|
||||
|
||||
glyph_size := Vec2 { glyph_width, glyph_height }
|
||||
textspace_x_form( & glyph_position, & glyph_size, f32(ctx.atlas.buffer_width), f32(ctx.atlas.buffer_height) )
|
||||
|
||||
// Add the glyph drawcall.
|
||||
call : DrawCall
|
||||
{
|
||||
using call
|
||||
pass = .Target_Unchanged
|
||||
colour = ctx.colour
|
||||
start_index = u32(ctx.draw_list.indices.num)
|
||||
blit_quad( & ctx.draw_list, dst, dst + { dst_width, dst_height }, glyph_position, glyph_position + glyph_size )
|
||||
end_index = u32(ctx.draw_list.indices.num)
|
||||
append( & ctx.draw_list.calls, call )
|
||||
}
|
||||
|
||||
// Clear glyph_update_FBO.
|
||||
call.pass = .Glyph
|
||||
call.start_index = 0
|
||||
call.end_index = 0
|
||||
call.clear_before_draw = true
|
||||
append( & ctx.draw_list.calls, call )
|
||||
}
|
||||
|
||||
is_empty :: proc( ctx : ^Context, entry : ^Entry, glyph_index : Glyph ) -> b32
|
||||
{
|
||||
if glyph_index == 0 do return true
|
||||
|
@ -89,6 +89,60 @@ clear_draw_list :: proc( draw_list : ^DrawList ) {
|
||||
clear( draw_list.vertices )
|
||||
}
|
||||
|
||||
directly_draw_massive_glyph :: proc( ctx : ^Context, entry : ^Entry, glyph : Glyph, bounds_0 : Vec2i, bounds_width, bounds_height : u32, over_sample, position, scale : Vec2 )
|
||||
{
|
||||
flush_glyph_buffer_to_atlas( ctx )
|
||||
|
||||
// Draw un-antialiased glyph to update FBO.
|
||||
glyph_draw_scale := over_sample * entry.size_scale
|
||||
glyph_draw_translate := - Vec2{ f32(bounds_0.x), f32(bounds_0.y)} * glyph_draw_scale + Vec2{ f32(ctx.atlas.glyph_padding), f32(ctx.atlas.glyph_padding) }
|
||||
screenspace_x_form( & glyph_draw_translate, & glyph_draw_scale, f32(ctx.atlas.buffer_width), f32(ctx.atlas.buffer_height) )
|
||||
|
||||
cache_glyph( ctx, entry.id, glyph, glyph_draw_scale, glyph_draw_translate )
|
||||
|
||||
// Figure out the source rect.
|
||||
glyph_position := Vec2 {}
|
||||
glyph_width := f32(bounds_width) * entry.size_scale * over_sample.x
|
||||
glyph_height := f32(bounds_height) * entry.size_scale * over_sample.y
|
||||
glyph_dst_width := f32(bounds_width) * entry.size_scale
|
||||
glyph_dst_height := f32(bounds_height) * entry.size_scale
|
||||
glyph_width += f32(2 * ctx.atlas.glyph_padding)
|
||||
glyph_height += f32(2 * ctx.atlas.glyph_padding)
|
||||
|
||||
// Figure out the destination rect.
|
||||
bounds_scaled := Vec2 {
|
||||
cast(f32) i32(f32(bounds_0.x) * entry.size_scale - 0.5),
|
||||
cast(f32) i32(f32(bounds_0.y) * entry.size_scale - 0.5),
|
||||
}
|
||||
dst := position + scale * bounds_scaled
|
||||
dst_width := scale.x * glyph_dst_width
|
||||
dst_height := scale.y * glyph_dst_height
|
||||
dst.x -= scale.x * f32(ctx.atlas.glyph_padding)
|
||||
dst.y -= scale.y * f32(ctx.atlas.glyph_padding)
|
||||
|
||||
glyph_size := Vec2 { glyph_width, glyph_height }
|
||||
textspace_x_form( & glyph_position, & glyph_size, f32(ctx.atlas.buffer_width), f32(ctx.atlas.buffer_height) )
|
||||
|
||||
// Add the glyph drawcall.
|
||||
call : DrawCall
|
||||
{
|
||||
using call
|
||||
pass = .Target_Unchanged
|
||||
colour = ctx.colour
|
||||
start_index = u32(ctx.draw_list.indices.num)
|
||||
blit_quad( & ctx.draw_list, dst, dst + { dst_width, dst_height }, glyph_position, glyph_position + glyph_size )
|
||||
end_index = u32(ctx.draw_list.indices.num)
|
||||
append( & ctx.draw_list.calls, call )
|
||||
}
|
||||
|
||||
// Clear glyph_update_FBO.
|
||||
call.pass = .Glyph
|
||||
call.start_index = 0
|
||||
call.end_index = 0
|
||||
call.clear_before_draw = true
|
||||
append( & ctx.draw_list.calls, call )
|
||||
}
|
||||
|
||||
draw_cached_glyph :: proc( ctx : ^Context, entry : ^Entry, glyph_index : Glyph, position, scale : Vec2 ) -> b32
|
||||
{
|
||||
// Glyph not in current font
|
||||
|
@ -78,7 +78,7 @@ parser_load_font :: proc( ctx : ParserContext, label : string, data : []byte ) -
|
||||
|
||||
error : AllocatorError
|
||||
font, error = set( ctx.fonts, key, ParserFontInfo {} )
|
||||
assert( error != .None, "VEFontCache.parser_load_font: Failed to set a new parser font info" )
|
||||
assert( error == .None, "VEFontCache.parser_load_font: Failed to set a new parser font info" )
|
||||
switch ctx.kind
|
||||
{
|
||||
case .Freetype:
|
||||
@ -434,7 +434,7 @@ parser_convert_conic_to_cubic_freetype :: proc( vertices : Array(ParserGlyphVert
|
||||
scratch_arena : Arena; arena_init(& scratch_arena, scratch[:])
|
||||
|
||||
points, error := make( Array(freetype.Vector), 256, allocator = arena_allocator( &scratch_arena) )
|
||||
assert(error != .None)
|
||||
assert(error == .None)
|
||||
|
||||
append( & points, p0)
|
||||
append( & points, p1)
|
||||
|
@ -44,7 +44,7 @@ shaper_load_font :: proc( ctx : ^ShaperContext, label : string, data : []byte, u
|
||||
|
||||
error : AllocatorError
|
||||
info, error = set( ctx.infos, key, ShaperInfo {} )
|
||||
assert( error != .None, "VEFontCache.parser_load_font: Failed to set a new shaper info" )
|
||||
assert( error == .None, "VEFontCache.parser_load_font: Failed to set a new shaper info" )
|
||||
|
||||
using info
|
||||
blob = harfbuzz.blob_create( raw_data(data), cast(c.uint) len(data), harfbuzz.Memory_Mode.READONLY, user_data, nil )
|
||||
|
@ -65,7 +65,7 @@ atlas_init :: proc( ctx : ^Context, width, height : i32, num_nodes : u32 = Init_
|
||||
{
|
||||
error : AllocatorError
|
||||
ctx.atlas, error = make( Array(AtlasNode), u64(num_nodes), dbg_name = "font atlas" )
|
||||
ensure(error != AllocatorError.None, "Failed to allocate font atlas")
|
||||
ensure(error == AllocatorError.None, "Failed to allocate font atlas")
|
||||
|
||||
ctx.width = width
|
||||
ctx.height = height
|
||||
|
@ -68,7 +68,7 @@ render :: proc()
|
||||
}
|
||||
|
||||
// learnopengl.com/In-Practice/Text-Rendering
|
||||
if true
|
||||
when false
|
||||
{
|
||||
profile("learngl_text_render_pass")
|
||||
using font_provider_data
|
||||
|
@ -21,11 +21,6 @@ Font_TTF_Default_Chars_Padding :: 4
|
||||
Font_Load_Use_Default_Size :: -1
|
||||
Font_Load_Gen_ID :: ""
|
||||
|
||||
Font_Atlas_Packing_Method :: enum u32 {
|
||||
Raylib_Basic = 0, // Basic packing algo
|
||||
Skyeline_Rect = 1, // stb_pack_rect
|
||||
}
|
||||
|
||||
FontID :: struct {
|
||||
key : u64,
|
||||
label : string,
|
@ -1 +0,0 @@
|
||||
package sectr
|
@ -1,3 +1,98 @@
|
||||
package sectr
|
||||
|
||||
import "codebase:font/VEFontCache"
|
||||
import "core:os"
|
||||
import ve "codebase:font/VEFontCache"
|
||||
import sokol_gfx "thirdparty:sokol/gfx"
|
||||
|
||||
|
||||
Font_Provider_Use_Freetype :: false
|
||||
Font_Largest_Px_Size :: 72
|
||||
Font_Size_Interval :: 2
|
||||
|
||||
Font_Default :: FontID { 0, "" }
|
||||
Font_Default_Point_Size :: 18.0
|
||||
|
||||
Font_Load_Use_Default_Size :: -1
|
||||
Font_Load_Gen_ID :: ""
|
||||
|
||||
FontID :: struct {
|
||||
key : u64,
|
||||
label : string,
|
||||
}
|
||||
|
||||
FontDef :: struct {
|
||||
path_file : string,
|
||||
ve_id : ve.FontID,
|
||||
}
|
||||
|
||||
FontProviderData :: struct
|
||||
{
|
||||
ve_font_cache : ve.Context,
|
||||
font_cache : HMapChained(FontDef),
|
||||
|
||||
gfx_bindings : sokol_gfx.Bindings,
|
||||
gfx_pipeline : sokol_gfx.Pipeline,
|
||||
gfx_v_buffer : sokol_gfx.Buffer,
|
||||
gfx_uv_buffer : sokol_gfx.Buffer,
|
||||
gfx_sampler : sokol_gfx.Sampler,
|
||||
}
|
||||
|
||||
font_provider_startup :: proc()
|
||||
{
|
||||
profile(#procedure)
|
||||
state := get_state()
|
||||
|
||||
provider_data := state.font_provider_data; using provider_data
|
||||
|
||||
error : AllocatorError
|
||||
font_cache, error = make( HMapChained(FontDef), hmap_closest_prime(1 * Kilo), persistent_allocator() /*dbg_name = "font_cache"*/ )
|
||||
verify( error == AllocatorError.None, "Failed to allocate font_cache" )
|
||||
|
||||
ve.init( & provider_data.ve_font_cache, allocator = persistent_slab_allocator() )
|
||||
log("VEFontCached initialized")
|
||||
|
||||
// TODO(Ed): Setup sokol hookup for VEFontCache
|
||||
}
|
||||
|
||||
font_provider_shutdown :: proc()
|
||||
{
|
||||
state := get_state()
|
||||
provider_data := state.font_provider_data; using provider_data
|
||||
|
||||
ve.shutdown( & provider_data.ve_font_cache )
|
||||
}
|
||||
|
||||
|
||||
font_load :: proc(path_file : string,
|
||||
default_size : f32 = Font_Load_Use_Default_Size,
|
||||
desired_id : string = Font_Load_Gen_ID
|
||||
) -> FontID
|
||||
{
|
||||
profile(#procedure)
|
||||
|
||||
logf("Loading font: %v", path_file)
|
||||
provider_data := & get_state().font_provider_data; using provider_data
|
||||
|
||||
font_data, read_succeded : = os.read_entire_file( path_file )
|
||||
verify( b32(read_succeded), str_fmt("Failed to read font file for: %v", path_file) )
|
||||
font_data_size := cast(i32) len(font_data)
|
||||
|
||||
desired_id := desired_id
|
||||
// Use file name as key
|
||||
if len(desired_id) == 0 {
|
||||
// NOTE(Ed): This should never be used except for laziness so I'll be throwing a warning everytime.
|
||||
log("desired_key not provided, using file name. Give it a proper name!", LogLevel.Warning)
|
||||
// desired_id = cast(FontID) file_name_from_path(path_file)
|
||||
desired_id = file_name_from_path(path_file)
|
||||
}
|
||||
|
||||
key := cast(u64) crc32( transmute([]byte) desired_id )
|
||||
def, set_error := hmap_chained_set(font_cache, key, FontDef{})
|
||||
verify( set_error == AllocatorError.None, "Failed to add new font entry to cache" )
|
||||
|
||||
// TODO(Ed): Load even sizes from 8px to upper bound.
|
||||
def.ve_id = ve.load_font( & provider_data.ve_font_cache, desired_id, font_data, default_size )
|
||||
|
||||
fid := FontID { key, desired_id }
|
||||
return fid
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user