LRU cache now as templated key type
Was testing to see if 16-bit cach emade a diff for the glyphs (it did not)
This commit is contained in:
parent
bf38087d8e
commit
a9080fe1f3
@ -6,17 +6,23 @@ The choice was made to keep the LRU cache implementation as close to the origina
|
||||
|
||||
import "base:runtime"
|
||||
|
||||
Pool_ListIter :: i32
|
||||
Pool_ListValue :: u32
|
||||
// 16-bit hashing was attempted, however it seems to get collisions with djb8_hash_16
|
||||
|
||||
Pool_List_Item :: struct {
|
||||
LRU_Fail_Mask_16 :: 0xFFFF
|
||||
LRU_Fail_Mask_32 :: 0xFFFFFFFF
|
||||
LRU_Fail_Mask_64 :: 0xFFFFFFFFFFFFFFFF
|
||||
|
||||
Pool_ListIter :: i32
|
||||
// Pool_ListValue :: LRU_Key
|
||||
|
||||
Pool_List_Item :: struct( $V_Type : typeid ) #packed {
|
||||
prev : Pool_ListIter,
|
||||
next : Pool_ListIter,
|
||||
value : Pool_ListValue,
|
||||
value : V_Type,
|
||||
}
|
||||
|
||||
Pool_List :: struct {
|
||||
items : [dynamic]Pool_List_Item,
|
||||
Pool_List :: struct( $V_Type : typeid) {
|
||||
items : [dynamic]Pool_List_Item(V_Type),
|
||||
free_list : [dynamic]Pool_ListIter,
|
||||
front : Pool_ListIter,
|
||||
back : Pool_ListIter,
|
||||
@ -25,10 +31,10 @@ Pool_List :: struct {
|
||||
dbg_name : string,
|
||||
}
|
||||
|
||||
pool_list_init :: proc( pool : ^Pool_List, capacity : i32, dbg_name : string = "" )
|
||||
pool_list_init :: proc( pool : ^Pool_List($V_Type), capacity : i32, dbg_name : string = "" )
|
||||
{
|
||||
error : Allocator_Error
|
||||
pool.items, error = make( [dynamic]Pool_List_Item, int(capacity) )
|
||||
pool.items, error = make( [dynamic]Pool_List_Item(V_Type), int(capacity) )
|
||||
assert( error == .None, "VEFontCache.pool_list_init : Failed to allocate items array")
|
||||
resize( & pool.items, capacity )
|
||||
|
||||
@ -52,17 +58,17 @@ pool_list_init :: proc( pool : ^Pool_List, capacity : i32, dbg_name : string = "
|
||||
pool.back = -1
|
||||
}
|
||||
|
||||
pool_list_free :: proc( pool : ^Pool_List ) {
|
||||
pool_list_free :: proc( pool : ^Pool_List($V_Type) ) {
|
||||
delete( pool.items)
|
||||
delete( pool.free_list)
|
||||
}
|
||||
|
||||
pool_list_reload :: proc( pool : ^Pool_List, allocator : Allocator ) {
|
||||
pool_list_reload :: proc( pool : ^Pool_List($V_Type), allocator : Allocator ) {
|
||||
reload_array( & pool.items, allocator )
|
||||
reload_array( & pool.free_list, allocator )
|
||||
}
|
||||
|
||||
pool_list_clear :: proc( pool: ^Pool_List )
|
||||
pool_list_clear :: proc( pool: ^Pool_List($V_Type) )
|
||||
{
|
||||
clear(& pool.items)
|
||||
clear(& pool.free_list)
|
||||
@ -82,7 +88,8 @@ pool_list_clear :: proc( pool: ^Pool_List )
|
||||
pool.size = 0
|
||||
}
|
||||
|
||||
pool_list_push_front :: proc( pool : ^Pool_List, value : Pool_ListValue )
|
||||
@(optimization_mode="favor_size")
|
||||
pool_list_push_front :: proc( pool : ^Pool_List($V_Type), value : V_Type ) #no_bounds_check
|
||||
{
|
||||
if pool.size >= pool.capacity do return
|
||||
|
||||
@ -108,7 +115,8 @@ pool_list_push_front :: proc( pool : ^Pool_List, value : Pool_ListValue )
|
||||
pool.size += 1
|
||||
}
|
||||
|
||||
pool_list_erase :: proc( pool : ^Pool_List, iter : Pool_ListIter )
|
||||
@(optimization_mode="favor_size")
|
||||
pool_list_erase :: proc( pool : ^Pool_List($V_Type), iter : Pool_ListIter ) #no_bounds_check
|
||||
{
|
||||
if pool.size <= 0 do return
|
||||
assert( iter >= 0 && iter < i32(pool.capacity) )
|
||||
@ -136,7 +144,8 @@ pool_list_erase :: proc( pool : ^Pool_List, iter : Pool_ListIter )
|
||||
}
|
||||
}
|
||||
|
||||
pool_list_move_to_front :: proc "contextless" ( pool : ^Pool_List, iter : Pool_ListIter )
|
||||
@(optimization_mode="favor_size")
|
||||
pool_list_move_to_front :: proc "contextless" ( pool : ^Pool_List($V_Type), iter : Pool_ListIter ) #no_bounds_check
|
||||
{
|
||||
if pool.front == iter do return
|
||||
|
||||
@ -151,13 +160,15 @@ pool_list_move_to_front :: proc "contextless" ( pool : ^Pool_List, iter : Pool_L
|
||||
pool.front = iter
|
||||
}
|
||||
|
||||
pool_list_peek_back :: #force_inline proc ( pool : Pool_List ) -> Pool_ListValue #no_bounds_check {
|
||||
@(optimization_mode="favor_size")
|
||||
pool_list_peek_back :: #force_inline proc ( pool : Pool_List($V_Type) ) -> V_Type #no_bounds_check {
|
||||
assert( pool.back != - 1 )
|
||||
value := pool.items[ pool.back ].value
|
||||
return value
|
||||
}
|
||||
|
||||
pool_list_pop_back :: #force_inline proc( pool : ^Pool_List ) -> Pool_ListValue {
|
||||
@(optimization_mode="favor_size")
|
||||
pool_list_pop_back :: #force_inline proc( pool : ^Pool_List($V_Type) ) -> V_Type #no_bounds_check {
|
||||
if pool.size <= 0 do return 0
|
||||
assert( pool.back != -1 )
|
||||
|
||||
@ -167,52 +178,50 @@ pool_list_pop_back :: #force_inline proc( pool : ^Pool_List ) -> Pool_ListValue
|
||||
}
|
||||
|
||||
LRU_Link :: struct {
|
||||
pad_top : u64,
|
||||
|
||||
value : i32,
|
||||
ptr : Pool_ListIter,
|
||||
|
||||
pad_bottom : u64,
|
||||
}
|
||||
|
||||
LRU_Cache :: struct {
|
||||
LRU_Cache :: struct( $Key_Type : typeid ) {
|
||||
capacity : i32,
|
||||
num : i32,
|
||||
table : map[u32]LRU_Link,
|
||||
key_queue : Pool_List,
|
||||
table : map[Key_Type]LRU_Link,
|
||||
key_queue : Pool_List(Key_Type),
|
||||
}
|
||||
|
||||
lru_init :: proc( cache : ^LRU_Cache, capacity : i32, dbg_name : string = "" ) {
|
||||
lru_init :: proc( cache : ^LRU_Cache($Key_Type), capacity : i32, dbg_name : string = "" ) {
|
||||
error : Allocator_Error
|
||||
cache.capacity = capacity
|
||||
cache.table, error = make( map[u32]LRU_Link, uint(capacity) )
|
||||
cache.table, error = make( map[Key_Type]LRU_Link, uint(capacity) )
|
||||
assert( error == .None, "VEFontCache.lru_init : Failed to allocate cache's table")
|
||||
|
||||
pool_list_init( & cache.key_queue, capacity, dbg_name = dbg_name )
|
||||
}
|
||||
}
|
||||
|
||||
lru_free :: proc( cache : ^LRU_Cache ) {
|
||||
lru_free :: proc( cache : ^LRU_Cache($Key_Type) ) {
|
||||
pool_list_free( & cache.key_queue )
|
||||
delete( cache.table )
|
||||
}
|
||||
|
||||
lru_reload :: #force_inline proc( cache : ^LRU_Cache, allocator : Allocator ) {
|
||||
lru_reload :: #force_inline proc( cache : ^LRU_Cache($Key_Type), allocator : Allocator ) {
|
||||
reload_map( & cache.table, allocator )
|
||||
pool_list_reload( & cache.key_queue, allocator )
|
||||
}
|
||||
|
||||
lru_clear :: proc ( cache : ^LRU_Cache ) {
|
||||
lru_clear :: proc ( cache : ^LRU_Cache($Key_Type) ) {
|
||||
pool_list_clear( & cache.key_queue )
|
||||
clear(& cache.table)
|
||||
cache.num = 0
|
||||
}
|
||||
|
||||
lru_find :: #force_inline proc "contextless" ( cache : LRU_Cache, key : u32, must_find := false ) -> (LRU_Link, bool) {
|
||||
@(optimization_mode="favor_size")
|
||||
lru_find :: #force_inline proc "contextless" ( cache : LRU_Cache($Key_Type), key : Key_Type, must_find := false ) -> (LRU_Link, bool) #no_bounds_check {
|
||||
link, success := cache.table[key]
|
||||
return link, success
|
||||
}
|
||||
|
||||
lru_get :: #force_inline proc ( cache: ^LRU_Cache, key : u32 ) -> i32 #no_bounds_check {
|
||||
@(optimization_mode="favor_size")
|
||||
lru_get :: #force_inline proc ( cache: ^LRU_Cache($Key_Type), key : Key_Type ) -> i32 #no_bounds_check {
|
||||
if link, ok := &cache.table[ key ]; ok {
|
||||
pool_list_move_to_front(&cache.key_queue, link.ptr)
|
||||
return link.value
|
||||
@ -220,15 +229,17 @@ lru_get :: #force_inline proc ( cache: ^LRU_Cache, key : u32 ) -> i32 #no_bounds
|
||||
return -1
|
||||
}
|
||||
|
||||
lru_get_next_evicted :: #force_inline proc ( cache : LRU_Cache ) -> u32 {
|
||||
@(optimization_mode="favor_size")
|
||||
lru_get_next_evicted :: #force_inline proc ( cache : LRU_Cache($Key_Type) ) -> Key_Type #no_bounds_check {
|
||||
if cache.key_queue.size >= cache.capacity {
|
||||
evict := pool_list_peek_back( cache.key_queue )
|
||||
return evict
|
||||
}
|
||||
return 0xFFFFFFFF
|
||||
return ~Key_Type(0)
|
||||
}
|
||||
|
||||
lru_peek :: #force_inline proc "contextless" ( cache : LRU_Cache, key : u32, must_find := false ) -> i32 {
|
||||
@(optimization_mode="favor_size")
|
||||
lru_peek :: #force_inline proc "contextless" ( cache : LRU_Cache($Key_Type), key : Key_Type, must_find := false ) -> i32 #no_bounds_check {
|
||||
iter, success := lru_find( cache, key, must_find )
|
||||
if success == false {
|
||||
return -1
|
||||
@ -236,7 +247,8 @@ lru_peek :: #force_inline proc "contextless" ( cache : LRU_Cache, key : u32, mus
|
||||
return iter.value
|
||||
}
|
||||
|
||||
lru_put :: #force_inline proc( cache : ^LRU_Cache, key : u32, value : i32 ) -> u32
|
||||
@(optimization_mode="favor_size")
|
||||
lru_put :: proc( cache : ^LRU_Cache($Key_Type), key : Key_Type, value : i32 ) -> Key_Type #no_bounds_check
|
||||
{
|
||||
// profile(#procedure)
|
||||
if link, ok := & cache.table[ key ]; ok {
|
||||
@ -261,7 +273,7 @@ lru_put :: #force_inline proc( cache : ^LRU_Cache, key : u32, value : i32 ) -> u
|
||||
return evict
|
||||
}
|
||||
|
||||
lru_refresh :: proc( cache : ^LRU_Cache, key : u32 ) {
|
||||
lru_refresh :: proc( cache : ^LRU_Cache($Key_Type), key : Key_Type ) {
|
||||
link, success := lru_find( cache ^, key )
|
||||
pool_list_erase( & cache.key_queue, link.ptr )
|
||||
pool_list_push_front( & cache.key_queue, key )
|
||||
|
@ -10,8 +10,10 @@ Atlas_Region_Kind :: enum u8 {
|
||||
Ignore = 0xFF, // ve_fontcache_cache_glyph_to_atlas uses a -1 value in clear draw call
|
||||
}
|
||||
|
||||
Atlas_Region_Key :: u32
|
||||
|
||||
Atlas_Region :: struct {
|
||||
state : LRU_Cache,
|
||||
state : LRU_Cache(Atlas_Region_Key),
|
||||
|
||||
size : Vec2i,
|
||||
capacity : Vec2i,
|
||||
@ -36,7 +38,19 @@ Atlas :: struct {
|
||||
size : Vec2i,
|
||||
}
|
||||
|
||||
atlas_region_bbox :: proc( region : Atlas_Region, local_idx : i32 ) -> (position, size: Vec2)
|
||||
|
||||
atlas_glyph_lru_code :: #force_inline proc "contextless" ( font : Font_ID, px_size : f32, glyph_index : Glyph ) -> (lru_code : Atlas_Region_Key) {
|
||||
// lru_code = u32(glyph_index) + ( ( 0x10000 * u32(font) ) & 0xFFFF0000 )
|
||||
font := font
|
||||
glyph_index := glyph_index
|
||||
px_size := px_size
|
||||
djb8_hash( & lru_code, to_bytes( & font) )
|
||||
djb8_hash( & lru_code, to_bytes( & glyph_index ) )
|
||||
djb8_hash( & lru_code, to_bytes( & px_size ) )
|
||||
return
|
||||
}
|
||||
|
||||
atlas_region_bbox :: #force_inline proc( region : Atlas_Region, local_idx : i32 ) -> (position, size: Vec2)
|
||||
{
|
||||
size = vec2(region.slot_size.x)
|
||||
|
||||
@ -65,7 +79,7 @@ atlas_decide_region :: #force_inline proc "contextless" (atlas : Atlas, glyph_bu
|
||||
}
|
||||
|
||||
// Grab an atlas LRU cache slot.
|
||||
atlas_reserve_slot :: #force_inline proc ( region : ^Atlas_Region, lru_code : u32 ) -> (atlas_index : i32)
|
||||
atlas_reserve_slot :: #force_inline proc ( region : ^Atlas_Region, lru_code : Atlas_Region_Key ) -> (atlas_index : i32)
|
||||
{
|
||||
if region.next_idx < region.state.capacity
|
||||
{
|
||||
@ -77,7 +91,7 @@ atlas_reserve_slot :: #force_inline proc ( region : ^Atlas_Region, lru_code : u3
|
||||
else
|
||||
{
|
||||
next_evict_codepoint := lru_get_next_evicted( region.state )
|
||||
assert( next_evict_codepoint != 0xFFFFFFFF)
|
||||
assert( next_evict_codepoint != LRU_Fail_Mask_16)
|
||||
|
||||
atlas_index = lru_peek( region.state, next_evict_codepoint, must_find = true )
|
||||
assert( atlas_index != -1 )
|
||||
|
@ -34,7 +34,7 @@ Glyph_Pack_Entry :: struct {
|
||||
position : Vec2,
|
||||
|
||||
index : Glyph,
|
||||
lru_code : u32,
|
||||
lru_code : Atlas_Region_Key,
|
||||
atlas_index : i32,
|
||||
in_atlas : b8,
|
||||
should_cache : b8,
|
||||
@ -92,7 +92,7 @@ Frame_Buffer_Pass :: enum u32 {
|
||||
}
|
||||
|
||||
Glyph_Batch_Cache :: struct {
|
||||
table : map[u32]b8,
|
||||
table : map[Atlas_Region_Key]b8,
|
||||
num : i32,
|
||||
cap : i32,
|
||||
}
|
||||
@ -115,6 +115,7 @@ Glyph_Draw_Buffer :: struct{
|
||||
cached : [dynamic]i32,
|
||||
}
|
||||
|
||||
@(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} )
|
||||
{
|
||||
// profile(#procedure)
|
||||
@ -149,12 +150,13 @@ blit_quad :: #force_inline proc ( draw_list : ^Draw_List, p0 : Vec2 = {0, 0}, p1
|
||||
}
|
||||
|
||||
// Constructs a triangle fan to fill a shape using the provided path outside_point represents the center point of the fan.
|
||||
construct_filled_path :: #force_inline proc( draw_list : ^Draw_List,
|
||||
@(optimization_mode="favor_size")
|
||||
construct_filled_path :: proc( draw_list : ^Draw_List,
|
||||
outside_point : Vec2,
|
||||
path : []Vertex,
|
||||
scale := Vec2 { 1, 1 },
|
||||
translate := Vec2 { 0, 0 }
|
||||
)
|
||||
) #no_bounds_check
|
||||
{
|
||||
// profile(#procedure)
|
||||
v_offset := cast(u32) len(draw_list.vertices)
|
||||
@ -185,12 +187,13 @@ construct_filled_path :: #force_inline proc( draw_list : ^Draw_List,
|
||||
}
|
||||
}
|
||||
|
||||
@(optimization_mode="favor_size")
|
||||
generate_glyph_pass_draw_list :: proc(draw_list : ^Draw_List, path : ^[dynamic]Vertex,
|
||||
glyph_shape : Parser_Glyph_Shape,
|
||||
curve_quality : f32,
|
||||
bounds : Range2,
|
||||
translate, scale : Vec2
|
||||
)
|
||||
) #no_bounds_check
|
||||
{
|
||||
profile(#procedure)
|
||||
outside := Vec2{bounds.p0.x - 21, bounds.p0.y - 33}
|
||||
@ -248,14 +251,15 @@ generate_glyph_pass_draw_list :: proc(draw_list : ^Draw_List, path : ^[dynamic]V
|
||||
}
|
||||
}
|
||||
|
||||
generate_shapes_draw_list :: proc ( ctx : ^Context, font : Font_ID, colour : Colour, entry : Entry, font_scale : f32, position, scale : Vec2, shapes : []Shaped_Text )
|
||||
generate_shapes_draw_list :: proc ( ctx : ^Context, font : Font_ID, colour : Colour, entry : Entry, px_size, font_scale : f32, position, scale : Vec2, shapes : []Shaped_Text )
|
||||
{
|
||||
assert(len(shapes) > 0)
|
||||
for shape in shapes {
|
||||
ctx.cursor_pos = {}
|
||||
ctx.cursor_pos = generate_shape_draw_list( & ctx.draw_list, shape, & ctx.atlas, & ctx.glyph_buffer, ctx.px_scalar,
|
||||
colour,
|
||||
entry,
|
||||
entry,
|
||||
px_size,
|
||||
font_scale,
|
||||
position,
|
||||
scale,
|
||||
@ -265,13 +269,15 @@ generate_shapes_draw_list :: proc ( ctx : ^Context, font : Font_ID, colour : Col
|
||||
}
|
||||
}
|
||||
|
||||
generate_shape_draw_list :: #force_no_inline proc( draw_list : ^Draw_List, shape : Shaped_Text,
|
||||
@(optimization_mode="favor_size")
|
||||
generate_shape_draw_list :: proc( draw_list : ^Draw_List, shape : Shaped_Text,
|
||||
atlas : ^Atlas,
|
||||
glyph_buffer : ^Glyph_Draw_Buffer,
|
||||
px_scalar : f32,
|
||||
|
||||
colour : Colour,
|
||||
entry : Entry,
|
||||
px_size : f32,
|
||||
font_scale : f32,
|
||||
|
||||
target_position : Vec2,
|
||||
@ -282,10 +288,10 @@ generate_shape_draw_list :: #force_no_inline proc( draw_list : ^Draw_List, shape
|
||||
{
|
||||
profile(#procedure)
|
||||
|
||||
font_scale := font_scale * px_scalar
|
||||
target_scale := target_scale / px_scalar
|
||||
// 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 : u32 ) {
|
||||
mark_glyph_seen :: #force_inline proc "contextless" ( cache : ^Glyph_Batch_Cache, lru_code : Atlas_Region_Key ) {
|
||||
cache.table[lru_code] = true
|
||||
cache.num += 1
|
||||
}
|
||||
@ -317,7 +323,7 @@ generate_shape_draw_list :: #force_no_inline proc( draw_list : ^Draw_List, shape
|
||||
for & glyph, index in glyph_pack
|
||||
{
|
||||
glyph.index = shape.glyphs[ index ]
|
||||
glyph.lru_code = font_glyph_lru_code(entry.id, glyph.index)
|
||||
glyph.lru_code = atlas_glyph_lru_code(entry.id, px_size, glyph.index)
|
||||
}
|
||||
profile_end()
|
||||
|
||||
@ -463,7 +469,7 @@ batch_generate_glyphs_draw_list :: proc ( draw_list : ^Draw_List,
|
||||
colour : Colour,
|
||||
font_scale : Vec2,
|
||||
target_scale : Vec2,
|
||||
)
|
||||
) #no_bounds_check
|
||||
{
|
||||
profile(#procedure)
|
||||
|
||||
@ -559,7 +565,6 @@ batch_generate_glyphs_draw_list :: proc ( draw_list : ^Draw_List,
|
||||
}
|
||||
profile_end()
|
||||
|
||||
|
||||
profile_begin("generate oversized glyphs draw_list")
|
||||
{
|
||||
when ENABLE_DRAW_TYPE_VIS {
|
||||
@ -722,7 +727,7 @@ batch_generate_glyphs_draw_list :: proc ( draw_list : ^Draw_List,
|
||||
}
|
||||
|
||||
// Flush the content of the glyph_buffers draw lists to the main draw list
|
||||
flush_glyph_buffer_draw_list :: #force_inline proc( #no_alias draw_list, glyph_buffer_draw_list, glyph_buffer_clear_draw_list : ^Draw_List, allocated_x : ^i32 )
|
||||
flush_glyph_buffer_draw_list :: proc( #no_alias draw_list, glyph_buffer_draw_list, glyph_buffer_clear_draw_list : ^Draw_List, allocated_x : ^i32 )
|
||||
{
|
||||
profile(#procedure)
|
||||
// if len(glyph_buffer_clear_draw_list.calls) == 0 || len(glyph_buffer_draw_list.calls) == 0 do return
|
||||
@ -743,6 +748,7 @@ flush_glyph_buffer_draw_list :: #force_inline proc( #no_alias draw_list, glyph_b
|
||||
}
|
||||
|
||||
// ve_fontcache_clear_Draw_List
|
||||
@(optimization_mode="favor_size")
|
||||
clear_draw_list :: #force_inline proc ( draw_list : ^Draw_List ) {
|
||||
clear( & draw_list.calls )
|
||||
clear( & draw_list.indices )
|
||||
@ -750,7 +756,8 @@ clear_draw_list :: #force_inline proc ( draw_list : ^Draw_List ) {
|
||||
}
|
||||
|
||||
// ve_fontcache_merge_Draw_List
|
||||
merge_draw_list :: proc ( #no_alias dst, src : ^Draw_List )
|
||||
@(optimization_mode="favor_size")
|
||||
merge_draw_list :: proc ( #no_alias dst, src : ^Draw_List ) #no_bounds_check
|
||||
{
|
||||
profile(#procedure)
|
||||
error : Allocator_Error
|
||||
@ -776,7 +783,7 @@ merge_draw_list :: proc ( #no_alias dst, src : ^Draw_List )
|
||||
}
|
||||
}
|
||||
|
||||
optimize_draw_list :: #force_inline proc (draw_list: ^Draw_List, call_offset: int)
|
||||
optimize_draw_list :: proc (draw_list: ^Draw_List, call_offset: int) #no_bounds_check
|
||||
{
|
||||
profile(#procedure)
|
||||
assert(draw_list != nil)
|
||||
|
@ -2,7 +2,7 @@ package vefontcache
|
||||
|
||||
import "base:runtime"
|
||||
import "core:hash"
|
||||
fnv64a :: hash.fnv64a
|
||||
ginger16 :: hash.ginger16
|
||||
import "core:math"
|
||||
ceil_f16 :: math.ceil_f16
|
||||
ceil_f16le :: math.ceil_f16le
|
||||
|
@ -21,13 +21,27 @@ reload_map :: #force_inline proc( self : ^map [$KeyType] $EntryType, allocator :
|
||||
raw.allocator = allocator
|
||||
}
|
||||
|
||||
font_glyph_lru_code :: #force_inline proc "contextless" ( font : Font_ID, glyph_index : Glyph ) -> (lru_code : u32) {
|
||||
lru_code = u32(glyph_index) + ( ( 0x10000 * u32(font) ) & 0xFFFF0000 )
|
||||
return
|
||||
}
|
||||
to_bytes :: #force_inline proc "contextless" ( typed_data : ^$Type ) -> []byte { return slice_ptr( transmute(^byte) typed_data, size_of(Type) ) }
|
||||
|
||||
djb8_hash_32 :: #force_inline proc "contextless" ( hash : ^u32, bytes : []byte ) { for value in bytes do (hash^) = (( (hash^) << 8) + (hash^) ) + u32(value) }
|
||||
djb8_hash :: #force_inline proc "contextless" ( hash : ^u64, bytes : []byte ) { for value in bytes do (hash^) = (( (hash^) << 8) + (hash^) ) + u64(value) }
|
||||
// Provides the nearest prime number value for the given capacity
|
||||
// closest_prime :: proc( capacity : uint ) -> uint
|
||||
// {
|
||||
// prime_table : []uint = {
|
||||
// 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593,
|
||||
// 49157, 98317, 196613, 393241, 786433, 1572869, 3145739,
|
||||
// 6291469, 12582917, 25165843, 50331653, 100663319,
|
||||
// 201326611, 402653189, 805306457, 1610612741, 3221225473, 6442450941
|
||||
// };
|
||||
// for slot in prime_table {
|
||||
// if slot >= capacity {
|
||||
// return slot
|
||||
// }
|
||||
// }
|
||||
// return prime_table[len(prime_table) - 1]
|
||||
// }
|
||||
|
||||
@(optimization_mode="favor_size")
|
||||
djb8_hash :: #force_inline proc "contextless" ( hash : ^$Type, bytes : []byte ) { for value in bytes do (hash^) = (( (hash^) << 8) + (hash^) ) + Type(value) }
|
||||
|
||||
Colour :: [4]f32
|
||||
Vec2 :: [2]f32
|
||||
@ -44,24 +58,25 @@ 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 )
|
||||
}
|
||||
|
||||
@(optimization_mode="favor_size")
|
||||
to_glyph_buffer_space :: #force_inline proc "contextless" ( #no_alias position, scale : ^Vec2, size : Vec2 )
|
||||
{
|
||||
pos := position^
|
||||
@ -75,6 +90,7 @@ to_glyph_buffer_space :: #force_inline proc "contextless" ( #no_alias position,
|
||||
(scale^) = scale_32
|
||||
}
|
||||
|
||||
@(optimization_mode="favor_size")
|
||||
to_target_space :: #force_inline proc "contextless" ( #no_alias position, scale : ^Vec2, size : Vec2 )
|
||||
{
|
||||
quotient : Vec2 = 1.0 / size
|
||||
@ -126,14 +142,17 @@ else
|
||||
{
|
||||
Vec2_SIMD :: simd.f32x4
|
||||
|
||||
@(optimization_mode="favor_size")
|
||||
vec2_to_simd :: #force_inline proc "contextless" (v: Vec2) -> Vec2_SIMD {
|
||||
return Vec2_SIMD{v.x, v.y, 0, 0}
|
||||
}
|
||||
|
||||
@(optimization_mode="favor_size")
|
||||
simd_to_vec2 :: #force_inline proc "contextless" (v: Vec2_SIMD) -> Vec2 {
|
||||
return Vec2{ simd.extract(v, 0), simd.extract(v, 1) }
|
||||
}
|
||||
|
||||
@(optimization_mode="favor_size")
|
||||
eval_point_on_bezier3 :: #force_inline proc "contextless" (p0, p1, p2: Vec2, alpha: f32) -> Vec2
|
||||
{
|
||||
simd_p0 := vec2_to_simd(p0)
|
||||
@ -157,6 +176,7 @@ else
|
||||
return simd_to_vec2(result)
|
||||
}
|
||||
|
||||
@(optimization_mode="favor_size")
|
||||
eval_point_on_bezier4 :: #force_inline proc "contextless" (p0, p1, p2, p3: Vec2, alpha: f32) -> Vec2
|
||||
{
|
||||
simd_p0 := vec2_to_simd(p0)
|
||||
|
@ -6,7 +6,7 @@ Note(Ed): The only reason I didn't directly use harfbuzz is because hamza exists
|
||||
import "core:c"
|
||||
import "thirdparty:harfbuzz"
|
||||
|
||||
shape_lru_code :: djb8_hash_32
|
||||
Shape_Key :: u32
|
||||
|
||||
Shaped_Text :: struct {
|
||||
glyphs : [dynamic]Glyph,
|
||||
@ -19,7 +19,7 @@ Shaped_Text :: struct {
|
||||
|
||||
Shaped_Text_Cache :: struct {
|
||||
storage : [dynamic]Shaped_Text,
|
||||
state : LRU_Cache,
|
||||
state : LRU_Cache(Shape_Key),
|
||||
next_cache_id : i32,
|
||||
}
|
||||
|
||||
@ -71,7 +71,8 @@ shaper_unload_font :: #force_inline proc( info : ^Shaper_Info )
|
||||
if info.blob != nil do harfbuzz.blob_destroy( info.blob )
|
||||
}
|
||||
|
||||
shaper_shape_harfbuzz :: #force_inline proc( ctx : ^Shaper_Context, text_utf8 : string, entry : Entry, font_px_Size, font_scale : f32, output :^Shaped_Text )
|
||||
@(optimization_mode="favor_size")
|
||||
shaper_shape_harfbuzz :: proc( ctx : ^Shaper_Context, text_utf8 : string, entry : Entry, font_px_Size, font_scale : f32, output :^Shaped_Text )
|
||||
{
|
||||
profile(#procedure)
|
||||
current_script := harfbuzz.Script.UNKNOWN
|
||||
@ -87,6 +88,8 @@ shaper_shape_harfbuzz :: #force_inline proc( ctx : ^Shaper_Context, text_utf8 :
|
||||
line_height := ((ascent - descent + line_gap) * font_scale)
|
||||
|
||||
position : Vec2
|
||||
|
||||
@(optimization_mode="favor_size")
|
||||
shape_run :: proc( output : ^Shaped_Text,
|
||||
entry : Entry,
|
||||
buffer : harfbuzz.Buffer,
|
||||
@ -241,7 +244,7 @@ shaper_shape_text_uncached_advanced :: #force_inline proc( ctx : ^Shaper_Context
|
||||
shaper_shape_harfbuzz( ctx, text_utf8, entry, font_px_size, font_scale, output )
|
||||
}
|
||||
|
||||
shaper_shape_text_latin :: #force_inline proc( ctx : ^Shaper_Context,
|
||||
shaper_shape_text_latin :: proc( ctx : ^Shaper_Context,
|
||||
entry : Entry,
|
||||
font_px_Size : f32,
|
||||
font_scale : f32,
|
||||
@ -305,7 +308,7 @@ shaper_shape_text_latin :: #force_inline proc( ctx : ^Shaper_Context,
|
||||
output.size.y = f32(line_count) * line_height
|
||||
}
|
||||
|
||||
shaper_shape_text_cached :: #force_inline proc( text_utf8 : string,
|
||||
shaper_shape_text_cached :: proc( text_utf8 : string,
|
||||
ctx : ^Shaper_Context,
|
||||
shape_cache : ^Shaped_Text_Cache,
|
||||
font : Font_ID,
|
||||
@ -316,13 +319,16 @@ shaper_shape_text_cached :: #force_inline proc( text_utf8 : string,
|
||||
) -> (shaped_text : Shaped_Text)
|
||||
{
|
||||
profile(#procedure)
|
||||
font := font
|
||||
font_bytes := slice_ptr( transmute(^byte) & font, size_of(Font_ID) )
|
||||
text_bytes := transmute( []byte) text_utf8
|
||||
font := font
|
||||
font_px_size := font_px_size
|
||||
font_bytes := to_bytes( & font )
|
||||
size_bytes := to_bytes( & font_px_size )
|
||||
text_bytes := transmute( []byte) text_utf8
|
||||
|
||||
lru_code : u32
|
||||
shape_lru_code( & lru_code, font_bytes )
|
||||
shape_lru_code( & lru_code, text_bytes )
|
||||
lru_code : Shape_Key
|
||||
djb8_hash( & lru_code, font_bytes )
|
||||
djb8_hash( & lru_code, size_bytes )
|
||||
djb8_hash( & lru_code, text_bytes )
|
||||
|
||||
state := & shape_cache.state
|
||||
|
||||
@ -337,7 +343,7 @@ shaper_shape_text_cached :: #force_inline proc( text_utf8 : string,
|
||||
else
|
||||
{
|
||||
next_evict_idx := lru_get_next_evicted( state ^ )
|
||||
assert( next_evict_idx != 0xFFFFFFFF )
|
||||
assert( next_evict_idx != LRU_Fail_Mask_32 )
|
||||
|
||||
shape_cache_idx = lru_peek( state ^, next_evict_idx, must_find = true )
|
||||
assert( shape_cache_idx != - 1 )
|
||||
|
@ -87,7 +87,7 @@ Init_Atlas_Params :: struct {
|
||||
}
|
||||
|
||||
Init_Atlas_Params_Default :: Init_Atlas_Params {
|
||||
size_multiplier = 2,
|
||||
size_multiplier = 1,
|
||||
glyph_padding = 1,
|
||||
}
|
||||
|
||||
@ -273,7 +273,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[u32]b8, uint(glyph_draw_params.shape_gen_scratch_reserve) )
|
||||
batch_cache.table, error = make( map[Atlas_Region_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 )
|
||||
@ -472,6 +472,7 @@ set_snap_glyph_pos :: #force_inline proc( ctx : ^Context, should_snap : b32 ) {
|
||||
ctx.shaper_ctx.snap_glyph_position = should_snap
|
||||
}
|
||||
|
||||
@(optimization_mode="favor_size")
|
||||
draw_text :: #force_inline proc( ctx : ^Context, font : Font_ID, px_size : f32, position, scale : Vec2, text_utf8 : string )
|
||||
{
|
||||
profile(#procedure)
|
||||
@ -499,16 +500,17 @@ draw_text :: #force_inline proc( ctx : ^Context, font : Font_ID, px_size : f32,
|
||||
shape := shaper_shape_text_cached( text_utf8, & ctx.shaper_ctx, & ctx.shape_cache,
|
||||
font,
|
||||
entry,
|
||||
px_size,
|
||||
font_scale,
|
||||
px_upscale,
|
||||
font_scale_upscale,
|
||||
shaper_shape_text_uncached_advanced
|
||||
)
|
||||
ctx.cursor_pos = generate_shape_draw_list( & ctx.draw_list, shape, & ctx.atlas, & ctx.glyph_buffer, ctx.px_scalar,
|
||||
colour,
|
||||
entry,
|
||||
font_scale,
|
||||
px_upscale,
|
||||
font_scale_upscale,
|
||||
position,
|
||||
scale,
|
||||
downscale,
|
||||
ctx.snap_width,
|
||||
ctx.snap_height
|
||||
)
|
||||
@ -543,14 +545,15 @@ draw_text_slice :: #force_inline proc( ctx : ^Context, font : Font_ID, px_size :
|
||||
assert( len(str) > 0 )
|
||||
shape := shaper_shape_text_cached( str, & ctx.shaper_ctx, & ctx.shape_cache,
|
||||
font,
|
||||
entry,
|
||||
entry,
|
||||
px_upscale,
|
||||
font_scale,
|
||||
font_scale_upscale,
|
||||
shaper_shape_text_uncached_advanced
|
||||
)
|
||||
shapes[id] = shape
|
||||
}
|
||||
generate_shapes_draw_list(ctx, font, colour, entry, font_scale, position, scale, shapes )
|
||||
|
||||
generate_shapes_draw_list(ctx, font, colour, entry, px_upscale, font_scale_upscale, position, downscale, shapes )
|
||||
}
|
||||
|
||||
|
||||
@ -578,6 +581,7 @@ draw_text_slice :: #force_inline proc( ctx : ^Context, font : Font_ID, px_size :
|
||||
// }
|
||||
|
||||
// Resolve the shape and track it to reduce iteration overhead
|
||||
@(optimization_mode="favor_size")
|
||||
draw_text_shape :: #force_inline proc( ctx : ^Context, font : Font_ID, px_size : f32, position, scale : Vec2, shape : Shaped_Text )
|
||||
{
|
||||
profile(#procedure)
|
||||
@ -601,9 +605,10 @@ draw_text_shape :: #force_inline proc( ctx : ^Context, font : Font_ID, px_size :
|
||||
ctx.cursor_pos = generate_shape_draw_list( & ctx.draw_list, shape, & ctx.atlas, & ctx.glyph_buffer, ctx.px_scalar,
|
||||
colour,
|
||||
entry,
|
||||
font_scale,
|
||||
px_upscale,
|
||||
font_scale_upscale,
|
||||
position,
|
||||
scale,
|
||||
downscale,
|
||||
ctx.snap_width,
|
||||
ctx.snap_height
|
||||
)
|
||||
@ -668,11 +673,12 @@ measure_text_size :: #force_inline proc( ctx : ^Context, font : Font_ID, px_size
|
||||
assert( font >= 0 && int(font) < len(ctx.entries) )
|
||||
|
||||
entry := ctx.entries[font]
|
||||
|
||||
font_scale := parser_scale( entry.parser_info, px_size )
|
||||
|
||||
px_size_upscaled := px_size * ctx.px_scalar
|
||||
font_scale_upscaled := parser_scale( entry.parser_info, px_size_upscaled )
|
||||
|
||||
// font_scale := parser_scale( entry.parser_info, px_size )
|
||||
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 )
|
||||
return shaped.size
|
||||
}
|
||||
@ -714,7 +720,7 @@ shape_text_latin :: #force_inline proc( ctx : ^Context, font : Font_ID, px_size
|
||||
return shaper_shape_text_cached( text_utf8, & ctx.shaper_ctx, & ctx.shape_cache,
|
||||
font,
|
||||
entry,
|
||||
px_size_upscaled,
|
||||
px_size,
|
||||
font_scale_upscaled,
|
||||
shaper_shape_text_latin
|
||||
)
|
||||
@ -734,7 +740,7 @@ shape_text_advanced :: #force_inline proc( ctx : ^Context, font : Font_ID, px_si
|
||||
return shaper_shape_text_cached( text_utf8, & ctx.shaper_ctx, & ctx.shape_cache,
|
||||
font,
|
||||
entry,
|
||||
px_size_upscaled,
|
||||
px_size,
|
||||
font_scale_upscaled,
|
||||
shaper_shape_text_uncached_advanced
|
||||
)
|
||||
|
@ -35,7 +35,8 @@ import "core:container/queue"
|
||||
import "core:dynlib"
|
||||
|
||||
import "core:hash"
|
||||
crc32 :: hash.crc32
|
||||
ginger16 :: hash.ginger16
|
||||
crc32 :: hash.crc32
|
||||
|
||||
import "core:hash/xxhash"
|
||||
xxh32 :: xxhash.XXH32
|
||||
|
@ -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 ) {
|
||||
|
@ -354,8 +354,8 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem
|
||||
|
||||
// debug.path_lorem = str_fmt("C:/projects/SectrPrototype/examples/Lorem Ipsum (197).txt", allocator = persistent_slab_allocator())
|
||||
// debug.path_lorem = str_fmt("C:/projects/SectrPrototype/examples/Lorem Ipsum (1022).txt", allocator = persistent_slab_allocator())
|
||||
// debug.path_lorem = str_fmt("C:/projects/SectrPrototype/examples/sokol_gp.h", allocator = persistent_slab_allocator())
|
||||
debug.path_lorem = str_fmt("C:/projects/SectrPrototype/examples/ve_fontcache.h", allocator = persistent_slab_allocator())
|
||||
debug.path_lorem = str_fmt("C:/projects/SectrPrototype/examples/sokol_gp.h", allocator = persistent_slab_allocator())
|
||||
// debug.path_lorem = str_fmt("C:/projects/SectrPrototype/examples/ve_fontcache.h", allocator = persistent_slab_allocator())
|
||||
|
||||
alloc_error : AllocatorError; success : bool
|
||||
debug.lorem_content, success = os.read_entire_file( debug.path_lorem, persistent_slab_allocator() )
|
||||
@ -528,8 +528,8 @@ tick_work_frame :: #force_inline proc( host_delta_time_ms : f64 ) -> b32
|
||||
debug.draw_ui_padding_bounds = false
|
||||
debug.draw_ui_content_bounds = false
|
||||
|
||||
font_provider_set_alpha_sharpen(0.15)
|
||||
font_provider_set_snap_glyph_pos(false)
|
||||
font_provider_set_alpha_sharpen(0.25)
|
||||
font_provider_set_snap_glyph_pos(true)
|
||||
|
||||
// config.engine_refresh_hz = 165
|
||||
|
||||
|
@ -57,6 +57,7 @@ render_mode_2d_workspace :: proc( screen_extent : Vec2, cam : Camera, input : In
|
||||
screen_size := screen_extent * 2
|
||||
|
||||
// TODO(Ed): Eventually will be the viewport extents
|
||||
ve.set_px_scalar( ve_ctx, app_config().font_size_canvas_scalar )
|
||||
ve.configure_snap( ve_ctx, u32(screen_size.x), u32(screen_size.y) )
|
||||
// ve.configure_snap( ve_ctx, 0, 0 )
|
||||
|
||||
@ -122,6 +123,7 @@ render_mode_screenspace :: proc( screen_extent : Extents2, screen_ui : ^UI_State
|
||||
screen_size := screen_extent * 2
|
||||
screen_ratio := screen_size.x * ( 1.0 / screen_size.y )
|
||||
|
||||
ve.set_px_scalar( ve_ctx, app_config().font_size_screen_scalar )
|
||||
ve.configure_snap( ve_ctx, u32(screen_size.x), u32(screen_size.y) )
|
||||
|
||||
render_screen_ui( screen_extent, screen_ui, ve_ctx, ve_render )
|
||||
@ -917,12 +919,18 @@ draw_text_string_pos_norm :: #force_inline proc( text : string, id : FontID, fon
|
||||
width := app_window.extent.x * 2
|
||||
height := app_window.extent.y * 2
|
||||
|
||||
ve_id, resolved_size := font_provider_resolve_draw_id( id, font_size )
|
||||
// over_sample : f32 = f32(config.font_size_screen_scalar)
|
||||
|
||||
target_size := font_size
|
||||
// target_size *= over_sample
|
||||
|
||||
ve_id, resolved_size := font_provider_resolve_draw_id( id, target_size )
|
||||
color_norm := normalize_rgba8(color)
|
||||
|
||||
screen_size_norm := 1 / Vec2 { width, height }
|
||||
|
||||
draw_scale := screen_size_norm * scale
|
||||
// draw_scale /= over_sample
|
||||
|
||||
// ve.set_px_scalar( & font_provider_ctx.ve_ctx, config.font_size_screen_scalar )
|
||||
ve.set_colour( & font_provider_ctx.ve_ctx, color_norm )
|
||||
@ -938,6 +946,7 @@ draw_text_string_pos_extent :: #force_inline proc( text : string, id : FontID, f
|
||||
screen_size := app_window.extent * 2
|
||||
render_pos := screen_to_render_pos(pos)
|
||||
normalized_pos := render_pos * (1.0 / screen_size)
|
||||
|
||||
draw_text_string_pos_norm( text, id, font_size, normalized_pos, color )
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,8 @@ FontID :: struct {
|
||||
FontDef :: struct {
|
||||
path_file : string,
|
||||
default_size : i32,
|
||||
size_table : [Font_Largest_Px_Size / Font_Size_Interval] ve.Font_ID,
|
||||
ve_id : ve.Font_ID
|
||||
// size_table : [Font_Largest_Px_Size / Font_Size_Interval] ve.Font_ID,
|
||||
}
|
||||
|
||||
FontProviderContext :: struct
|
||||
@ -76,6 +77,7 @@ font_load :: proc(path_file : string,
|
||||
profile(msg)
|
||||
log(msg)
|
||||
|
||||
|
||||
font_data, read_succeded : = os.read_entire_file( path_file, persistent_allocator() )
|
||||
verify( b32(read_succeded), str_fmt("Failed to read font file for: %v", path_file) )
|
||||
font_data_size := cast(i32) len(font_data)
|
||||
@ -103,14 +105,8 @@ font_load :: proc(path_file : string,
|
||||
def.path_file = path_file
|
||||
def.default_size = default_size
|
||||
|
||||
for font_size : i32 = clamp( Font_Size_Interval, 2, Font_Size_Interval ); font_size <= Font_Largest_Px_Size; font_size += Font_Size_Interval
|
||||
{
|
||||
// logf("Loading at size %v", font_size)
|
||||
id := (font_size / Font_Size_Interval) + (font_size % Font_Size_Interval)
|
||||
ve_id := & def.size_table[id - 1]
|
||||
ve_ret_id, error := ve.load_font( & ve_ctx, desired_id, font_data )
|
||||
(ve_id^) = ve_ret_id
|
||||
}
|
||||
error : ve.Load_Font_Error
|
||||
def.ve_id, error = ve.load_font( & ve_ctx, desired_id, font_data )
|
||||
|
||||
fid := FontID { key, desired_id }
|
||||
return fid
|
||||
@ -118,20 +114,14 @@ font_load :: proc(path_file : string,
|
||||
|
||||
font_provider_set_alpha_sharpen :: #force_inline proc( scalar : f32 ) {
|
||||
ve.set_alpha_scalar( & get_state().font_provider_ctx.ve_ctx, scalar )
|
||||
// ve.clear_atlas_region_caches(& ctx.ve_ctx)
|
||||
// ve.clear_shape_cache(& ctx.ve_ctx)
|
||||
}
|
||||
|
||||
font_provider_set_px_scalar :: #force_inline proc( scalar : f32 ) {
|
||||
ve.set_px_scalar( & get_state().font_provider_ctx.ve_ctx, scalar )
|
||||
// ve.clear_atlas_region_caches(& ctx.ve_ctx)
|
||||
// ve.clear_shape_cache(& ctx.ve_ctx)
|
||||
}
|
||||
|
||||
font_provider_set_snap_glyph_pos :: #force_inline proc( should_snap : b32 ) {
|
||||
ve.set_snap_glyph_pos( & get_state().font_provider_ctx.ve_ctx, should_snap )
|
||||
// ve.clear_atlas_region_caches(& ctx.ve_ctx)
|
||||
// ve.clear_shape_cache(& ctx.ve_ctx)
|
||||
}
|
||||
|
||||
Font_Use_Default_Size :: f32(0.0)
|
||||
@ -146,7 +136,7 @@ font_provider_resolve_draw_id :: #force_inline proc( id : FontID, size := Font_U
|
||||
resolved_size = clamp( i32( even_size), 2, Font_Largest_Px_Size )
|
||||
|
||||
id := (resolved_size / Font_Size_Interval) + (resolved_size % Font_Size_Interval)
|
||||
ve_id = def.size_table[ id - 1 ]
|
||||
ve_id = def.ve_id
|
||||
return
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user