VEFontCache: look into to trying to cache the draw_list for a shape
plus other misc changes
This commit is contained in:
parent
5fbede25cb
commit
43415446b0
@ -28,11 +28,11 @@ PoolList :: struct {
|
||||
pool_list_init :: proc( pool : ^PoolList, capacity : u32, dbg_name : string = "" )
|
||||
{
|
||||
error : AllocatorError
|
||||
pool.items, error = make( [dynamic]PoolListItem, u64(capacity) )
|
||||
pool.items, error = make( [dynamic]PoolListItem, int(capacity) )
|
||||
assert( error == .None, "VEFontCache.pool_list_init : Failed to allocate items array")
|
||||
resize( & pool.items, capacity )
|
||||
|
||||
pool.free_list, error = make( [dynamic]PoolListIter, u64(capacity) )
|
||||
pool.free_list, error = make( [dynamic]PoolListIter, len = 0, cap = int(capacity) )
|
||||
assert( error == .None, "VEFontCache.pool_list_init : Failed to allocate free_list array")
|
||||
resize( & pool.free_list, capacity )
|
||||
|
||||
@ -55,7 +55,7 @@ pool_list_init :: proc( pool : ^PoolList, capacity : u32, dbg_name : string = ""
|
||||
|
||||
pool_list_free :: proc( pool : ^PoolList )
|
||||
{
|
||||
// TODO(Ed): Implement
|
||||
// TODO(Ed): Implement
|
||||
}
|
||||
|
||||
pool_list_reload :: proc( pool : ^PoolList, allocator : Allocator )
|
||||
@ -160,7 +160,7 @@ LRU_init :: proc( cache : ^LRU_Cache, capacity : u32, dbg_name : string = "" ) {
|
||||
|
||||
LRU_free :: proc( cache : ^LRU_Cache )
|
||||
{
|
||||
// TODO(Ed): Implement
|
||||
// TODO(Ed): Implement
|
||||
}
|
||||
|
||||
LRU_reload :: #force_inline proc( cache : ^LRU_Cache, allocator : Allocator )
|
||||
|
@ -27,3 +27,10 @@ TODO Additional Features:
|
||||
* Ability to set a draw transform, viewport and projection
|
||||
* By default the library's position is in unsigned normalized render space
|
||||
* Allow curve_quality to be set on a per-font basis
|
||||
|
||||
TODO Optimization:
|
||||
|
||||
* Look into caching the draw_list for each shape instead of the glyphs/positions
|
||||
* Each shape is already constrained to a Entry which is restricted to already a size-class for the glyphs
|
||||
* Caching a glyph to atlas or generating the draw command for a glyph quad to screen is expensive for large batches.
|
||||
* Attempt to look into chunking shapes again if caching the draw_list for a shape is found to be optimal
|
||||
|
@ -161,25 +161,26 @@ startup :: proc( ctx : ^Context, parser_kind : ParserKind,
|
||||
ctx.curve_quality = curve_quality
|
||||
|
||||
error : AllocatorError
|
||||
entries, error = make( [dynamic]Entry, entires_reserve )
|
||||
entries, error = make( [dynamic]Entry, len = 0, cap = entires_reserve )
|
||||
assert(error == .None, "VEFontCache.init : Failed to allocate entries")
|
||||
|
||||
temp_path, error = make( [dynamic]Vec2, temp_path_reserve )
|
||||
temp_path, error = make( [dynamic]Vec2, len = 0, cap = temp_path_reserve )
|
||||
assert(error == .None, "VEFontCache.init : Failed to allocate temp_path")
|
||||
|
||||
temp_codepoint_seen, error = make( map[u64]bool, uint(temp_codepoint_seen_reserve) )
|
||||
assert(error == .None, "VEFontCache.init : Failed to allocate temp_path")
|
||||
|
||||
draw_list.vertices, error = make( [dynamic]Vertex, 4 * Kilobyte )
|
||||
draw_list.vertices, error = make( [dynamic]Vertex, len = 0, cap = 4 * Kilobyte )
|
||||
assert(error == .None, "VEFontCache.init : Failed to allocate draw_list.vertices")
|
||||
|
||||
draw_list.indices, error = make( [dynamic]u32, 8 * Kilobyte )
|
||||
draw_list.indices, error = make( [dynamic]u32, len = 0, cap = 8 * Kilobyte )
|
||||
assert(error == .None, "VEFontCache.init : Failed to allocate draw_list.indices")
|
||||
|
||||
draw_list.calls, error = make( [dynamic]DrawCall, 512 )
|
||||
draw_list.calls, error = make( [dynamic]DrawCall, len = 0, cap = 512 )
|
||||
assert(error == .None, "VEFontCache.init : Failed to allocate draw_list.calls")
|
||||
|
||||
init_atlas_region :: proc( region : ^AtlasRegion, params : InitAtlasParams, region_params : InitAtlasRegionParams, factor : Vec2i, expected_cap : i32 ) {
|
||||
init_atlas_region :: proc( region : ^AtlasRegion, params : InitAtlasParams, region_params : InitAtlasRegionParams, factor : Vec2i, expected_cap : i32 )
|
||||
{
|
||||
using region
|
||||
|
||||
next_idx = 0;
|
||||
@ -225,11 +226,20 @@ startup :: proc( ctx : ^Context, parser_kind : ParserKind,
|
||||
for idx : u32 = 0; idx < shape_cache_params.capacity; idx += 1 {
|
||||
stroage_entry := & shape_cache.storage[idx]
|
||||
using stroage_entry
|
||||
glyphs, error = make( [dynamic]Glyph, shape_cache_params.reserve_length )
|
||||
glyphs, error = make( [dynamic]Glyph, len = 0, cap = shape_cache_params.reserve_length )
|
||||
assert( error == .None, "VEFontCache.init : Failed to allocate glyphs array for shape cache storage" )
|
||||
|
||||
positions, error = make( [dynamic]Vec2, shape_cache_params.reserve_length )
|
||||
positions, error = make( [dynamic]Vec2, len = 0, cap = shape_cache_params.reserve_length )
|
||||
assert( error == .None, "VEFontCache.init : Failed to allocate positions array for shape cache storage" )
|
||||
|
||||
draw_list.calls, error = make( [dynamic]DrawCall, len = 0, cap = glyph_draw_params.buffer_batch * 2 )
|
||||
assert( error == .None, "VEFontCache.init : Failed to allocate calls for draw_list" )
|
||||
|
||||
draw_list.indices, error = make( [dynamic]u32, len = 0, cap = glyph_draw_params.buffer_batch * 2 * 6 )
|
||||
assert( error == .None, "VEFontCache.init : Failed to allocate indices array for draw_list" )
|
||||
|
||||
draw_list.vertices, error = make( [dynamic]Vertex, len = 0, cap = glyph_draw_params.buffer_batch * 2 * 4 )
|
||||
assert( error == .None, "VEFontCache.init : Failed to allocate vertices array for draw_list" )
|
||||
}
|
||||
|
||||
// Note(From original author): We can actually go over VE_FONTCACHE_GLYPHDRAW_BUFFER_BATCH batches due to smart packing!
|
||||
@ -241,22 +251,22 @@ startup :: proc( ctx : ^Context, parser_kind : ParserKind,
|
||||
height = atlas.region_d.height * u32(over_sample.y)
|
||||
draw_padding = glyph_draw_params.draw_padding
|
||||
|
||||
draw_list.calls, error = make( [dynamic]DrawCall, cast(u64) glyph_draw_params.buffer_batch * 2 )
|
||||
draw_list.calls, error = make( [dynamic]DrawCall, len = 0, cap = glyph_draw_params.buffer_batch * 2 )
|
||||
assert( error == .None, "VEFontCache.init : Failed to allocate calls for draw_list" )
|
||||
|
||||
draw_list.indices, error = make( [dynamic]u32, cast(u64) glyph_draw_params.buffer_batch * 2 * 6 )
|
||||
draw_list.indices, error = make( [dynamic]u32, len = 0, cap = glyph_draw_params.buffer_batch * 2 * 6 )
|
||||
assert( error == .None, "VEFontCache.init : Failed to allocate indices array for draw_list" )
|
||||
|
||||
draw_list.vertices, error = make( [dynamic]Vertex, glyph_draw_params.buffer_batch * 2 * 4 )
|
||||
draw_list.vertices, error = make( [dynamic]Vertex, len = 0, cap = glyph_draw_params.buffer_batch * 2 * 4 )
|
||||
assert( error == .None, "VEFontCache.init : Failed to allocate vertices array for draw_list" )
|
||||
|
||||
clear_draw_list.calls, error = make( [dynamic]DrawCall, cast(u64) glyph_draw_params.buffer_batch * 2 )
|
||||
clear_draw_list.calls, error = make( [dynamic]DrawCall, len = 0, cap = glyph_draw_params.buffer_batch * 2 )
|
||||
assert( error == .None, "VEFontCache.init : Failed to allocate calls for calls for clear_draw_list" )
|
||||
|
||||
clear_draw_list.indices, error = make( [dynamic]u32, cast(u64) glyph_draw_params.buffer_batch * 2 * 4 )
|
||||
clear_draw_list.indices, error = make( [dynamic]u32, len = 0, cap = glyph_draw_params.buffer_batch * 2 * 4 )
|
||||
assert( error == .None, "VEFontCache.init : Failed to allocate calls for indices array for clear_draw_list" )
|
||||
|
||||
clear_draw_list.vertices, error = make( [dynamic]Vertex, glyph_draw_params.buffer_batch * 2 * 4 )
|
||||
clear_draw_list.vertices, error = make( [dynamic]Vertex, len = 0, cap = glyph_draw_params.buffer_batch * 2 * 4 )
|
||||
assert( error == .None, "VEFontCache.init : Failed to allocate vertices array for clear_draw_list" )
|
||||
}
|
||||
|
||||
@ -395,7 +405,7 @@ configure_snap :: #force_inline proc( ctx : ^Context, snap_width, snap_height :
|
||||
get_cursor_pos :: #force_inline proc "contextless" ( ctx : ^Context ) -> Vec2 { return ctx.cursor_pos }
|
||||
set_colour :: #force_inline proc "contextless" ( ctx : ^Context, colour : Colour ) { ctx.colour = colour }
|
||||
|
||||
draw_text :: proc( ctx : ^Context, font : FontID, text_utf8 : string, position : Vec2, scale : Vec2 ) -> b32
|
||||
draw_text :: proc( ctx : ^Context, font : FontID, text_utf8 : string, position, scale : Vec2 ) -> b32
|
||||
{
|
||||
// profile(#procedure)
|
||||
assert( ctx != nil )
|
||||
@ -471,24 +481,9 @@ measure_text_size :: proc( ctx : ^Context, font : FontID, text_utf8 : string ) -
|
||||
assert( ctx != nil )
|
||||
assert( font >= 0 && int(font) < len(ctx.entries) )
|
||||
|
||||
atlas := ctx.atlas
|
||||
entry := & ctx.entries[ font ]
|
||||
shaped := shape_text_cached( ctx, font, text_utf8, entry )
|
||||
padding := cast(f32) atlas.glyph_padding
|
||||
|
||||
for index : i32 = 0; index < i32(len(shaped.glyphs)); index += 1
|
||||
{
|
||||
glyph_index := shaped.glyphs[ index ]
|
||||
if is_empty( ctx, entry, glyph_index ) do continue
|
||||
|
||||
bounds_0, bounds_1 := parser_get_glyph_box( & entry.parser_info, glyph_index )
|
||||
bounds_size := bounds_1 - bounds_0
|
||||
|
||||
glyph_size := Vec2 { f32(bounds_size.x), f32(bounds_size.y) } * entry.size_scale
|
||||
measured.y = max(measured.y, glyph_size.y)
|
||||
}
|
||||
measured.x = shaped.end_cursor_pos.x
|
||||
return measured
|
||||
entry := &ctx.entries[font]
|
||||
shaped := shape_text_cached(ctx, font, text_utf8, entry)
|
||||
return shaped.size
|
||||
}
|
||||
|
||||
get_font_vertical_metrics :: #force_inline proc ( ctx : ^Context, font : FontID ) -> ( ascent, descent, line_gap : i32 )
|
||||
|
Binary file not shown.
@ -60,25 +60,25 @@ blit_quad :: proc( draw_list : ^DrawList, p0 : Vec2 = {0, 0}, p1 : Vec2 = {1, 1}
|
||||
{p0.x, p0.y},
|
||||
uv0.x, uv0.y
|
||||
}
|
||||
append_elem( & draw_list.vertices, vertex )
|
||||
append( & draw_list.vertices, vertex )
|
||||
|
||||
vertex = Vertex {
|
||||
{p0.x, p1.y},
|
||||
uv0.x, uv1.y
|
||||
}
|
||||
append_elem( & draw_list.vertices, vertex )
|
||||
append( & draw_list.vertices, vertex )
|
||||
|
||||
vertex = Vertex {
|
||||
{p1.x, p0.y},
|
||||
uv1.x, uv0.y
|
||||
}
|
||||
append_elem( & draw_list.vertices, vertex )
|
||||
append( & draw_list.vertices, vertex )
|
||||
|
||||
vertex = Vertex {
|
||||
{p1.x, p1.y},
|
||||
uv1.x, uv1.y
|
||||
}
|
||||
append_elem( & draw_list.vertices, vertex )
|
||||
append( & draw_list.vertices, vertex )
|
||||
|
||||
quad_indices : []u32 = {
|
||||
0, 1, 2,
|
||||
@ -332,7 +332,8 @@ cache_glyph_to_atlas :: proc( ctx : ^Context,
|
||||
cache_glyph( ctx, font, glyph_index, entry, vec2(bounds_0), vec2(bounds_1), glyph_draw_scale, glyph_draw_translate )
|
||||
}
|
||||
|
||||
can_batch_glyph :: #force_inline proc( ctx : ^Context, font : FontID, entry : ^Entry, glyph_index : Glyph,
|
||||
// If the glyuph is found in the atlas, nothing occurs, otherwise, the glyph call is setup to catch it to the atlas
|
||||
check_glyph_in_atlas :: #force_inline proc( ctx : ^Context, font : FontID, entry : ^Entry, glyph_index : Glyph,
|
||||
lru_code : u64,
|
||||
atlas_index : i32,
|
||||
region_kind : AtlasRegionKind,
|
||||
@ -438,7 +439,7 @@ directly_draw_massive_glyph :: proc( ctx : ^Context,
|
||||
append( & ctx.draw_list.calls, call )
|
||||
}
|
||||
|
||||
draw_cached_glyph :: proc( ctx : ^Context,
|
||||
draw_cached_glyph :: proc( ctx : ^Context, shaped : ^ShapedText,
|
||||
entry : ^Entry,
|
||||
glyph_index : Glyph,
|
||||
lru_code : u64,
|
||||
@ -486,6 +487,24 @@ draw_cached_glyph :: proc( ctx : ^Context,
|
||||
|
||||
textspace_x_form( & slot_position, & glyph_scale, atlas_size )
|
||||
|
||||
// Shape call setup
|
||||
if false
|
||||
{
|
||||
call := DrawCall_Default
|
||||
{
|
||||
using call
|
||||
pass = .Target
|
||||
colour = ctx.colour
|
||||
start_index = cast(u32) len(shaped.draw_list.indices)
|
||||
|
||||
blit_quad( & shaped.draw_list,
|
||||
dst, dst + dst_scale,
|
||||
slot_position, slot_position + glyph_scale )
|
||||
end_index = cast(u32) len(shaped.draw_list.indices)
|
||||
}
|
||||
append( & shaped.draw_list.calls, call )
|
||||
}
|
||||
|
||||
// Add the glyph drawcall
|
||||
call := DrawCall_Default
|
||||
{
|
||||
@ -500,6 +519,7 @@ draw_cached_glyph :: proc( ctx : ^Context,
|
||||
end_index = cast(u32) len(ctx.draw_list.indices)
|
||||
}
|
||||
append( & ctx.draw_list.calls, call )
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@ -575,7 +595,7 @@ draw_text_batch :: proc( ctx : ^Context, entry : ^Entry, shaped : ^ShapedText,
|
||||
shaped_position := shaped.positions[index]
|
||||
glyph_translate := position + shaped_position * scale
|
||||
|
||||
glyph_cached := draw_cached_glyph( ctx,
|
||||
glyph_cached := draw_cached_glyph( ctx, shaped,
|
||||
entry, glyph_index,
|
||||
lru_code, atlas_index,
|
||||
vec2(bounds_0), vec2(bounds_1),
|
||||
@ -594,6 +614,9 @@ draw_text_shape :: proc( ctx : ^Context,
|
||||
snap_width, snap_height : f32
|
||||
) -> (cursor_pos : Vec2)
|
||||
{
|
||||
draw_hash := shape_draw_hash( shaped, position, scale )
|
||||
dirty_shape := ! (len(shaped.draw_list.calls) > 0) || draw_hash != shaped.draw_hash
|
||||
|
||||
// position := position //+ ctx.cursor_pos * scale
|
||||
// profile(#procedure)
|
||||
batch_start_idx : i32 = 0
|
||||
@ -607,7 +630,10 @@ draw_text_shape :: proc( ctx : ^Context,
|
||||
atlas_index := cast(i32) -1
|
||||
|
||||
if region_kind != .E do atlas_index = LRU_get( & region.state, lru_code )
|
||||
if can_batch_glyph( ctx, font, entry, glyph_index, lru_code, atlas_index, region_kind, region, over_sample ) do continue
|
||||
if check_glyph_in_atlas( ctx, font, entry, glyph_index, lru_code, atlas_index, region_kind, region, over_sample ) do continue
|
||||
|
||||
// We can no longer directly append the shape as it has missing glyphs in the atlas
|
||||
dirty_shape = true
|
||||
|
||||
// Glyph has not been catched, needs to be directly drawn.
|
||||
|
||||
@ -621,10 +647,18 @@ draw_text_shape :: proc( ctx : ^Context,
|
||||
batch_start_idx = index
|
||||
}
|
||||
|
||||
// flush_glyph_buffer_to_atlas(ctx)
|
||||
draw_text_batch( ctx, entry, shaped, batch_start_idx, cast(i32) len(shaped.glyphs), position, scale, snap_width , snap_height )
|
||||
// if dirty_shape {
|
||||
flush_glyph_buffer_to_atlas(ctx)
|
||||
draw_text_batch( ctx, entry, shaped, batch_start_idx, cast(i32) len(shaped.glyphs), position, scale, snap_width , snap_height )
|
||||
// shaped.draw_hash = draw_hash
|
||||
// }
|
||||
// else {
|
||||
// flush_glyph_buffer_to_atlas( ctx )
|
||||
// merge_draw_list( & ctx.draw_list, & shaped.draw_list )
|
||||
// }
|
||||
reset_batch_codepoint_state( ctx )
|
||||
cursor_pos = position + shaped.end_cursor_pos * scae
|
||||
|
||||
cursor_pos = position + shaped.end_cursor_pos * scale
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -50,13 +50,6 @@ font_glyph_lru_code :: #force_inline proc "contextless" ( font : FontID, glyph_i
|
||||
return
|
||||
}
|
||||
|
||||
shape_lru_hash :: #force_inline proc "contextless" ( label : string ) -> u64 {
|
||||
hash : u64
|
||||
for str_byte in transmute([]byte) label {
|
||||
hash = ((hash << 8) + hash) + u64(str_byte)
|
||||
}
|
||||
return hash
|
||||
}
|
||||
|
||||
// For a provided alpha value,
|
||||
// allows the function to calculate the position of a point along the curve at any given fraction of its total length
|
||||
|
@ -1,11 +1,13 @@
|
||||
package VEFontCache
|
||||
|
||||
import "core:math"
|
||||
|
||||
ShapedText :: struct {
|
||||
draw_list : DrawList,
|
||||
glyphs : [dynamic]Glyph,
|
||||
positions : [dynamic]Vec2,
|
||||
end_cursor_pos : Vec2,
|
||||
size : Vec2,
|
||||
storage_hash : u64,
|
||||
draw_hash : u64,
|
||||
}
|
||||
|
||||
ShapedTextCache :: struct {
|
||||
@ -14,36 +16,68 @@ ShapedTextCache :: struct {
|
||||
next_cache_id : i32,
|
||||
}
|
||||
|
||||
|
||||
shape_draw_hash :: #force_inline proc "contextless" ( shaped : ^ShapedText, pos, scale : Vec2 ) -> (draw_hash : u64)
|
||||
{
|
||||
pos := pos
|
||||
scale := scale
|
||||
pos_bytes := slice_ptr( transmute(^byte) & pos, size_of(Vec2))
|
||||
scale_bytes := slice_ptr( transmute(^byte) & scale, size_of(Vec2))
|
||||
|
||||
draw_hash = shaped.storage_hash
|
||||
shape_lru_hash( & shaped.draw_hash, pos_bytes )
|
||||
shape_lru_hash( & shaped.draw_hash, scale_bytes )
|
||||
return
|
||||
}
|
||||
|
||||
// shape_lru_hash_og :: #force_inline proc "contextless" ( label : string ) -> u64 {
|
||||
// hash : u64
|
||||
// for str_byte in transmute([]byte) label {
|
||||
// hash = ((hash << 8) + hash) + u64(str_byte)
|
||||
// }
|
||||
// return hash
|
||||
// }
|
||||
|
||||
shape_lru_hash :: #force_inline proc "contextless" ( hash : ^u64, bytes : []byte ) {
|
||||
for value in bytes {
|
||||
(hash^) = (( (hash^) << 8) + (hash^) ) + u64(value)
|
||||
}
|
||||
}
|
||||
|
||||
shape_text_cached :: proc( ctx : ^Context, font : FontID, text_utf8 : string, entry : ^Entry ) -> ^ShapedText
|
||||
{
|
||||
// profile(#procedure)
|
||||
@static buffer : [64 * Kilobyte]byte
|
||||
font := font
|
||||
font_bytes := slice_ptr( transmute(^byte) & font, size_of(FontID) )
|
||||
text_bytes := transmute( []byte) text_utf8
|
||||
|
||||
font := font
|
||||
text_size := len(text_utf8)
|
||||
sice_end_offset := size_of(FontID) + len(text_utf8)
|
||||
lru_code : u64
|
||||
shape_lru_hash( & lru_code, font_bytes )
|
||||
shape_lru_hash( & lru_code, text_bytes )
|
||||
|
||||
buffer_slice := buffer[:]
|
||||
font_bytes := slice_ptr( transmute(^byte) & font, size_of(FontID) )
|
||||
copy( buffer_slice, font_bytes )
|
||||
// @static buffer : [64 * Kilobyte]byte
|
||||
// text_size := len(text_utf8)
|
||||
// sice_end_offset := size_of(FontID) + len(text_utf8)
|
||||
|
||||
text_bytes := transmute( []byte) text_utf8
|
||||
buffer_slice_post_font := buffer[ size_of(FontID) : sice_end_offset ]
|
||||
copy( buffer_slice_post_font, text_bytes )
|
||||
// buffer_slice := buffer[:]
|
||||
// copy( buffer_slice, font_bytes )
|
||||
|
||||
hash := shape_lru_hash( transmute(string) buffer[: sice_end_offset ] )
|
||||
// buffer_slice_post_font := buffer[ size_of(FontID) : sice_end_offset ]
|
||||
// copy( buffer_slice_post_font, text_bytes )
|
||||
|
||||
// lru_code := shape_lru_hash_og( transmute(string) buffer[: sice_end_offset ] )
|
||||
|
||||
shape_cache := & ctx.shape_cache
|
||||
state := & ctx.shape_cache.state
|
||||
|
||||
shape_cache_idx := LRU_get( state, hash )
|
||||
shape_cache_idx := LRU_get( state, lru_code )
|
||||
if shape_cache_idx == -1
|
||||
{
|
||||
if shape_cache.next_cache_id < i32(state.capacity) {
|
||||
shape_cache_idx = shape_cache.next_cache_id
|
||||
shape_cache.next_cache_id += 1
|
||||
evicted := LRU_put( state, hash, shape_cache_idx )
|
||||
assert( evicted == hash )
|
||||
evicted := LRU_put( state, lru_code, shape_cache_idx )
|
||||
assert( evicted == lru_code )
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -53,16 +87,17 @@ shape_text_cached :: proc( ctx : ^Context, font : FontID, text_utf8 : string, en
|
||||
shape_cache_idx = LRU_peek( state, next_evict_idx, must_find = true )
|
||||
assert( shape_cache_idx != - 1 )
|
||||
|
||||
LRU_put( state, hash, shape_cache_idx )
|
||||
LRU_put( state, lru_code, shape_cache_idx )
|
||||
}
|
||||
|
||||
shape_text_uncached( ctx, font, text_utf8, entry, & shape_cache.storage[ shape_cache_idx ] )
|
||||
shape_entry := & shape_cache.storage[ shape_cache_idx ]
|
||||
shape_entry.storage_hash = lru_code
|
||||
shape_text_uncached( ctx, font, text_utf8, entry, shape_entry )
|
||||
}
|
||||
|
||||
return & shape_cache.storage[ shape_cache_idx ]
|
||||
}
|
||||
|
||||
// TODO(Ed): Make position rounding an option
|
||||
shape_text_uncached :: proc( ctx : ^Context, font : FontID, text_utf8 : string, entry : ^Entry, output : ^ShapedText )
|
||||
{
|
||||
// profile(#procedure)
|
||||
@ -71,15 +106,21 @@ shape_text_uncached :: proc( ctx : ^Context, font : FontID, text_utf8 : string,
|
||||
|
||||
use_full_text_shape := ctx.text_shape_adv
|
||||
|
||||
clear_draw_list( & output.draw_list )
|
||||
clear( & output.glyphs )
|
||||
clear( & output.positions )
|
||||
|
||||
ascent, descent, line_gap := parser_get_font_vertical_metrics( & entry.parser_info )
|
||||
ascent_i32, descent_i32, line_gap_i32 := parser_get_font_vertical_metrics( & entry.parser_info )
|
||||
ascent := f32(ascent_i32)
|
||||
descent := f32(descent_i32)
|
||||
line_gap := f32(line_gap_i32)
|
||||
line_height := (ascent - descent + line_gap) * entry.size_scale
|
||||
|
||||
if use_full_text_shape
|
||||
{
|
||||
// assert( entry.shaper_info != nil )
|
||||
shaper_shape_from_text( & ctx.shaper_ctx, & entry.shaper_info, output, text_utf8, ascent, descent, line_gap, 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
|
||||
}
|
||||
else
|
||||
@ -87,13 +128,10 @@ shape_text_uncached :: proc( ctx : ^Context, font : FontID, text_utf8 : string,
|
||||
// Note(Original Author):
|
||||
// We use our own fallback dumbass text shaping.
|
||||
// WARNING: PLEASE USE HARFBUZZ. GOOD TEXT SHAPING IS IMPORTANT FOR INTERNATIONALISATION.
|
||||
ascent := f32(ascent)
|
||||
descent := f32(descent)
|
||||
line_gap := f32(line_gap)
|
||||
|
||||
position : Vec2
|
||||
advance : i32 = 0
|
||||
to_left_side_glyph : i32 = 0
|
||||
line_count : int = 1
|
||||
max_line_width : f32 = 0
|
||||
position : Vec2
|
||||
|
||||
prev_codepoint : rune
|
||||
for codepoint in text_utf8
|
||||
@ -104,29 +142,34 @@ shape_text_uncached :: proc( ctx : ^Context, font : FontID, text_utf8 : string,
|
||||
}
|
||||
if codepoint == '\n'
|
||||
{
|
||||
position.x = 0.0
|
||||
position.y -= (ascent - descent + line_gap) * entry.size_scale
|
||||
position.y = ceil(position.y)
|
||||
line_count += 1
|
||||
max_line_width = max(max_line_width, position.x)
|
||||
position.x = 0.0
|
||||
position.y -= line_height
|
||||
position.y = ceil(position.y)
|
||||
prev_codepoint = rune(0)
|
||||
continue
|
||||
}
|
||||
if abs( entry.size ) <= Advance_Snap_Smallfont_Size {
|
||||
position.x = math.ceil( position.x )
|
||||
position.x = ceil( position.x )
|
||||
}
|
||||
|
||||
append( & output.glyphs, parser_find_glyph_index( & entry.parser_info, codepoint ))
|
||||
advance, to_left_side_glyph = parser_get_codepoint_horizontal_metrics( & entry.parser_info, codepoint )
|
||||
advance, _ := parser_get_codepoint_horizontal_metrics( & entry.parser_info, codepoint )
|
||||
|
||||
append( & output.positions, Vec2 {
|
||||
ceil(position.x),
|
||||
position.y
|
||||
})
|
||||
// append( & output.positions, position )
|
||||
|
||||
position.x += f32(advance) * entry.size_scale
|
||||
prev_codepoint = codepoint
|
||||
}
|
||||
|
||||
output.end_cursor_pos = position
|
||||
max_line_width = max(max_line_width, position.x)
|
||||
|
||||
output.size.x = max_line_width
|
||||
output.size.y = f32(line_count) * line_height
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user