Preparing to attempt to offload various metric calculations for a shape's glyphs to the shape itself from the draw list generator

This commit is contained in:
Edward R. Gonzalez 2025-01-07 22:24:23 -05:00
parent fa627b4c4a
commit 18d8735c54
7 changed files with 176 additions and 67 deletions

View File

@ -13,14 +13,14 @@ Atlas_Region_Kind :: enum u8 {
}
// Note(Ed): Using 16 bit hash had collision failures and no observable performance improvement (tried several 16-bit hashers)
Atlas_Region_Key :: u32
Atlas_Key :: u32
// TODO(Ed) It might perform better with a tailored made hashtable implementation for the LRU_Cache or dedicated array struct/procs for the Atlas.
/* Essentially a sub-atlas of the atlas. There is a state cache per region that tracks the glyph inventory (what slot they occupy).
Unlike the shape cache this one's fixed capacity (natrually) and the next avail slot is tracked.
*/
Atlas_Region :: struct {
state : LRU_Cache(Atlas_Region_Key),
state : LRU_Cache(Atlas_Key),
size : Vec2i,
capacity : Vec2i,
@ -54,7 +54,7 @@ Atlas :: struct {
}
// Hahser for the atlas.
atlas_glyph_lru_code :: #force_inline proc "contextless" ( font : Font_ID, px_size : f32, glyph_index : Glyph ) -> (lru_code : Atlas_Region_Key) {
atlas_glyph_lru_code :: #force_inline proc "contextless" ( font : Font_ID, px_size : f32, glyph_index : Glyph ) -> (lru_code : Atlas_Key) {
// lru_code = u32(glyph_index) + ( ( 0x10000 * u32(font) ) & 0xFFFF0000 )
font := font
glyph_index := glyph_index
@ -65,6 +65,7 @@ atlas_glyph_lru_code :: #force_inline proc "contextless" ( font : Font_ID, px_si
return
}
@(optimization_mode="favor_size")
atlas_region_bbox :: #force_inline proc( region : Atlas_Region, local_idx : i32 ) -> (position, size: Vec2)
{
size = vec2(region.slot_size.x)
@ -77,13 +78,17 @@ atlas_region_bbox :: #force_inline proc( region : Atlas_Region, local_idx : i32
return
}
@(optimization_mode="favor_size")
atlas_decide_region :: #force_inline proc "contextless" (atlas : Atlas, glyph_buffer_size : Vec2, bounds_size_scaled : Vec2 ) -> (region_kind : Atlas_Region_Kind)
{
profile(#procedure)
glyph_padding_dbl := atlas.glyph_padding * 2
padded_bounds := bounds_size_scaled + glyph_padding_dbl
for kind in 1 ..= 4 do if padded_bounds.x <= f32( atlas.regions[kind].slot_size.x) && padded_bounds.y <= f32(atlas.regions[kind].slot_size.y) {
for kind in 1 ..= 4 do if
padded_bounds.x <= f32(atlas.regions[kind].slot_size.x) &&
padded_bounds.y <= f32(atlas.regions[kind].slot_size.y)
{
return cast(Atlas_Region_Kind) kind
}
@ -93,8 +98,46 @@ atlas_decide_region :: #force_inline proc "contextless" (atlas : Atlas, glyph_bu
return .None
}
@(optimization_mode="favor_size")
atlas_decide_region_branchless :: #force_inline proc "contextless" (
atlas: Atlas,
glyph_buffer_size : Vec2,
bounds_size_scaled : Vec2,
) -> Atlas_Region_Kind
{
profile(#procedure)
glyph_padding_dbl := atlas.glyph_padding * 2
padded_bounds := bounds_size_scaled + glyph_padding_dbl
slot_size_region_a := vec2(atlas.region_a.slot_size)
slot_size_region_b := vec2(atlas.region_b.slot_size)
slot_size_region_c := vec2(atlas.region_c.slot_size)
slot_size_region_d := vec2(atlas.region_d.slot_size)
within_a := padded_bounds.x <= slot_size_region_a.x && padded_bounds.y <= slot_size_region_a.y
within_b := padded_bounds.x <= slot_size_region_b.x && padded_bounds.y <= slot_size_region_b.y
within_c := padded_bounds.x <= slot_size_region_c.x && padded_bounds.y <= slot_size_region_c.y
within_d := padded_bounds.x <= slot_size_region_d.x && padded_bounds.y <= slot_size_region_d.y
within_buffer := padded_bounds.x <= glyph_buffer_size.x && padded_bounds.y <= glyph_buffer_size.y
within_none := cast(i32) ! (within_a || within_b || within_c || within_d )
score_a := i32(within_a) * -5
score_b := i32(within_b) * -4
score_c := i32(within_c) * -3
score_d := i32(within_d) * -2
score_buffer := i32(within_buffer) * -1
which_ab := min(score_a, score_b)
which_cd := min(score_c, score_d)
which_region := min(which_ab, which_cd)
resolved := min(which_region, score_buffer) + 6
return Atlas_Region_Kind(resolved)
}
// Grab an atlas LRU cache slot.
atlas_reserve_slot :: #force_inline proc ( region : ^Atlas_Region, lru_code : Atlas_Region_Key ) -> (atlas_index : i32)
@(optimization_mode="favor_size")
atlas_reserve_slot :: #force_inline proc ( region : ^Atlas_Region, lru_code : Atlas_Key ) -> (atlas_index : i32)
{
if region.next_idx < region.state.capacity
{

View File

@ -41,11 +41,11 @@ Glyph_Draw_Quad :: struct {
// This is used by generate_shape_draw_list & batch_generate_glyphs_draw_list
// to track relevant glyph data in soa format for pipelined processing
Glyph_Pack_Entry :: struct {
Glyph_Pack_Entry :: struct #packed {
position : Vec2,
index : Glyph,
lru_code : Atlas_Region_Key,
lru_code : Atlas_Key,
atlas_index : i32,
in_atlas : b8,
should_cache : b8,
@ -103,7 +103,7 @@ Frame_Buffer_Pass :: enum u32 {
}
Glyph_Batch_Cache :: struct {
table : map[Atlas_Region_Key]b8,
table : map[Atlas_Key]b8,
num : i32,
cap : i32,
}
@ -128,7 +128,7 @@ Glyph_Draw_Buffer :: struct{
cached : [dynamic]i32,
}
// Contructs a
// Contructs a quad mesh for bliting a texture from one render target (src uv0 & 1) to the destination rendertarget (p0, p1)
@(optimization_mode="favor_size")
blit_quad :: #force_inline proc ( draw_list : ^Draw_List, p0 : Vec2 = {0, 0}, p1 : Vec2 = {1, 1}, uv0 : Vec2 = {0, 0}, uv1 : Vec2 = {1, 1} )
{
@ -330,7 +330,7 @@ generate_shape_draw_list :: proc( draw_list : ^Draw_List, shape : Shaped_Text,
// font_scale := font_scale * px_scalar
// target_scale := target_scale / px_scalar
mark_glyph_seen :: #force_inline proc "contextless" ( cache : ^Glyph_Batch_Cache, lru_code : Atlas_Region_Key ) {
mark_glyph_seen :: #force_inline proc "contextless" ( cache : ^Glyph_Batch_Cache, lru_code : Atlas_Key ) {
cache.table[lru_code] = true
cache.num += 1
}
@ -348,7 +348,7 @@ generate_shape_draw_list :: proc( draw_list : ^Draw_List, shape : Shaped_Text,
oversized := & glyph_buffer.oversized
to_cache := & glyph_buffer.to_cache
cached := & glyph_buffer.cached
resize_soa_non_zero(glyph_pack, len(shape.glyphs))
resize_soa_non_zero(glyph_pack, len(shape.glyph_id))
append_sub_pack :: #force_inline proc ( pack : ^[dynamic]i32, entry : i32 )
{
@ -361,7 +361,7 @@ generate_shape_draw_list :: proc( draw_list : ^Draw_List, shape : Shaped_Text,
profile_begin("index")
for & glyph, index in glyph_pack
{
glyph.index = shape.glyphs[ index ]
glyph.index = shape.glyph_id[ index ]
glyph.lru_code = atlas_glyph_lru_code(entry.id, px_size, glyph.index)
}
profile_end()
@ -369,7 +369,7 @@ generate_shape_draw_list :: proc( draw_list : ^Draw_List, shape : Shaped_Text,
profile_begin("translate")
for & glyph, index in glyph_pack
{
glyph.position = target_position + (shape.positions[index]) * target_scale
glyph.position = target_position + (shape.position[index]) * target_scale
}
profile_end()
@ -724,12 +724,12 @@ batch_generate_glyphs_draw_list :: proc ( draw_list : ^Draw_List,
dst_glyph_pos := glyph.region_pos
dst_glyph_size := glyph.bounds_size_scaled + atlas.glyph_padding
dst_glyph_size.y = ceil(dst_glyph_size.y) * glyph_buffer.snap_glyph_height // Note(Ed): Seems to improve hinting
dst_glyph_size.y = max(dst_glyph_size.y, ceil(dst_glyph_size.y) * glyph_buffer.snap_glyph_height) // Note(Ed): Seems to improve hinting
to_glyph_buffer_space( & dst_glyph_pos, & dst_glyph_size, atlas_size )
src_position := Vec2 { glyph.buffer_x, 0 }
src_size := (glyph.bounds_size_scaled + atlas.glyph_padding) * glyph_buffer.over_sample
src_size.y = ceil(src_size.y) * glyph_buffer.snap_glyph_height // Note(Ed): Seems to improve hinting
src_size.y = max(src_size.y, ceil(src_size.y) * glyph_buffer.snap_glyph_height) // Note(Ed): Seems to improve hinting
to_target_space( & src_position, & src_size, glyph_buffer_size )
blit_to_atlas : Draw_Call

View File

@ -26,10 +26,11 @@ Shape_Key :: u32
your not going to be satisfied with keeping that in the iteration).
*/
Shaped_Text :: struct {
glyphs : [dynamic]Glyph,
positions : [dynamic]Vec2,
// bounds : [dynamic]Range2, // TODO(Ed): Test tracking/resolving the bounds here, its expensive to resolve at the draw list generation stage.
// region_kinds : [dynamic]Atlas_Region_Kind, // TODO(ed): test tracking/resolving the assigne atlas region here, for some reason as ^^.
glyph_id : [dynamic]Glyph,
position : [dynamic]Vec2,
atlas_lru_code : [dynamic]Atlas_Key,
region_kind : [dynamic]Atlas_Region_Kind,
bound : [dynamic]Range2,
end_cursor_pos : Vec2,
size : Vec2,
}
@ -43,7 +44,15 @@ Shaped_Text_Cache :: struct {
}
// Used by shaper_shape_text_cached, allows user to specify their own proc at compile-time without having to rewrite the caching implementation.
Shaper_Shape_Text_Uncached_Proc :: #type proc( ctx : ^Shaper_Context, entry : Entry, font_px_Size, font_scale : f32, text_utf8 : string, output : ^Shaped_Text )
Shaper_Shape_Text_Uncached_Proc :: #type proc( ctx : ^Shaper_Context,
atlas : Atlas,
glyph_buffer_size : Vec2,
entry : Entry,
font_px_Size : f32,
font_scale : f32,
text_utf8 : string,
output : ^Shaped_Text
)
// Note(Ed): Not used..
Shaper_Kind :: enum {
@ -186,8 +195,8 @@ shaper_shape_harfbuzz :: proc( ctx : ^Shaper_Context, text_utf8 : string, entry
is_empty := parser_is_glyph_empty(entry.parser_info, glyph_id)
if ! is_empty {
append( & output.glyphs, glyph_id )
append( & output.positions, glyph_pos)
append( & output.glyph_id, glyph_id )
append( & output.position, glyph_pos)
}
}
@ -253,36 +262,67 @@ shaper_shape_harfbuzz :: proc( ctx : ^Shaper_Context, text_utf8 : string, entry
}
shaper_shape_text_uncached_advanced :: #force_inline proc( ctx : ^Shaper_Context,
entry : Entry,
font_px_size : f32,
font_scale : f32,
text_utf8 : string,
output : ^Shaped_Text
atlas : Atlas,
glyph_buffer_size : Vec2,
entry : Entry,
font_px_size : f32,
font_scale : f32,
text_utf8 : string,
output : ^Shaped_Text
)
{
profile(#procedure)
assert( ctx != nil )
clear( & output.glyphs )
clear( & output.positions )
clear( & output.glyph_id )
clear( & output.position )
shaper_shape_harfbuzz( ctx, text_utf8, entry, font_px_size, font_scale, output )
// Resolve each glyphs: bounds, atlas lru, and the atlas region as we have everything we need now.
profile_begin("bounds")
for id, index in output.glyph_id
{
// glyph.bounds = parser_get_bounds( entry.parser_info, glyph.index )
// glyph.bounds_scaled = { glyph.bounds.p0 * font_scale, glyph.bounds.p1 * font_scale }
// glyph.bounds_size = glyph.bounds.p1 - glyph.bounds.p0
// glyph.bounds_size_scaled = glyph.bounds_size * font_scale
// glyph.scale = glyph.bounds_size_scaled + atlas.glyph_padding
}
profile_end()
profile_begin("index")
for id, index in output.glyph_id
{
// output.atlas_lru_code[index] = atlas_glyph_lru_code(entry.id, px_size, glyph.index)
}
profile_end()
profile_begin("region")
for id, index in output.glyph_id
{
// output.region_kind[index] = atlas_decide_region_branchless( atlas ^, glyph_buffer_size, glyph.bounds_size_scaled )
}
profile_end()
}
// Basic western alphabet based shaping. Not that much faster than harfbuzz if at all.
shaper_shape_text_latin :: proc( ctx : ^Shaper_Context,
entry : Entry,
font_px_Size : f32,
font_scale : f32,
text_utf8 : string,
output : ^Shaped_Text
shaper_shape_text_latin :: proc( ctx : ^Shaper_Context,
atlas : Atlas,
glyph_buffer_size : Vec2,
entry : Entry,
font_px_Size : f32,
font_scale : f32,
text_utf8 : string,
output : ^Shaped_Text
)
{
profile(#procedure)
assert( ctx != nil )
clear( & output.glyphs )
clear( & output.positions )
clear( & output.glyph_id )
clear( & output.position )
line_height := (entry.ascent - entry.descent + entry.line_gap) * font_scale
@ -315,8 +355,8 @@ shaper_shape_text_latin :: proc( ctx : ^Shaper_Context,
is_glyph_empty := parser_is_glyph_empty( entry.parser_info, glyph_index )
if ! is_glyph_empty
{
append( & output.glyphs, glyph_index)
append( & output.positions, Vec2 {
append( & output.glyph_id, glyph_index)
append( & output.position, Vec2 {
ceil(position.x),
ceil(position.y)
})
@ -343,6 +383,8 @@ shaper_shape_text_latin :: proc( ctx : ^Shaper_Context,
shaper_shape_text_cached :: proc( text_utf8 : string,
ctx : ^Shaper_Context,
shape_cache : ^Shaped_Text_Cache,
atlas : Atlas,
glyph_buffer_size : Vec2,
font : Font_ID,
entry : Entry,
font_px_size : f32,
@ -384,7 +426,7 @@ shaper_shape_text_cached :: proc( text_utf8 : string,
}
storage_entry := & shape_cache.storage[ shape_cache_idx ]
shape_text_uncached( ctx, entry, font_px_size, font_scale, text_utf8, storage_entry )
shape_text_uncached( ctx, atlas, glyph_buffer_size, entry, font_px_size, font_scale, text_utf8, storage_entry )
shaped_text = storage_entry ^
return

View File

@ -8,7 +8,7 @@ package vetext
import "base:runtime"
// See: mappings.odin for profiling hookup
DISABLE_PROFILING :: true
DISABLE_PROFILING :: false
Font_ID :: distinct i32
Glyph :: distinct i32
@ -271,10 +271,10 @@ startup :: proc( ctx : ^Context, parser_kind : Parser_Kind = .STB_TrueType,
for idx : u32 = 0; idx < shape_cache_params.capacity; idx += 1 {
stroage_entry := & shape_cache.storage[idx]
stroage_entry.glyphs, error = make( [dynamic]Glyph, len = 0, cap = shape_cache_params.reserve )
stroage_entry.glyph_id, error = make( [dynamic]Glyph, len = 0, cap = shape_cache_params.reserve )
assert( error == .None, "VEFontCache.init : Failed to allocate glyphs array for shape cache storage" )
stroage_entry.positions, error = make( [dynamic]Vec2, len = 0, cap = shape_cache_params.reserve )
stroage_entry.position, error = make( [dynamic]Vec2, len = 0, cap = shape_cache_params.reserve )
assert( error == .None, "VEFontCache.init : Failed to allocate positions array for shape cache storage" )
}
}
@ -282,10 +282,11 @@ startup :: proc( ctx : ^Context, parser_kind : Parser_Kind = .STB_TrueType,
Glyph_Buffer_Setup:
{
glyph_buffer := & ctx.glyph_buffer
glyph_buffer.over_sample = { f32(glyph_draw_params.over_sample), f32(glyph_draw_params.over_sample) }
glyph_buffer.size.x = atlas.region_d.slot_size.x * i32(glyph_buffer.over_sample.x) * i32(glyph_draw_params.buffer_glyph_limit)
glyph_buffer.size.y = atlas.region_d.slot_size.y * i32(glyph_buffer.over_sample.y)
glyph_buffer.draw_padding = cast(f32) glyph_draw_params.draw_padding
glyph_buffer.snap_glyph_height = cast(f32) i32(glyph_draw_params.snap_glyph_height)
glyph_buffer.over_sample = { f32(glyph_draw_params.over_sample), f32(glyph_draw_params.over_sample) }
glyph_buffer.size.x = atlas.region_d.slot_size.x * i32(glyph_buffer.over_sample.x) * i32(glyph_draw_params.buffer_glyph_limit)
glyph_buffer.size.y = atlas.region_d.slot_size.y * i32(glyph_buffer.over_sample.y)
glyph_buffer.draw_padding = cast(f32) glyph_draw_params.draw_padding
buffer_limit := glyph_draw_params.buffer_glyph_limit
batch_limit := glyph_draw_params.batch_glyph_limit
@ -314,7 +315,7 @@ startup :: proc( ctx : ^Context, parser_kind : Parser_Kind = .STB_TrueType,
batch_cache := & glyph_buffer.batch_cache
batch_cache.cap = i32(glyph_draw_params.batch_glyph_limit)
batch_cache.num = 0
batch_cache.table, error = make( map[Atlas_Region_Key]b8, uint(glyph_draw_params.shape_gen_scratch_reserve) )
batch_cache.table, error = make( map[Atlas_Key]b8, uint(glyph_draw_params.shape_gen_scratch_reserve) )
assert(error == .None, "VEFontCache.init : Failed to allocate batch_cache")
glyph_buffer.glyph_pack,error = make_soa( #soa[dynamic]Glyph_Pack_Entry, length = 0, capacity = 1 * Kilobyte )
@ -364,8 +365,8 @@ hot_reload :: proc( ctx : ^Context, allocator : Allocator )
lru_reload( & shape_cache.state, allocator )
for idx : i32 = 0; idx < i32(len(shape_cache.storage)); idx += 1 {
storage_entry := & shape_cache.storage[idx]
reload_array( & storage_entry.glyphs, allocator )
reload_array( & storage_entry.positions, allocator )
reload_array( & storage_entry.glyph_id, allocator )
reload_array( & storage_entry.position, allocator )
}
reload_array( & shape_cache.storage, allocator )
@ -412,8 +413,8 @@ shutdown :: proc( ctx : ^Context )
for idx : i32 = 0; idx < i32(len(shape_cache.storage)); idx += 1 {
storage_entry := & shape_cache.storage[idx]
delete( storage_entry.glyphs )
delete( storage_entry.positions )
delete( storage_entry.glyph_id )
delete( storage_entry.position )
}
lru_free( & shape_cache.state )
@ -447,8 +448,8 @@ clear_shape_cache :: proc (ctx : ^Context)
stroage_entry := & ctx.shape_cache.storage[idx]
stroage_entry.end_cursor_pos = {}
stroage_entry.size = {}
clear(& stroage_entry.glyphs)
clear(& stroage_entry.positions)
clear(& stroage_entry.glyph_id)
clear(& stroage_entry.position)
}
ctx.shape_cache.next_cache_id = 0
}
@ -665,7 +666,7 @@ draw_text_shape_normalized_space :: #force_inline proc( ctx : ^Context,
font_scale := parser_scale( entry.parser_info, px_size )
target_px_size := px_size * ctx.px_scalar
target_scale := scale * (1 / ctx.px_scalar)
target_scale := scale * (1 / ctx.px_scalar)
target_font_scale := parser_scale( entry.parser_info, target_px_size )
ctx.cursor_pos = generate_shape_draw_list( & ctx.draw_list, shape, & ctx.atlas, & ctx.glyph_buffer,
@ -704,16 +705,17 @@ draw_text_normalized_space :: #force_inline proc( ctx : ^Context,
entry := ctx.entries[ font ]
adjusted_position := get_snapped_position( ctx^, position )
colour := ctx.colour
colour.a = 1.0 + ctx.alpha_sharpen
// Does nothing when px_scalar is 1.0
target_px_size := px_size * ctx.px_scalar
target_scale := scale * (1 / ctx.px_scalar)
target_scale := scale * (1 / ctx.px_scalar)
target_font_scale := parser_scale( entry.parser_info, target_px_size )
shape := shaper_shape_text_cached( text_utf8, & ctx.shaper_ctx, & ctx.shape_cache,
shape := shaper_shape_text_cached( text_utf8, & ctx.shaper_ctx, & ctx.shape_cache, ctx.atlas, vec2(ctx.glyph_buffer.size),
font,
entry,
target_px_size,
@ -782,7 +784,11 @@ draw_text_layer :: #force_inline proc( ctx : ^Context, layer : []Text_Layer_Elem
target_font_scale := parser_scale( entry.parser_info, target_px_size )
assert( len(elem.text) > 0 )
shape := shaper_shape_text_cached( elem.text, & ctx.shaper_ctx, & ctx.shape_cache,
shape := shaper_shape_text_cached( elem.text,
& ctx.shaper_ctx,
& ctx.shape_cache,
ctx.atlas,
vec2(ctx.glyph_buffer.size),
elem.font,
entry,
target_px_size,
@ -871,7 +877,17 @@ measure_text_size :: #force_inline proc( ctx : ^Context, font : Font_ID, px_size
px_size_upscaled := px_size * ctx.px_scalar
font_scale_upscaled := parser_scale( entry.parser_info, px_size_upscaled )
shaped := shaper_shape_text_cached( text_utf8, & ctx.shaper_ctx, & ctx.shape_cache, font, entry, px_size_upscaled, font_scale_upscaled, shaper_shape_text_uncached_advanced )
shaped := shaper_shape_text_cached( text_utf8,
& ctx.shaper_ctx,
& ctx.shape_cache,
ctx.atlas,
vec2(ctx.glyph_buffer.size),
font,
entry,
px_size_upscaled,
font_scale_upscaled,
shaper_shape_text_uncached_advanced
)
return shaped.size * downscale
}
@ -905,7 +921,11 @@ shape_text_latin :: #force_inline proc( ctx : ^Context, font : Font_ID, px_size
px_size_upscaled := px_size * ctx.px_scalar
font_scale_upscaled := parser_scale( entry.parser_info, px_size_upscaled )
return shaper_shape_text_cached( text_utf8, & ctx.shaper_ctx, & ctx.shape_cache,
return shaper_shape_text_cached( text_utf8,
& ctx.shaper_ctx,
& ctx.shape_cache,
ctx.atlas,
vec2(ctx.glyph_buffer.size),
font,
entry,
px_size_upscaled,
@ -925,7 +945,11 @@ shape_text_advanced :: #force_inline proc( ctx : ^Context, font : Font_ID, px_si
px_size_upscaled := px_size * ctx.px_scalar
font_scale_upscaled := parser_scale( entry.parser_info, px_size_upscaled )
return shaper_shape_text_cached( text_utf8, & ctx.shaper_ctx, & ctx.shape_cache,
return shaper_shape_text_cached( text_utf8,
& ctx.shaper_ctx,
& ctx.shape_cache,
ctx.atlas,
vec2(ctx.glyph_buffer.size),
font,
entry,
px_size_upscaled,

View File

@ -15,7 +15,7 @@ set_profiler_module_context :: #force_inline proc "contextless" ( ctx : ^SpallPr
Module_Context = ctx
}
DISABLE_PROFILING :: true
DISABLE_PROFILING :: false
@(deferred_none = profile_end, disabled = DISABLE_PROFILING)
profile :: #force_inline proc "contextless" ( name : string, loc := #caller_location ) {

View File

@ -550,7 +550,7 @@ ui_settings_menu_builder :: proc( captures : rawptr = nil ) -> ( should_raise :
else
{
clear( input_str )
append( & input_str, to_runes(str_fmt("%v", config.text_size_canvas_scalar)))
append( & input_str, to_runes(str_fmt("%v", config.text_snap_glyph_positions)))
}
}
@ -608,7 +608,7 @@ ui_settings_menu_builder :: proc( captures : rawptr = nil ) -> ( should_raise :
else
{
clear( input_str )
append( & input_str, to_runes(str_fmt("%v", config.text_size_canvas_scalar)))
append( & input_str, to_runes(str_fmt("%v", config.text_alpha_sharpen)))
}
}
}

View File

@ -153,8 +153,8 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem
color_theme = App_Thm_Dusk
text_snap_glyph_positions = true
text_size_screen_scalar = 1.0
text_size_canvas_scalar = 1.0
text_size_screen_scalar = 2.0
text_size_canvas_scalar = 2.0
text_alpha_sharpen = 0.25
}
@ -526,7 +526,7 @@ tick_work_frame :: #force_inline proc( host_delta_time_ms : f64 ) -> b32
config := & get_state().config
debug := & get_state().debug
debug.draw_ui_box_bounds_points = true
debug.draw_ui_box_bounds_points = false
debug.draw_ui_padding_bounds = false
debug.draw_ui_content_bounds = false