mirror of
https://github.com/Ed94/VEFontCache-Odin.git
synced 2025-08-05 14:42:42 -07:00
Formating, name changes (making identifiers more idiomatic)
This commit is contained in:
@@ -41,7 +41,7 @@ COLOR_WHITE :: RGBA8 { 255, 255, 255, 255 }
|
|||||||
FONT_LARGEST_PIXEL_SIZE :: 400
|
FONT_LARGEST_PIXEL_SIZE :: 400
|
||||||
FONT_SIZE_INTERVAL :: 2
|
FONT_SIZE_INTERVAL :: 2
|
||||||
|
|
||||||
FONT_DEFAULT :: FontID { "" }
|
FONT_DEFAULT :: Font_ID { "" }
|
||||||
FONT_DEFAULT_SIZEZ :: 12.0
|
FONT_DEFAULT_SIZEZ :: 12.0
|
||||||
|
|
||||||
FONT_LOAD_USE_DEFAULT_SIZE :: -1
|
FONT_LOAD_USE_DEFAULT_SIZE :: -1
|
||||||
@@ -52,17 +52,17 @@ PATH_FONTS :: "../fonts/"
|
|||||||
|
|
||||||
OVER_SAMPLE_ZOOM : f32 : 2.0 // Adjust this value as needed, used by draw_text_zoomed_norm
|
OVER_SAMPLE_ZOOM : f32 : 2.0 // Adjust this value as needed, used by draw_text_zoomed_norm
|
||||||
|
|
||||||
FontID :: struct {
|
Font_ID :: struct {
|
||||||
label : string,
|
label : string,
|
||||||
}
|
}
|
||||||
|
|
||||||
FontDef :: struct {
|
FontDef :: struct {
|
||||||
path_file : string,
|
path_file : string,
|
||||||
default_size : i32,
|
default_size : i32,
|
||||||
size_table : [FONT_LARGEST_PIXEL_SIZE / FONT_SIZE_INTERVAL] ve.FontID,
|
size_table : [FONT_LARGEST_PIXEL_SIZE / FONT_SIZE_INTERVAL] ve.Font_ID,
|
||||||
}
|
}
|
||||||
|
|
||||||
DemoContext :: struct {
|
Demo_Context :: struct {
|
||||||
ve_ctx : ve.Context,
|
ve_ctx : ve.Context,
|
||||||
render_ctx : ve_sokol.Context,
|
render_ctx : ve_sokol.Context,
|
||||||
font_ids : map[string]FontDef,
|
font_ids : map[string]FontDef,
|
||||||
@@ -70,43 +70,43 @@ DemoContext :: struct {
|
|||||||
// Values between 1, & -1 on Y axis
|
// Values between 1, & -1 on Y axis
|
||||||
mouse_scroll : Vec2,
|
mouse_scroll : Vec2,
|
||||||
|
|
||||||
font_firacode : FontID,
|
font_firacode : Font_ID,
|
||||||
font_logo : FontID,
|
font_logo : Font_ID,
|
||||||
font_title : FontID,
|
font_title : Font_ID,
|
||||||
font_print : FontID,
|
font_print : Font_ID,
|
||||||
font_mono : FontID,
|
font_mono : Font_ID,
|
||||||
font_small : FontID,
|
font_small : Font_ID,
|
||||||
font_demo_sans : FontID,
|
font_demo_sans : Font_ID,
|
||||||
font_demo_serif : FontID,
|
font_demo_serif : Font_ID,
|
||||||
font_demo_script : FontID,
|
font_demo_script : Font_ID,
|
||||||
font_demo_mono : FontID,
|
font_demo_mono : Font_ID,
|
||||||
font_demo_chinese : FontID,
|
font_demo_chinese : Font_ID,
|
||||||
font_demo_japanese : FontID,
|
font_demo_japanese : Font_ID,
|
||||||
font_demo_korean : FontID,
|
font_demo_korean : Font_ID,
|
||||||
font_demo_thai : FontID,
|
font_demo_thai : Font_ID,
|
||||||
font_demo_arabic : FontID,
|
font_demo_arabic : Font_ID,
|
||||||
font_demo_hebrew : FontID,
|
font_demo_hebrew : Font_ID,
|
||||||
font_demo_raincode : FontID,
|
font_demo_raincode : Font_ID,
|
||||||
font_demo_grid2 : FontID,
|
font_demo_grid2 : Font_ID,
|
||||||
font_demo_grid3 : FontID,
|
font_demo_grid3 : Font_ID,
|
||||||
|
|
||||||
screen_size : [2]f32,
|
screen_size : [2]f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
demo_ctx : DemoContext
|
demo_ctx : Demo_Context
|
||||||
|
|
||||||
font_load :: proc(path_file : string,
|
font_load :: proc(path_file : string,
|
||||||
default_size : i32 = FONT_LOAD_USE_DEFAULT_SIZE,
|
default_size : i32 = FONT_LOAD_USE_DEFAULT_SIZE,
|
||||||
desired_id : string = FONT_LOAD_GEN_ID,
|
desired_id : string = FONT_LOAD_GEN_ID,
|
||||||
curve_quality : u32 = 3,
|
curve_quality : u32 = 3,
|
||||||
) -> FontID
|
) -> Font_ID
|
||||||
{
|
{
|
||||||
msg := fmt.println("Loading font: %v", path_file)
|
msg := fmt.println("Loading font: %v", path_file)
|
||||||
|
|
||||||
font_data, read_succeded : = os.read_entire_file( path_file )
|
font_data, read_succeded : = os.read_entire_file( path_file )
|
||||||
assert( bool(read_succeded), fmt.tprintf("Failed to read font file for: %v", path_file) )
|
assert( bool(read_succeded), fmt.tprintf("Failed to read font file for: %v", path_file) )
|
||||||
font_data_size := cast(i32) len(font_data)
|
font_data_size := cast(i32) len(font_data)
|
||||||
font_firacode : FontID
|
font_firacode : Font_ID
|
||||||
|
|
||||||
|
|
||||||
desired_id := desired_id
|
desired_id := desired_id
|
||||||
@@ -134,13 +134,13 @@ font_firacode : FontID
|
|||||||
(ve_id^) = ve_ret_id
|
(ve_id^) = ve_ret_id
|
||||||
}
|
}
|
||||||
|
|
||||||
fid := FontID { desired_id }
|
fid := Font_ID { desired_id }
|
||||||
return fid
|
return fid
|
||||||
}
|
}
|
||||||
|
|
||||||
Font_Use_Default_Size :: f32(0.0)
|
Font_Use_Default_Size :: f32(0.0)
|
||||||
|
|
||||||
font_resolve_draw_id :: proc( id : FontID, size := Font_Use_Default_Size ) -> ( ve_id : ve.FontID, resolved_size : i32 )
|
font_resolve_draw_id :: proc( id : Font_ID, size := Font_Use_Default_Size ) -> ( ve_id : ve.Font_ID, resolved_size : i32 )
|
||||||
{
|
{
|
||||||
def := demo_ctx.font_ids[ id.label ]
|
def := demo_ctx.font_ids[ id.label ]
|
||||||
size := size == 0.0 ? f32(def.default_size) : size
|
size := size == 0.0 ? f32(def.default_size) : size
|
||||||
@@ -152,14 +152,14 @@ font_resolve_draw_id :: proc( id : FontID, size := Font_Use_Default_Size ) -> (
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
measure_text_size :: proc( text : string, font : FontID, font_size := Font_Use_Default_Size, spacing : f32 ) -> Vec2
|
measure_text_size :: proc( text : string, font : Font_ID, font_size := Font_Use_Default_Size, spacing : f32 ) -> Vec2
|
||||||
{
|
{
|
||||||
ve_id, size := font_resolve_draw_id( font, font_size )
|
ve_id, size := font_resolve_draw_id( font, font_size )
|
||||||
measured := ve.measure_text_size( & demo_ctx.ve_ctx, ve_id, text )
|
measured := ve.measure_text_size( & demo_ctx.ve_ctx, ve_id, text )
|
||||||
return measured
|
return measured
|
||||||
}
|
}
|
||||||
|
|
||||||
get_font_vertical_metrics :: #force_inline proc ( font : FontID, font_size := Font_Use_Default_Size ) -> ( ascent, descent, line_gap : f32 )
|
get_font_vertical_metrics :: #force_inline proc ( font : Font_ID, font_size := Font_Use_Default_Size ) -> ( ascent, descent, line_gap : f32 )
|
||||||
{
|
{
|
||||||
ve_id, size := font_resolve_draw_id( font, font_size )
|
ve_id, size := font_resolve_draw_id( font, font_size )
|
||||||
ascent, descent, line_gap = ve.get_font_vertical_metrics( & demo_ctx.ve_ctx, ve_id )
|
ascent, descent, line_gap = ve.get_font_vertical_metrics( & demo_ctx.ve_ctx, ve_id )
|
||||||
@@ -167,7 +167,7 @@ get_font_vertical_metrics :: #force_inline proc ( font : FontID, font_size := Fo
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Draw text using a string and normalized render coordinates
|
// Draw text using a string and normalized render coordinates
|
||||||
draw_text_string_pos_norm :: proc( content : string, id : FontID, size : f32, pos : Vec2, color := COLOR_WHITE, scale : f32 = 1.0 )
|
draw_text_string_pos_norm :: proc( content : string, id : Font_ID, size : f32, pos : Vec2, color := COLOR_WHITE, scale : f32 = 1.0 )
|
||||||
{
|
{
|
||||||
width := demo_ctx.screen_size.x
|
width := demo_ctx.screen_size.x
|
||||||
height := demo_ctx.screen_size.y
|
height := demo_ctx.screen_size.y
|
||||||
@@ -181,14 +181,14 @@ draw_text_string_pos_norm :: proc( content : string, id : FontID, size : f32, po
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Draw text using a string and extent-based screen coordinates
|
// Draw text using a string and extent-based screen coordinates
|
||||||
draw_text_string_pos_extent :: proc( content : string, id : FontID, size : f32, pos : Vec2, color := COLOR_WHITE ) {
|
draw_text_string_pos_extent :: proc( content : string, id : Font_ID, size : f32, pos : Vec2, color := COLOR_WHITE ) {
|
||||||
render_pos := pos + demo_ctx.screen_size * 0.5
|
render_pos := pos + demo_ctx.screen_size * 0.5
|
||||||
normalized_pos := render_pos * (1.0 / demo_ctx.screen_size)
|
normalized_pos := render_pos * (1.0 / demo_ctx.screen_size)
|
||||||
draw_text_string_pos_norm( content, id, size, normalized_pos, color )
|
draw_text_string_pos_norm( content, id, size, normalized_pos, color )
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adapt the draw_text_string_pos_extent_zoomed procedure
|
// Adapt the draw_text_string_pos_extent_zoomed procedure
|
||||||
draw_text_zoomed_norm :: proc(content : string, id : FontID, size : f32, pos : Vec2, zoom : f32, color := COLOR_WHITE)
|
draw_text_zoomed_norm :: proc(content : string, id : Font_ID, size : f32, pos : Vec2, zoom : f32, color := COLOR_WHITE)
|
||||||
{
|
{
|
||||||
screen_size := demo_ctx.screen_size
|
screen_size := demo_ctx.screen_size
|
||||||
screen_scale := Vec2{1.0 / screen_size.x, 1.0 / screen_size.y}
|
screen_scale := Vec2{1.0 / screen_size.x, 1.0 / screen_size.y}
|
||||||
|
@@ -6,33 +6,33 @@ The choice was made to keep the LRU cache implementation as close to the origina
|
|||||||
|
|
||||||
import "base:runtime"
|
import "base:runtime"
|
||||||
|
|
||||||
PoolListIter :: i32
|
Pool_ListIter :: i32
|
||||||
PoolListValue :: u64
|
Pool_ListValue :: u64
|
||||||
|
|
||||||
PoolListItem :: struct {
|
Pool_List_Item :: struct {
|
||||||
prev : PoolListIter,
|
prev : Pool_ListIter,
|
||||||
next : PoolListIter,
|
next : Pool_ListIter,
|
||||||
value : PoolListValue,
|
value : Pool_ListValue,
|
||||||
}
|
}
|
||||||
|
|
||||||
PoolList :: struct {
|
Pool_List :: struct {
|
||||||
items : [dynamic]PoolListItem,
|
items : [dynamic]Pool_List_Item,
|
||||||
free_list : [dynamic]PoolListIter,
|
free_list : [dynamic]Pool_ListIter,
|
||||||
front : PoolListIter,
|
front : Pool_ListIter,
|
||||||
back : PoolListIter,
|
back : Pool_ListIter,
|
||||||
size : i32,
|
size : i32,
|
||||||
capacity : i32,
|
capacity : i32,
|
||||||
dbg_name : string,
|
dbg_name : string,
|
||||||
}
|
}
|
||||||
|
|
||||||
pool_list_init :: proc( pool : ^PoolList, capacity : i32, dbg_name : string = "" )
|
pool_list_init :: proc( pool : ^Pool_List, capacity : i32, dbg_name : string = "" )
|
||||||
{
|
{
|
||||||
error : AllocatorError
|
error : Allocator_Error
|
||||||
pool.items, error = make( [dynamic]PoolListItem, int(capacity) )
|
pool.items, error = make( [dynamic]Pool_List_Item, int(capacity) )
|
||||||
assert( error == .None, "VEFontCache.pool_list_init : Failed to allocate items array")
|
assert( error == .None, "VEFontCache.pool_list_init : Failed to allocate items array")
|
||||||
resize( & pool.items, capacity )
|
resize( & pool.items, capacity )
|
||||||
|
|
||||||
pool.free_list, error = make( [dynamic]PoolListIter, len = 0, cap = int(capacity) )
|
pool.free_list, error = make( [dynamic]Pool_ListIter, len = 0, cap = int(capacity) )
|
||||||
assert( error == .None, "VEFontCache.pool_list_init : Failed to allocate free_list array")
|
assert( error == .None, "VEFontCache.pool_list_init : Failed to allocate free_list array")
|
||||||
resize( & pool.free_list, capacity )
|
resize( & pool.free_list, capacity )
|
||||||
|
|
||||||
@@ -53,17 +53,17 @@ pool_list_init :: proc( pool : ^PoolList, capacity : i32, dbg_name : string = ""
|
|||||||
back = -1
|
back = -1
|
||||||
}
|
}
|
||||||
|
|
||||||
pool_list_free :: proc( pool : ^PoolList ) {
|
pool_list_free :: proc( pool : ^Pool_List ) {
|
||||||
delete( pool.items)
|
delete( pool.items)
|
||||||
delete( pool.free_list)
|
delete( pool.free_list)
|
||||||
}
|
}
|
||||||
|
|
||||||
pool_list_reload :: proc( pool : ^PoolList, allocator : Allocator ) {
|
pool_list_reload :: proc( pool : ^Pool_List, allocator : Allocator ) {
|
||||||
reload_array( & pool.items, allocator )
|
reload_array( & pool.items, allocator )
|
||||||
reload_array( & pool.free_list, allocator )
|
reload_array( & pool.free_list, allocator )
|
||||||
}
|
}
|
||||||
|
|
||||||
pool_list_push_front :: proc( pool : ^PoolList, value : PoolListValue )
|
pool_list_push_front :: proc( pool : ^Pool_List, value : Pool_ListValue )
|
||||||
{
|
{
|
||||||
using pool
|
using pool
|
||||||
if size >= capacity do return
|
if size >= capacity do return
|
||||||
@@ -90,7 +90,7 @@ pool_list_push_front :: proc( pool : ^PoolList, value : PoolListValue )
|
|||||||
size += 1
|
size += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
pool_list_erase :: proc( pool : ^PoolList, iter : PoolListIter )
|
pool_list_erase :: proc( pool : ^Pool_List, iter : Pool_ListIter )
|
||||||
{
|
{
|
||||||
using pool
|
using pool
|
||||||
if size <= 0 do return
|
if size <= 0 do return
|
||||||
@@ -119,7 +119,7 @@ pool_list_erase :: proc( pool : ^PoolList, iter : PoolListIter )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pool_list_move_to_front :: #force_inline proc( pool : ^PoolList, iter : PoolListIter )
|
pool_list_move_to_front :: #force_inline proc( pool : ^Pool_List, iter : Pool_ListIter )
|
||||||
{
|
{
|
||||||
using pool
|
using pool
|
||||||
|
|
||||||
@@ -136,13 +136,13 @@ pool_list_move_to_front :: #force_inline proc( pool : ^PoolList, iter : PoolList
|
|||||||
front = iter
|
front = iter
|
||||||
}
|
}
|
||||||
|
|
||||||
pool_list_peek_back :: #force_inline proc ( pool : ^PoolList ) -> PoolListValue {
|
pool_list_peek_back :: #force_inline proc ( pool : ^Pool_List ) -> Pool_ListValue {
|
||||||
assert( pool.back != - 1 )
|
assert( pool.back != - 1 )
|
||||||
value := pool.items[ pool.back ].value
|
value := pool.items[ pool.back ].value
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
pool_list_pop_back :: #force_inline proc( pool : ^PoolList ) -> PoolListValue {
|
pool_list_pop_back :: #force_inline proc( pool : ^Pool_List ) -> Pool_ListValue {
|
||||||
if pool.size <= 0 do return 0
|
if pool.size <= 0 do return 0
|
||||||
assert( pool.back != -1 )
|
assert( pool.back != -1 )
|
||||||
|
|
||||||
@@ -153,8 +153,10 @@ pool_list_pop_back :: #force_inline proc( pool : ^PoolList ) -> PoolListValue {
|
|||||||
|
|
||||||
LRU_Link :: struct {
|
LRU_Link :: struct {
|
||||||
pad_top : u64,
|
pad_top : u64,
|
||||||
|
|
||||||
value : i32,
|
value : i32,
|
||||||
ptr : PoolListIter,
|
ptr : Pool_ListIter,
|
||||||
|
|
||||||
pad_bottom : u64,
|
pad_bottom : u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,34 +164,34 @@ LRU_Cache :: struct {
|
|||||||
capacity : i32,
|
capacity : i32,
|
||||||
num : i32,
|
num : i32,
|
||||||
table : map[u64]LRU_Link,
|
table : map[u64]LRU_Link,
|
||||||
key_queue : PoolList,
|
key_queue : Pool_List,
|
||||||
}
|
}
|
||||||
|
|
||||||
LRU_init :: proc( cache : ^LRU_Cache, capacity : i32, dbg_name : string = "" ) {
|
lru_init :: proc( cache : ^LRU_Cache, capacity : i32, dbg_name : string = "" ) {
|
||||||
error : AllocatorError
|
error : Allocator_Error
|
||||||
cache.capacity = capacity
|
cache.capacity = capacity
|
||||||
cache.table, error = make( map[u64]LRU_Link, uint(capacity) )
|
cache.table, error = make( map[u64]LRU_Link, 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, dbg_name = dbg_name )
|
pool_list_init( & cache.key_queue, capacity, dbg_name = dbg_name )
|
||||||
}
|
}
|
||||||
|
|
||||||
LRU_free :: proc( cache : ^LRU_Cache ) {
|
lru_free :: proc( cache : ^LRU_Cache ) {
|
||||||
pool_list_free( & cache.key_queue )
|
pool_list_free( & cache.key_queue )
|
||||||
delete( cache.table )
|
delete( cache.table )
|
||||||
}
|
}
|
||||||
|
|
||||||
LRU_reload :: #force_inline proc( cache : ^LRU_Cache, allocator : Allocator ) {
|
lru_reload :: #force_inline proc( cache : ^LRU_Cache, allocator : Allocator ) {
|
||||||
reload_map( & cache.table, allocator )
|
reload_map( & cache.table, allocator )
|
||||||
pool_list_reload( & cache.key_queue, allocator )
|
pool_list_reload( & cache.key_queue, allocator )
|
||||||
}
|
}
|
||||||
|
|
||||||
LRU_find :: #force_inline proc "contextless" ( cache : ^LRU_Cache, key : u64, must_find := false ) -> (LRU_Link, bool) {
|
lru_find :: #force_inline proc "contextless" ( cache : ^LRU_Cache, key : u64, must_find := false ) -> (LRU_Link, bool) {
|
||||||
link, success := cache.table[key]
|
link, success := cache.table[key]
|
||||||
return link, success
|
return link, success
|
||||||
}
|
}
|
||||||
|
|
||||||
LRU_get :: #force_inline proc( cache: ^LRU_Cache, key : u64 ) -> i32 {
|
lru_get :: #force_inline proc( cache: ^LRU_Cache, key : u64 ) -> i32 {
|
||||||
if link, ok := &cache.table[ key ]; ok {
|
if link, ok := &cache.table[ key ]; ok {
|
||||||
pool_list_move_to_front(&cache.key_queue, link.ptr)
|
pool_list_move_to_front(&cache.key_queue, link.ptr)
|
||||||
return link.value
|
return link.value
|
||||||
@@ -197,7 +199,7 @@ LRU_get :: #force_inline proc( cache: ^LRU_Cache, key : u64 ) -> i32 {
|
|||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
LRU_get_next_evicted :: #force_inline proc ( cache : ^LRU_Cache ) -> u64 {
|
lru_get_next_evicted :: #force_inline proc ( cache : ^LRU_Cache ) -> u64 {
|
||||||
if cache.key_queue.size >= cache.capacity {
|
if cache.key_queue.size >= cache.capacity {
|
||||||
evict := pool_list_peek_back( & cache.key_queue )
|
evict := pool_list_peek_back( & cache.key_queue )
|
||||||
return evict
|
return evict
|
||||||
@@ -205,15 +207,15 @@ LRU_get_next_evicted :: #force_inline proc ( cache : ^LRU_Cache ) -> u64 {
|
|||||||
return 0xFFFFFFFFFFFFFFFF
|
return 0xFFFFFFFFFFFFFFFF
|
||||||
}
|
}
|
||||||
|
|
||||||
LRU_peek :: #force_inline proc ( cache : ^LRU_Cache, key : u64, must_find := false ) -> i32 {
|
lru_peek :: #force_inline proc ( cache : ^LRU_Cache, key : u64, must_find := false ) -> i32 {
|
||||||
iter, success := LRU_find( cache, key, must_find )
|
iter, success := lru_find( cache, key, must_find )
|
||||||
if success == false {
|
if success == false {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
return iter.value
|
return iter.value
|
||||||
}
|
}
|
||||||
|
|
||||||
LRU_put :: #force_inline proc( cache : ^LRU_Cache, key : u64, value : i32 ) -> u64
|
lru_put :: #force_inline proc( cache : ^LRU_Cache, key : u64, value : i32 ) -> u64
|
||||||
{
|
{
|
||||||
if link, ok := & cache.table[ key ]; ok {
|
if link, ok := & cache.table[ key ]; ok {
|
||||||
pool_list_move_to_front( & cache.key_queue, link.ptr )
|
pool_list_move_to_front( & cache.key_queue, link.ptr )
|
||||||
@@ -237,8 +239,8 @@ LRU_put :: #force_inline proc( cache : ^LRU_Cache, key : u64, value : i32 ) -> u
|
|||||||
return evict
|
return evict
|
||||||
}
|
}
|
||||||
|
|
||||||
LRU_refresh :: proc( cache : ^LRU_Cache, key : u64 ) {
|
lru_refresh :: proc( cache : ^LRU_Cache, key : u64 ) {
|
||||||
link, success := LRU_find( cache, key )
|
link, success := lru_find( cache, key )
|
||||||
pool_list_erase( & cache.key_queue, link.ptr )
|
pool_list_erase( & cache.key_queue, link.ptr )
|
||||||
pool_list_push_front( & cache.key_queue, key )
|
pool_list_push_front( & cache.key_queue, key )
|
||||||
link.ptr = cache.key_queue.front
|
link.ptr = cache.key_queue.front
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
package vefontcache
|
package vefontcache
|
||||||
|
|
||||||
AtlasRegionKind :: enum u8 {
|
Atlas_Region_Kind :: enum u8 {
|
||||||
None = 0x00,
|
None = 0x00,
|
||||||
A = 0x41,
|
A = 0x41,
|
||||||
B = 0x42,
|
B = 0x42,
|
||||||
@@ -10,7 +10,7 @@ AtlasRegionKind :: enum u8 {
|
|||||||
Ignore = 0xFF, // ve_fontcache_cache_glyph_to_atlas uses a -1 value in clear draw call
|
Ignore = 0xFF, // ve_fontcache_cache_glyph_to_atlas uses a -1 value in clear draw call
|
||||||
}
|
}
|
||||||
|
|
||||||
AtlasRegion :: struct {
|
Atlas_Region :: struct {
|
||||||
state : LRU_Cache,
|
state : LRU_Cache,
|
||||||
|
|
||||||
width : i32,
|
width : i32,
|
||||||
@@ -29,13 +29,13 @@ Atlas :: struct {
|
|||||||
|
|
||||||
glyph_padding : i32,
|
glyph_padding : i32,
|
||||||
|
|
||||||
region_a : AtlasRegion,
|
region_a : Atlas_Region,
|
||||||
region_b : AtlasRegion,
|
region_b : Atlas_Region,
|
||||||
region_c : AtlasRegion,
|
region_c : Atlas_Region,
|
||||||
region_d : AtlasRegion,
|
region_d : Atlas_Region,
|
||||||
}
|
}
|
||||||
|
|
||||||
atlas_bbox :: proc( atlas : ^Atlas, region : AtlasRegionKind, local_idx : i32 ) -> (position, size: Vec2)
|
atlas_bbox :: proc( atlas : ^Atlas, region : Atlas_Region_Kind, local_idx : i32 ) -> (position, size: Vec2)
|
||||||
{
|
{
|
||||||
switch region
|
switch region
|
||||||
{
|
{
|
||||||
@@ -79,14 +79,12 @@ atlas_bbox :: proc( atlas : ^Atlas, region : AtlasRegionKind, local_idx : i32 )
|
|||||||
position.x += f32(atlas.region_d.offset.x)
|
position.x += f32(atlas.region_d.offset.x)
|
||||||
position.y += f32(atlas.region_d.offset.y)
|
position.y += f32(atlas.region_d.offset.y)
|
||||||
|
|
||||||
case .Ignore: fallthrough
|
case .Ignore, .None, .E:
|
||||||
case .None: fallthrough
|
|
||||||
case .E:
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
decide_codepoint_region :: proc(ctx : ^Context, entry : ^Entry, glyph_index : Glyph ) -> (region_kind : AtlasRegionKind, region : ^AtlasRegion, over_sample : Vec2)
|
decide_codepoint_region :: proc(ctx : ^Context, entry : ^Entry, glyph_index : Glyph ) -> (region_kind : Atlas_Region_Kind, region : ^Atlas_Region, over_sample : Vec2)
|
||||||
{
|
{
|
||||||
if parser_is_glyph_empty(&entry.parser_info, glyph_index) {
|
if parser_is_glyph_empty(&entry.parser_info, glyph_index) {
|
||||||
return .None, nil, {}
|
return .None, nil, {}
|
||||||
@@ -104,11 +102,11 @@ decide_codepoint_region :: proc(ctx : ^Context, entry : ^Entry, glyph_index : Gl
|
|||||||
bounds_height_scaled := i32(bounds_height * entry.size_scale + glyph_padding)
|
bounds_height_scaled := i32(bounds_height * entry.size_scale + glyph_padding)
|
||||||
|
|
||||||
// Use a lookup table for faster region selection
|
// Use a lookup table for faster region selection
|
||||||
region_lookup := [4]struct { kind: AtlasRegionKind, region: ^AtlasRegion } {
|
region_lookup := [4]struct { kind: Atlas_Region_Kind, region: ^Atlas_Region } {
|
||||||
{ .A, & atlas.region_a },
|
{ .A, & atlas.region_a },
|
||||||
{ .B, & atlas.region_b },
|
{ .B, & atlas.region_b },
|
||||||
{ .C, & atlas.region_c },
|
{ .C, & atlas.region_c },
|
||||||
{ .D, & atlas.region_d },
|
{ .D, & atlas.region_d },
|
||||||
}
|
}
|
||||||
|
|
||||||
for region in region_lookup do if bounds_width_scaled <= region.region.width && bounds_height_scaled <= region.region.height {
|
for region in region_lookup do if bounds_width_scaled <= region.region.width && bounds_height_scaled <= region.region.height {
|
||||||
|
@@ -8,16 +8,16 @@ Vertex :: struct {
|
|||||||
u, v : f32,
|
u, v : f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawCall :: struct {
|
Draw_Call :: struct {
|
||||||
pass : FrameBufferPass,
|
pass : Frame_Buffer_Pass,
|
||||||
start_index : u32,
|
start_index : u32,
|
||||||
end_index : u32,
|
end_index : u32,
|
||||||
clear_before_draw : b32,
|
clear_before_draw : b32,
|
||||||
region : AtlasRegionKind,
|
region : Atlas_Region_Kind,
|
||||||
colour : Colour,
|
colour : Colour,
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawCall_Default :: DrawCall {
|
Draw_Call_Default :: Draw_Call {
|
||||||
pass = .None,
|
pass = .None,
|
||||||
start_index = 0,
|
start_index = 0,
|
||||||
end_index = 0,
|
end_index = 0,
|
||||||
@@ -26,14 +26,14 @@ DrawCall_Default :: DrawCall {
|
|||||||
colour = { 1.0, 1.0, 1.0, 1.0 }
|
colour = { 1.0, 1.0, 1.0, 1.0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawList :: struct {
|
Draw_List :: struct {
|
||||||
vertices : [dynamic]Vertex,
|
vertices : [dynamic]Vertex,
|
||||||
indices : [dynamic]u32,
|
indices : [dynamic]u32,
|
||||||
calls : [dynamic]DrawCall,
|
calls : [dynamic]Draw_Call,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(Ed): This was a rough translation of the raw values the orignal was using, need to give better names...
|
// TODO(Ed): This was a rough translation of the raw values the orignal was using, need to give better names...
|
||||||
FrameBufferPass :: enum u32 {
|
Frame_Buffer_Pass :: enum u32 {
|
||||||
None = 0,
|
None = 0,
|
||||||
Glyph = 1,
|
Glyph = 1,
|
||||||
Atlas = 2,
|
Atlas = 2,
|
||||||
@@ -41,7 +41,7 @@ FrameBufferPass :: enum u32 {
|
|||||||
Target_Uncached = 4,
|
Target_Uncached = 4,
|
||||||
}
|
}
|
||||||
|
|
||||||
GlyphDrawBuffer :: struct {
|
Glyph_Draw_Buffer :: struct {
|
||||||
over_sample : Vec2,
|
over_sample : Vec2,
|
||||||
batch : i32,
|
batch : i32,
|
||||||
width : i32,
|
width : i32,
|
||||||
@@ -49,11 +49,11 @@ GlyphDrawBuffer :: struct {
|
|||||||
draw_padding : i32,
|
draw_padding : i32,
|
||||||
|
|
||||||
batch_x : i32,
|
batch_x : i32,
|
||||||
clear_draw_list : DrawList,
|
clear_draw_list : Draw_List,
|
||||||
draw_list : DrawList,
|
draw_list : Draw_List,
|
||||||
}
|
}
|
||||||
|
|
||||||
blit_quad :: proc( draw_list : ^DrawList, p0 : Vec2 = {0, 0}, p1 : Vec2 = {1, 1}, uv0 : Vec2 = {0, 0}, uv1 : Vec2 = {1, 1} )
|
blit_quad :: proc( draw_list : ^Draw_List, p0 : Vec2 = {0, 0}, p1 : Vec2 = {1, 1}, uv0 : Vec2 = {0, 0}, uv1 : Vec2 = {1, 1} )
|
||||||
{
|
{
|
||||||
// profile(#procedure)
|
// profile(#procedure)
|
||||||
// logf("Blitting: xy0: %0.2f, %0.2f xy1: %0.2f, %0.2f uv0: %0.2f, %0.2f uv1: %0.2f, %0.2f",
|
// logf("Blitting: xy0: %0.2f, %0.2f xy1: %0.2f, %0.2f uv0: %0.2f, %0.2f uv1: %0.2f, %0.2f",
|
||||||
@@ -89,9 +89,9 @@ blit_quad :: proc( draw_list : ^DrawList, p0 : Vec2 = {0, 0}, p1 : Vec2 = {1, 1}
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO(Ed): glyph caching cannot be handled in a 'font parser' abstraction. Just going to have explicit procedures to grab info neatly...
|
// TODO(Ed): glyph caching cannot be handled in a 'font parser' abstraction. Just going to have explicit procedures to grab info neatly...
|
||||||
cache_glyph_freetype :: proc(ctx: ^Context, font: FontID, glyph_index: Glyph, entry: ^Entry, bounds_0, bounds_1: Vec2, scale, translate: Vec2) -> b32
|
cache_glyph_freetype :: proc(ctx: ^Context, font: Font_ID, glyph_index: Glyph, entry: ^Entry, bounds_0, bounds_1: Vec2, scale, translate: Vec2) -> b32
|
||||||
{
|
{
|
||||||
draw_filled_path_freetype :: proc( draw_list : ^DrawList, outside_point : Vec2, path : []Vertex,
|
draw_filled_path_freetype :: proc( draw_list : ^Draw_List, outside_point : Vec2, path : []Vertex,
|
||||||
scale := Vec2 { 1, 1 },
|
scale := Vec2 { 1, 1 },
|
||||||
translate := Vec2 { 0, 0 },
|
translate := Vec2 { 0, 0 },
|
||||||
debug_print_verbose : b32 = false
|
debug_print_verbose : b32 = false
|
||||||
@@ -130,9 +130,9 @@ cache_glyph_freetype :: proc(ctx: ^Context, font: FontID, glyph_index: Glyph, en
|
|||||||
|
|
||||||
// Close the path by connecting the last vertex to the first two
|
// Close the path by connecting the last vertex to the first two
|
||||||
to_add := [3]u32 {
|
to_add := [3]u32 {
|
||||||
v_offset,
|
v_offset,
|
||||||
v_offset + cast(u32)(len(path) - 1),
|
v_offset + cast(u32)(len(path) - 1),
|
||||||
v_offset + 1
|
v_offset + 1
|
||||||
}
|
}
|
||||||
append( indices, ..to_add[:] )
|
append( indices, ..to_add[:] )
|
||||||
}
|
}
|
||||||
@@ -158,8 +158,8 @@ cache_glyph_freetype :: proc(ctx: ^Context, font: FontID, glyph_index: Glyph, en
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
draw := DrawCall_Default
|
draw := Draw_Call_Default
|
||||||
draw.pass = FrameBufferPass.Glyph
|
draw.pass = Frame_Buffer_Pass.Glyph
|
||||||
draw.start_index = cast(u32) len(ctx.draw_list.indices)
|
draw.start_index = cast(u32) len(ctx.draw_list.indices)
|
||||||
|
|
||||||
contours := slice.from_ptr(cast( [^]i16) outline.contours, int(outline.n_contours))
|
contours := slice.from_ptr(cast( [^]i16) outline.contours, int(outline.n_contours))
|
||||||
@@ -178,57 +178,57 @@ cache_glyph_freetype :: proc(ctx: ^Context, font: FontID, glyph_index: Glyph, en
|
|||||||
prev_point: Vec2
|
prev_point: Vec2
|
||||||
first_point: Vec2
|
first_point: Vec2
|
||||||
|
|
||||||
for idx := start_index; idx < end_index; idx += 1
|
for idx := start_index; idx < end_index; idx += 1
|
||||||
|
{
|
||||||
|
current_pos := Vec2 { f32( points[idx].x ), f32( points[idx].y ) }
|
||||||
|
if ( tags[idx] & 1 ) == 0
|
||||||
{
|
{
|
||||||
current_pos := Vec2 { f32( points[idx].x ), f32( points[idx].y ) }
|
// If current point is off-curve
|
||||||
if ( tags[idx] & 1 ) == 0
|
if (idx == start_index || (tags[ idx - 1 ] & 1) != 0)
|
||||||
{
|
{
|
||||||
// If current point is off-curve
|
// current is the first or following an on-curve point
|
||||||
if (idx == start_index || (tags[ idx - 1 ] & 1) != 0)
|
prev_point = current_pos
|
||||||
{
|
|
||||||
// current is the first or following an on-curve point
|
|
||||||
prev_point = current_pos
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// current and previous are off-curve, calculate midpoint
|
|
||||||
midpoint := (prev_point + current_pos) * 0.5
|
|
||||||
append( path, Vertex { pos = midpoint } ) // Add midpoint as on-curve point
|
|
||||||
if idx < end_index - 1
|
|
||||||
{
|
|
||||||
// perform interp from prev_point to current_pos via midpoint
|
|
||||||
step := 1.0 / entry.curve_quality
|
|
||||||
for alpha : f32 = 0.0; alpha <= 1.0; alpha += step
|
|
||||||
{
|
|
||||||
bezier_point := eval_point_on_bezier3( prev_point, midpoint, current_pos, alpha )
|
|
||||||
append( path, Vertex{ pos = bezier_point } )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
prev_point = current_pos
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if idx == start_index {
|
// current and previous are off-curve, calculate midpoint
|
||||||
first_point = current_pos
|
midpoint := (prev_point + current_pos) * 0.5
|
||||||
|
append( path, Vertex { pos = midpoint } ) // Add midpoint as on-curve point
|
||||||
|
if idx < end_index - 1
|
||||||
|
{
|
||||||
|
// perform interp from prev_point to current_pos via midpoint
|
||||||
|
step := 1.0 / entry.curve_quality
|
||||||
|
for alpha : f32 = 0.0; alpha <= 1.0; alpha += step
|
||||||
|
{
|
||||||
|
bezier_point := eval_point_on_bezier3( prev_point, midpoint, current_pos, alpha )
|
||||||
|
append( path, Vertex{ pos = bezier_point } )
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if prev_point != (Vec2{}) {
|
|
||||||
// there was an off-curve point before this
|
prev_point = current_pos
|
||||||
append(path, Vertex{ pos = prev_point}) // Ensure previous off-curve is handled
|
|
||||||
}
|
|
||||||
append(path, Vertex{ pos = current_pos})
|
|
||||||
prev_point = {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
// ensure the contour is closed
|
{
|
||||||
if path[0].pos != path[ len(path) - 1 ].pos {
|
if idx == start_index {
|
||||||
append(path, Vertex{pos = path[0].pos})
|
first_point = current_pos
|
||||||
|
}
|
||||||
|
if prev_point != (Vec2{}) {
|
||||||
|
// there was an off-curve point before this
|
||||||
|
append(path, Vertex{ pos = prev_point}) // Ensure previous off-curve is handled
|
||||||
|
}
|
||||||
|
append(path, Vertex{ pos = current_pos})
|
||||||
|
prev_point = {}
|
||||||
}
|
}
|
||||||
draw_filled_path(&ctx.draw_list, bounds_0, path[:], scale, translate, ctx.debug_print_verbose)
|
}
|
||||||
clear(path)
|
|
||||||
start_index = end_index
|
// ensure the contour is closed
|
||||||
|
if path[0].pos != path[ len(path) - 1 ].pos {
|
||||||
|
append(path, Vertex{pos = path[0].pos})
|
||||||
|
}
|
||||||
|
draw_filled_path(&ctx.draw_list, bounds_0, path[:], scale, translate, ctx.debug_print_verbose)
|
||||||
|
clear(path)
|
||||||
|
start_index = end_index
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(path) > 0 {
|
if len(path) > 0 {
|
||||||
@@ -244,7 +244,7 @@ cache_glyph_freetype :: proc(ctx: ^Context, font: FontID, glyph_index: Glyph, en
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO(Ed): Is it better to cache the glyph vertices for when it must be re-drawn (directly or two atlas)?
|
// TODO(Ed): Is it better to cache the glyph vertices for when it must be re-drawn (directly or two atlas)?
|
||||||
cache_glyph :: proc(ctx : ^Context, font : FontID, glyph_index : Glyph, entry : ^Entry, bounds_0, bounds_1 : Vec2, scale, translate : Vec2) -> b32
|
cache_glyph :: proc(ctx : ^Context, font : Font_ID, glyph_index : Glyph, entry : ^Entry, bounds_0, bounds_1 : Vec2, scale, translate : Vec2) -> b32
|
||||||
{
|
{
|
||||||
// profile(#procedure)
|
// profile(#procedure)
|
||||||
if glyph_index == Glyph(0) {
|
if glyph_index == Glyph(0) {
|
||||||
@@ -265,8 +265,8 @@ cache_glyph :: proc(ctx : ^Context, font : FontID, glyph_index : Glyph, entry :
|
|||||||
|
|
||||||
outside := Vec2{bounds_0.x - 21, bounds_0.y - 33}
|
outside := Vec2{bounds_0.x - 21, bounds_0.y - 33}
|
||||||
|
|
||||||
draw := DrawCall_Default
|
draw := Draw_Call_Default
|
||||||
draw.pass = FrameBufferPass.Glyph
|
draw.pass = Frame_Buffer_Pass.Glyph
|
||||||
draw.start_index = u32(len(ctx.draw_list.indices))
|
draw.start_index = u32(len(ctx.draw_list.indices))
|
||||||
|
|
||||||
path := &ctx.temp_path
|
path := &ctx.temp_path
|
||||||
@@ -276,8 +276,8 @@ cache_glyph :: proc(ctx : ^Context, font : FontID, glyph_index : Glyph, entry :
|
|||||||
{
|
{
|
||||||
case .Move:
|
case .Move:
|
||||||
if len(path) > 0 {
|
if len(path) > 0 {
|
||||||
draw_filled_path(&ctx.draw_list, outside, path[:], scale, translate, ctx.debug_print_verbose)
|
draw_filled_path(&ctx.draw_list, outside, path[:], scale, translate, ctx.debug_print_verbose)
|
||||||
clear(path)
|
clear(path)
|
||||||
}
|
}
|
||||||
fallthrough
|
fallthrough
|
||||||
|
|
||||||
@@ -329,13 +329,13 @@ cache_glyph :: proc(ctx : ^Context, font : FontID, glyph_index : Glyph, entry :
|
|||||||
* draw_text_shape : Glyph
|
* draw_text_shape : Glyph
|
||||||
*/
|
*/
|
||||||
cache_glyph_to_atlas :: proc( ctx : ^Context,
|
cache_glyph_to_atlas :: proc( ctx : ^Context,
|
||||||
font : FontID,
|
font : Font_ID,
|
||||||
glyph_index : Glyph,
|
glyph_index : Glyph,
|
||||||
lru_code : u64,
|
lru_code : u64,
|
||||||
atlas_index : i32,
|
atlas_index : i32,
|
||||||
entry : ^Entry,
|
entry : ^Entry,
|
||||||
region_kind : AtlasRegionKind,
|
region_kind : Atlas_Region_Kind,
|
||||||
region : ^AtlasRegion,
|
region : ^Atlas_Region,
|
||||||
over_sample : Vec2 )
|
over_sample : Vec2 )
|
||||||
{
|
{
|
||||||
// profile(#procedure)
|
// profile(#procedure)
|
||||||
@@ -356,24 +356,24 @@ cache_glyph_to_atlas :: proc( ctx : ^Context,
|
|||||||
{
|
{
|
||||||
if region.next_idx < region.state.capacity
|
if region.next_idx < region.state.capacity
|
||||||
{
|
{
|
||||||
evicted := LRU_put( & region.state, lru_code, i32(region.next_idx) )
|
evicted := lru_put( & region.state, lru_code, i32(region.next_idx) )
|
||||||
atlas_index = i32(region.next_idx)
|
atlas_index = i32(region.next_idx)
|
||||||
region.next_idx += 1
|
region.next_idx += 1
|
||||||
assert( evicted == lru_code )
|
assert( evicted == lru_code )
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
next_evict_codepoint := LRU_get_next_evicted( & region.state )
|
next_evict_codepoint := lru_get_next_evicted( & region.state )
|
||||||
assert( next_evict_codepoint != 0xFFFFFFFFFFFFFFFF )
|
assert( next_evict_codepoint != 0xFFFFFFFFFFFFFFFF )
|
||||||
|
|
||||||
atlas_index = LRU_peek( & region.state, next_evict_codepoint, must_find = true )
|
atlas_index = lru_peek( & region.state, next_evict_codepoint, must_find = true )
|
||||||
assert( atlas_index != -1 )
|
assert( atlas_index != -1 )
|
||||||
|
|
||||||
evicted := LRU_put( & region.state, lru_code, atlas_index )
|
evicted := lru_put( & region.state, lru_code, atlas_index )
|
||||||
assert( evicted == next_evict_codepoint )
|
assert( evicted == next_evict_codepoint )
|
||||||
}
|
}
|
||||||
|
|
||||||
assert( LRU_get( & region.state, lru_code ) != - 1 )
|
assert( lru_get( & region.state, lru_code ) != - 1 )
|
||||||
}
|
}
|
||||||
|
|
||||||
atlas := & ctx.atlas
|
atlas := & ctx.atlas
|
||||||
@@ -420,7 +420,7 @@ cache_glyph_to_atlas :: proc( ctx : ^Context,
|
|||||||
glyph_buffer.batch_x += i32(gwidth_scaled_px)
|
glyph_buffer.batch_x += i32(gwidth_scaled_px)
|
||||||
screenspace_x_form( & glyph_draw_translate, & glyph_draw_scale, glyph_buffer_size )
|
screenspace_x_form( & glyph_draw_translate, & glyph_draw_scale, glyph_buffer_size )
|
||||||
|
|
||||||
clear_target_region : DrawCall
|
clear_target_region : Draw_Call
|
||||||
{
|
{
|
||||||
using clear_target_region
|
using clear_target_region
|
||||||
pass = .Atlas
|
pass = .Atlas
|
||||||
@@ -434,7 +434,7 @@ cache_glyph_to_atlas :: proc( ctx : ^Context,
|
|||||||
end_index = cast(u32) len(glyph_buffer.clear_draw_list.indices)
|
end_index = cast(u32) len(glyph_buffer.clear_draw_list.indices)
|
||||||
}
|
}
|
||||||
|
|
||||||
blit_to_atlas : DrawCall
|
blit_to_atlas : Draw_Call
|
||||||
{
|
{
|
||||||
using blit_to_atlas
|
using blit_to_atlas
|
||||||
pass = .Atlas
|
pass = .Atlas
|
||||||
@@ -456,11 +456,11 @@ cache_glyph_to_atlas :: proc( ctx : ^Context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If the glyuph is found in the atlas, nothing occurs, otherwise, the glyph call is setup to catch it to the atlas
|
// 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,
|
check_glyph_in_atlas :: #force_inline proc( ctx : ^Context, font : Font_ID, entry : ^Entry, glyph_index : Glyph,
|
||||||
lru_code : u64,
|
lru_code : u64,
|
||||||
atlas_index : i32,
|
atlas_index : i32,
|
||||||
region_kind : AtlasRegionKind,
|
region_kind : Atlas_Region_Kind,
|
||||||
region : ^AtlasRegion,
|
region : ^Atlas_Region,
|
||||||
over_sample : Vec2
|
over_sample : Vec2
|
||||||
) -> b32
|
) -> b32
|
||||||
{
|
{
|
||||||
@@ -476,7 +476,7 @@ check_glyph_in_atlas :: #force_inline proc( ctx : ^Context, font : FontID, entry
|
|||||||
{
|
{
|
||||||
if region.next_idx > region.state.capacity {
|
if region.next_idx > region.state.capacity {
|
||||||
// We will evict LRU. We must predict which LRU will get evicted, and if it's something we've seen then we need to take slowpath and flush batch.
|
// We will evict LRU. We must predict which LRU will get evicted, and if it's something we've seen then we need to take slowpath and flush batch.
|
||||||
next_evict_codepoint := LRU_get_next_evicted( & region.state )
|
next_evict_codepoint := lru_get_next_evicted( & region.state )
|
||||||
seen, success := ctx.temp_codepoint_seen[next_evict_codepoint]
|
seen, success := ctx.temp_codepoint_seen[next_evict_codepoint]
|
||||||
assert(success != false)
|
assert(success != false)
|
||||||
|
|
||||||
@@ -488,13 +488,13 @@ check_glyph_in_atlas :: #force_inline proc( ctx : ^Context, font : FontID, entry
|
|||||||
cache_glyph_to_atlas( ctx, font, glyph_index, lru_code, atlas_index, entry, region_kind, region, over_sample )
|
cache_glyph_to_atlas( ctx, font, glyph_index, lru_code, atlas_index, entry, region_kind, region, over_sample )
|
||||||
}
|
}
|
||||||
|
|
||||||
assert( LRU_get( & region.state, lru_code ) != -1 )
|
assert( lru_get( & region.state, lru_code ) != -1 )
|
||||||
mark_batch_codepoint_seen( ctx, lru_code)
|
mark_batch_codepoint_seen( ctx, lru_code)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// ve_fontcache_clear_drawlist
|
// ve_fontcache_clear_Draw_List
|
||||||
clear_draw_list :: #force_inline proc ( draw_list : ^DrawList ) {
|
clear_draw_list :: #force_inline proc ( draw_list : ^Draw_List ) {
|
||||||
clear( & draw_list.calls )
|
clear( & draw_list.calls )
|
||||||
clear( & draw_list.indices )
|
clear( & draw_list.indices )
|
||||||
clear( & draw_list.vertices )
|
clear( & draw_list.vertices )
|
||||||
@@ -538,8 +538,8 @@ directly_draw_massive_glyph :: proc( ctx : ^Context,
|
|||||||
dst_size := glyph_dst_size * scale
|
dst_size := glyph_dst_size * scale
|
||||||
textspace_x_form( & glyph_position, & glyph_size, glyph_buffer_size )
|
textspace_x_form( & glyph_position, & glyph_size, glyph_buffer_size )
|
||||||
|
|
||||||
// Add the glyph drawcall.
|
// Add the glyph Draw_Call.
|
||||||
calls : [2]DrawCall
|
calls : [2]Draw_Call
|
||||||
|
|
||||||
draw_to_target := & calls[0]
|
draw_to_target := & calls[0]
|
||||||
{
|
{
|
||||||
@@ -549,8 +549,8 @@ directly_draw_massive_glyph :: proc( ctx : ^Context,
|
|||||||
start_index = u32(len(ctx.draw_list.indices))
|
start_index = u32(len(ctx.draw_list.indices))
|
||||||
|
|
||||||
blit_quad( & ctx.draw_list,
|
blit_quad( & ctx.draw_list,
|
||||||
dst, dst + dst_size,
|
dst, dst + dst_size,
|
||||||
glyph_position, glyph_position + glyph_size )
|
glyph_position, glyph_position + glyph_size )
|
||||||
|
|
||||||
end_index = u32(len(ctx.draw_list.indices))
|
end_index = u32(len(ctx.draw_list.indices))
|
||||||
}
|
}
|
||||||
@@ -570,9 +570,9 @@ directly_draw_massive_glyph :: proc( ctx : ^Context,
|
|||||||
// outside_point represents the center point of the fan.
|
// outside_point represents the center point of the fan.
|
||||||
//
|
//
|
||||||
// Note(Original Author):
|
// Note(Original Author):
|
||||||
// WARNING: doesn't actually append drawcall; caller is responsible for actually appending the drawcall.
|
// WARNING: doesn't actually append Draw_Call; caller is responsible for actually appending the Draw_Call.
|
||||||
// ve_fontcache_draw_filled_path
|
// ve_fontcache_draw_filled_path
|
||||||
draw_filled_path :: proc( draw_list : ^DrawList, outside_point : Vec2, path : []Vertex,
|
draw_filled_path :: proc( draw_list : ^Draw_List, outside_point : Vec2, path : []Vertex,
|
||||||
scale := Vec2 { 1, 1 },
|
scale := Vec2 { 1, 1 },
|
||||||
translate := Vec2 { 0, 0 },
|
translate := Vec2 { 0, 0 },
|
||||||
debug_print_verbose : b32 = false
|
debug_print_verbose : b32 = false
|
||||||
@@ -615,7 +615,7 @@ draw_filled_path :: proc( draw_list : ^DrawList, outside_point : Vec2, path : []
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
draw_text_batch :: proc(ctx: ^Context, entry: ^Entry, shaped: ^ShapedText,
|
draw_text_batch :: proc(ctx: ^Context, entry: ^Entry, shaped: ^Shaped_Text,
|
||||||
batch_start_idx, batch_end_idx : i32,
|
batch_start_idx, batch_end_idx : i32,
|
||||||
position, scale : Vec2,
|
position, scale : Vec2,
|
||||||
snap_width, snap_height : f32 )
|
snap_width, snap_height : f32 )
|
||||||
@@ -634,7 +634,7 @@ draw_text_batch :: proc(ctx: ^Context, entry: ^Entry, shaped: ^ShapedText,
|
|||||||
|
|
||||||
region_kind, region, over_sample := decide_codepoint_region( ctx, entry, glyph_index )
|
region_kind, region, over_sample := decide_codepoint_region( ctx, entry, glyph_index )
|
||||||
lru_code := font_glyph_lru_code( entry.id, glyph_index )
|
lru_code := font_glyph_lru_code( entry.id, glyph_index )
|
||||||
atlas_index := region_kind != .E ? LRU_get( & region.state, lru_code ) : -1
|
atlas_index := region_kind != .E ? lru_get( & region.state, lru_code ) : -1
|
||||||
bounds_0, bounds_1 := parser_get_glyph_box( & entry.parser_info, glyph_index )
|
bounds_0, bounds_1 := parser_get_glyph_box( & entry.parser_info, glyph_index )
|
||||||
vbounds_0 := vec2(bounds_0)
|
vbounds_0 := vec2(bounds_0)
|
||||||
vbounds_1 := vec2(bounds_1)
|
vbounds_1 := vec2(bounds_1)
|
||||||
@@ -660,7 +660,7 @@ draw_text_batch :: proc(ctx: ^Context, entry: ^Entry, shaped: ^ShapedText,
|
|||||||
dst_scale := glyph_scale * scale
|
dst_scale := glyph_scale * scale
|
||||||
textspace_x_form( & slot_position, & glyph_scale, atlas_size )
|
textspace_x_form( & slot_position, & glyph_scale, atlas_size )
|
||||||
|
|
||||||
call := DrawCall_Default
|
call := Draw_Call_Default
|
||||||
call.pass = .Target
|
call.pass = .Target
|
||||||
call.colour = ctx.colour
|
call.colour = ctx.colour
|
||||||
call.start_index = u32(len(ctx.draw_list.indices))
|
call.start_index = u32(len(ctx.draw_list.indices))
|
||||||
@@ -677,9 +677,9 @@ draw_text_batch :: proc(ctx: ^Context, entry: ^Entry, shaped: ^ShapedText,
|
|||||||
|
|
||||||
// Helper for draw_text, all raw text content should be confirmed to be either formatting or visible shapes before getting cached.
|
// Helper for draw_text, all raw text content should be confirmed to be either formatting or visible shapes before getting cached.
|
||||||
draw_text_shape :: proc( ctx : ^Context,
|
draw_text_shape :: proc( ctx : ^Context,
|
||||||
font : FontID,
|
font : Font_ID,
|
||||||
entry : ^Entry,
|
entry : ^Entry,
|
||||||
shaped : ^ShapedText,
|
shaped : ^Shaped_Text,
|
||||||
position, scale : Vec2,
|
position, scale : Vec2,
|
||||||
snap_width, snap_height : f32
|
snap_width, snap_height : f32
|
||||||
) -> (cursor_pos : Vec2)
|
) -> (cursor_pos : Vec2)
|
||||||
@@ -695,7 +695,7 @@ draw_text_shape :: proc( ctx : ^Context,
|
|||||||
lru_code := font_glyph_lru_code(entry.id, glyph_index)
|
lru_code := font_glyph_lru_code(entry.id, glyph_index)
|
||||||
atlas_index := cast(i32) -1
|
atlas_index := cast(i32) -1
|
||||||
|
|
||||||
if region_kind != .E do atlas_index = LRU_get( & region.state, lru_code )
|
if region_kind != .E do atlas_index = lru_get( & region.state, lru_code )
|
||||||
if check_glyph_in_atlas( 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
|
// We can no longer directly append the shape as it has missing glyphs in the atlas
|
||||||
@@ -720,7 +720,7 @@ draw_text_shape :: proc( ctx : ^Context,
|
|||||||
flush_glyph_buffer_to_atlas :: proc( ctx : ^Context )
|
flush_glyph_buffer_to_atlas :: proc( ctx : ^Context )
|
||||||
{
|
{
|
||||||
// profile(#procedure)
|
// profile(#procedure)
|
||||||
// Flush drawcalls to draw list
|
// Flush Draw_Calls to draw list
|
||||||
merge_draw_list( & ctx.draw_list, & ctx.glyph_buffer.clear_draw_list )
|
merge_draw_list( & ctx.draw_list, & ctx.glyph_buffer.clear_draw_list )
|
||||||
merge_draw_list( & ctx.draw_list, & ctx.glyph_buffer.draw_list)
|
merge_draw_list( & ctx.draw_list, & ctx.glyph_buffer.draw_list)
|
||||||
clear_draw_list( & ctx.glyph_buffer.draw_list )
|
clear_draw_list( & ctx.glyph_buffer.draw_list )
|
||||||
@@ -729,7 +729,7 @@ flush_glyph_buffer_to_atlas :: proc( ctx : ^Context )
|
|||||||
// Clear glyph_update_FBO
|
// Clear glyph_update_FBO
|
||||||
if ctx.glyph_buffer.batch_x != 0
|
if ctx.glyph_buffer.batch_x != 0
|
||||||
{
|
{
|
||||||
call := DrawCall_Default
|
call := Draw_Call_Default
|
||||||
call.pass = .Glyph
|
call.pass = .Glyph
|
||||||
call.start_index = 0
|
call.start_index = 0
|
||||||
call.end_index = 0
|
call.end_index = 0
|
||||||
@@ -739,11 +739,11 @@ flush_glyph_buffer_to_atlas :: proc( ctx : ^Context )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ve_fontcache_merge_drawlist
|
// ve_fontcache_merge_Draw_List
|
||||||
merge_draw_list :: proc( dst, src : ^DrawList )
|
merge_draw_list :: proc( dst, src : ^Draw_List )
|
||||||
{
|
{
|
||||||
// profile(#procedure)
|
// profile(#procedure)
|
||||||
error : AllocatorError
|
error : Allocator_Error
|
||||||
|
|
||||||
v_offset := cast(u32) len( dst.vertices )
|
v_offset := cast(u32) len( dst.vertices )
|
||||||
num_appended : int
|
num_appended : int
|
||||||
@@ -766,11 +766,11 @@ merge_draw_list :: proc( dst, src : ^DrawList )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
optimize_draw_list :: proc(draw_list: ^DrawList, call_offset: int) {
|
optimize_draw_list :: proc(draw_list: ^Draw_List, call_offset: int) {
|
||||||
// profile(#procedure)
|
// profile(#procedure)
|
||||||
assert(draw_list != nil)
|
assert(draw_list != nil)
|
||||||
|
|
||||||
can_merge_draw_calls :: #force_inline proc "contextless" ( a, b : ^DrawCall ) -> bool {
|
can_merge_draw_calls :: #force_inline proc "contextless" ( a, b : ^Draw_Call ) -> bool {
|
||||||
result := \
|
result := \
|
||||||
a.pass == b.pass &&
|
a.pass == b.pass &&
|
||||||
a.end_index == b.start_index &&
|
a.end_index == b.start_index &&
|
||||||
|
@@ -27,8 +27,8 @@ import "core:mem"
|
|||||||
Kilobyte :: mem.Kilobyte
|
Kilobyte :: mem.Kilobyte
|
||||||
slice_ptr :: mem.slice_ptr
|
slice_ptr :: mem.slice_ptr
|
||||||
|
|
||||||
Allocator :: mem.Allocator
|
Allocator :: mem.Allocator
|
||||||
AllocatorError :: mem.Allocator_Error
|
Allocator_Error :: mem.Allocator_Error
|
||||||
|
|
||||||
Arena :: mem.Arena
|
Arena :: mem.Arena
|
||||||
arena_allocator :: mem.arena_allocator
|
arena_allocator :: mem.arena_allocator
|
||||||
|
@@ -49,7 +49,7 @@ reload_map :: proc( self : ^map [$KeyType] $EntryType, allocator : Allocator ) {
|
|||||||
raw.allocator = allocator
|
raw.allocator = allocator
|
||||||
}
|
}
|
||||||
|
|
||||||
font_glyph_lru_code :: #force_inline proc "contextless" ( font : FontID, glyph_index : Glyph ) -> (lru_code : u64) {
|
font_glyph_lru_code :: #force_inline proc "contextless" ( font : Font_ID, glyph_index : Glyph ) -> (lru_code : u64) {
|
||||||
lru_code = u64(glyph_index) + ( ( 0x100000000 * u64(font) ) & 0xFFFFFFFF00000000 )
|
lru_code = u64(glyph_index) + ( ( 0x100000000 * u64(font) ) & 0xFFFFFFFF00000000 )
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -71,9 +71,11 @@ reset_batch_codepoint_state :: #force_inline proc( ctx : ^Context ) {
|
|||||||
ctx.temp_codepoint_seen_num = 0
|
ctx.temp_codepoint_seen_num = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
USE_F64_PRECISION_ON_X_FORM_OPS :: false
|
||||||
|
|
||||||
screenspace_x_form :: #force_inline proc "contextless" ( position, scale : ^Vec2, size : Vec2 )
|
screenspace_x_form :: #force_inline proc "contextless" ( position, scale : ^Vec2, size : Vec2 )
|
||||||
{
|
{
|
||||||
if true
|
when USE_F64_PRECISION_ON_X_FORM_OPS
|
||||||
{
|
{
|
||||||
pos_64 := vec2_64_from_vec2(position^)
|
pos_64 := vec2_64_from_vec2(position^)
|
||||||
scale_64 := vec2_64_from_vec2(scale^)
|
scale_64 := vec2_64_from_vec2(scale^)
|
||||||
@@ -101,7 +103,7 @@ screenspace_x_form :: #force_inline proc "contextless" ( position, scale : ^Vec2
|
|||||||
|
|
||||||
textspace_x_form :: #force_inline proc "contextless" ( position, scale : ^Vec2, size : Vec2 )
|
textspace_x_form :: #force_inline proc "contextless" ( position, scale : ^Vec2, size : Vec2 )
|
||||||
{
|
{
|
||||||
if true
|
when USE_F64_PRECISION_ON_X_FORM_OPS
|
||||||
{
|
{
|
||||||
pos_64 := vec2_64_from_vec2(position^)
|
pos_64 := vec2_64_from_vec2(position^)
|
||||||
scale_64 := vec2_64_from_vec2(scale^)
|
scale_64 := vec2_64_from_vec2(scale^)
|
||||||
@@ -121,9 +123,9 @@ textspace_x_form :: #force_inline proc "contextless" ( position, scale : ^Vec2,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Use_SIMD_For_Bezier_Ops :: false
|
USE_MANUAL_SIMD_FOR_BEZIER_OPS :: false
|
||||||
|
|
||||||
when ! Use_SIMD_For_Bezier_Ops
|
when ! USE_MANUAL_SIMD_FOR_BEZIER_OPS
|
||||||
{
|
{
|
||||||
// For a provided alpha value,
|
// 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
|
// allows the function to calculate the position of a point along the curve at any given fraction of its total length
|
||||||
|
@@ -16,14 +16,14 @@ import "core:slice"
|
|||||||
import stbtt "vendor:stb/truetype"
|
import stbtt "vendor:stb/truetype"
|
||||||
import freetype "thirdparty:freetype"
|
import freetype "thirdparty:freetype"
|
||||||
|
|
||||||
ParserKind :: enum u32 {
|
Parser_Kind :: enum u32 {
|
||||||
STB_TrueType,
|
STB_TrueType,
|
||||||
Freetype,
|
Freetype,
|
||||||
}
|
}
|
||||||
|
|
||||||
ParserFontInfo :: struct {
|
Parser_Font_Info :: struct {
|
||||||
label : string,
|
label : string,
|
||||||
kind : ParserKind,
|
kind : Parser_Kind,
|
||||||
using _ : struct #raw_union {
|
using _ : struct #raw_union {
|
||||||
stbtt_info : stbtt.fontinfo,
|
stbtt_info : stbtt.fontinfo,
|
||||||
freetype_info : freetype.Face
|
freetype_info : freetype.Face
|
||||||
@@ -31,7 +31,7 @@ ParserFontInfo :: struct {
|
|||||||
data : []byte,
|
data : []byte,
|
||||||
}
|
}
|
||||||
|
|
||||||
GlyphVertType :: enum u8 {
|
Glyph_Vert_Type :: enum u8 {
|
||||||
None,
|
None,
|
||||||
Move = 1,
|
Move = 1,
|
||||||
Line,
|
Line,
|
||||||
@@ -40,22 +40,22 @@ GlyphVertType :: enum u8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Based directly off of stb_truetype's vertex
|
// Based directly off of stb_truetype's vertex
|
||||||
ParserGlyphVertex :: struct {
|
Parser_Glyph_Vertex :: struct {
|
||||||
x, y : i16,
|
x, y : i16,
|
||||||
contour_x0, contour_y0 : i16,
|
contour_x0, contour_y0 : i16,
|
||||||
contour_x1, contour_y1 : i16,
|
contour_x1, contour_y1 : i16,
|
||||||
type : GlyphVertType,
|
type : Glyph_Vert_Type,
|
||||||
padding : u8,
|
padding : u8,
|
||||||
}
|
}
|
||||||
// A shape can be a dynamic array free_type or an opaque set of data handled by stb_truetype
|
// A shape can be a dynamic array free_type or an opaque set of data handled by stb_truetype
|
||||||
ParserGlyphShape :: [dynamic]ParserGlyphVertex
|
Parser_Glyph_Shape :: [dynamic]Parser_Glyph_Vertex
|
||||||
|
|
||||||
ParserContext :: struct {
|
Parser_Context :: struct {
|
||||||
kind : ParserKind,
|
kind : Parser_Kind,
|
||||||
ft_library : freetype.Library,
|
ft_library : freetype.Library,
|
||||||
}
|
}
|
||||||
|
|
||||||
parser_init :: proc( ctx : ^ParserContext, kind : ParserKind )
|
parser_init :: proc( ctx : ^Parser_Context, kind : Parser_Kind )
|
||||||
{
|
{
|
||||||
switch kind
|
switch kind
|
||||||
{
|
{
|
||||||
@@ -70,11 +70,11 @@ parser_init :: proc( ctx : ^ParserContext, kind : ParserKind )
|
|||||||
ctx.kind = kind
|
ctx.kind = kind
|
||||||
}
|
}
|
||||||
|
|
||||||
parser_shutdown :: proc( ctx : ^ParserContext ) {
|
parser_shutdown :: proc( ctx : ^Parser_Context ) {
|
||||||
// TODO(Ed): Implement
|
// TODO(Ed): Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
parser_load_font :: proc( ctx : ^ParserContext, label : string, data : []byte ) -> (font : ParserFontInfo)
|
parser_load_font :: proc( ctx : ^Parser_Context, label : string, data : []byte ) -> (font : Parser_Font_Info)
|
||||||
{
|
{
|
||||||
switch ctx.kind
|
switch ctx.kind
|
||||||
{
|
{
|
||||||
@@ -93,7 +93,7 @@ parser_load_font :: proc( ctx : ^ParserContext, label : string, data : []byte )
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
parser_unload_font :: proc( font : ^ParserFontInfo )
|
parser_unload_font :: proc( font : ^Parser_Font_Info )
|
||||||
{
|
{
|
||||||
switch font.kind {
|
switch font.kind {
|
||||||
case .Freetype:
|
case .Freetype:
|
||||||
@@ -105,7 +105,7 @@ parser_unload_font :: proc( font : ^ParserFontInfo )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
parser_find_glyph_index :: #force_inline proc "contextless" ( font : ^ParserFontInfo, codepoint : rune ) -> (glyph_index : Glyph)
|
parser_find_glyph_index :: #force_inline proc "contextless" ( font : ^Parser_Font_Info, codepoint : rune ) -> (glyph_index : Glyph)
|
||||||
{
|
{
|
||||||
switch font.kind
|
switch font.kind
|
||||||
{
|
{
|
||||||
@@ -120,7 +120,7 @@ parser_find_glyph_index :: #force_inline proc "contextless" ( font : ^ParserFont
|
|||||||
return Glyph(-1)
|
return Glyph(-1)
|
||||||
}
|
}
|
||||||
|
|
||||||
parser_free_shape :: proc( font : ^ParserFontInfo, shape : ParserGlyphShape )
|
parser_free_shape :: proc( font : ^Parser_Font_Info, shape : Parser_Glyph_Shape )
|
||||||
{
|
{
|
||||||
switch font.kind
|
switch font.kind
|
||||||
{
|
{
|
||||||
@@ -132,7 +132,7 @@ parser_free_shape :: proc( font : ^ParserFontInfo, shape : ParserGlyphShape )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
parser_get_codepoint_horizontal_metrics :: #force_inline proc "contextless" ( font : ^ParserFontInfo, codepoint : rune ) -> ( advance, to_left_side_glyph : i32 )
|
parser_get_codepoint_horizontal_metrics :: #force_inline proc "contextless" ( font : ^Parser_Font_Info, codepoint : rune ) -> ( advance, to_left_side_glyph : i32 )
|
||||||
{
|
{
|
||||||
switch font.kind
|
switch font.kind
|
||||||
{
|
{
|
||||||
@@ -156,7 +156,7 @@ parser_get_codepoint_horizontal_metrics :: #force_inline proc "contextless" ( fo
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
parser_get_codepoint_kern_advance :: #force_inline proc "contextless" ( font : ^ParserFontInfo, prev_codepoint, codepoint : rune ) -> i32
|
parser_get_codepoint_kern_advance :: #force_inline proc "contextless" ( font : ^Parser_Font_Info, prev_codepoint, codepoint : rune ) -> i32
|
||||||
{
|
{
|
||||||
switch font.kind
|
switch font.kind
|
||||||
{
|
{
|
||||||
@@ -176,7 +176,7 @@ parser_get_codepoint_kern_advance :: #force_inline proc "contextless" ( font : ^
|
|||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
parser_get_font_vertical_metrics :: #force_inline proc "contextless" ( font : ^ParserFontInfo ) -> (ascent, descent, line_gap : i32 )
|
parser_get_font_vertical_metrics :: #force_inline proc "contextless" ( font : ^Parser_Font_Info ) -> (ascent, descent, line_gap : i32 )
|
||||||
{
|
{
|
||||||
switch font.kind
|
switch font.kind
|
||||||
{
|
{
|
||||||
@@ -192,7 +192,7 @@ parser_get_font_vertical_metrics :: #force_inline proc "contextless" ( font : ^P
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
parser_get_glyph_box :: #force_inline proc ( font : ^ParserFontInfo, glyph_index : Glyph ) -> (bounds_0, bounds_1 : Vec2i)
|
parser_get_glyph_box :: #force_inline proc ( font : ^Parser_Font_Info, glyph_index : Glyph ) -> (bounds_0, bounds_1 : Vec2i)
|
||||||
{
|
{
|
||||||
switch font.kind
|
switch font.kind
|
||||||
{
|
{
|
||||||
@@ -215,7 +215,7 @@ parser_get_glyph_box :: #force_inline proc ( font : ^ParserFontInfo, glyph_index
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
parser_get_glyph_shape :: proc( font : ^ParserFontInfo, glyph_index : Glyph ) -> (shape : ParserGlyphShape, error : AllocatorError)
|
parser_get_glyph_shape :: proc( font : ^Parser_Font_Info, glyph_index : Glyph ) -> (shape : Parser_Glyph_Shape, error : Allocator_Error)
|
||||||
{
|
{
|
||||||
switch font.kind
|
switch font.kind
|
||||||
{
|
{
|
||||||
@@ -232,14 +232,14 @@ parser_get_glyph_shape :: proc( font : ^ParserFontInfo, glyph_index : Glyph ) ->
|
|||||||
shape_raw.len = int(nverts)
|
shape_raw.len = int(nverts)
|
||||||
shape_raw.cap = int(nverts)
|
shape_raw.cap = int(nverts)
|
||||||
shape_raw.allocator = runtime.nil_allocator()
|
shape_raw.allocator = runtime.nil_allocator()
|
||||||
error = AllocatorError.None
|
error = Allocator_Error.None
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
parser_is_glyph_empty :: #force_inline proc "contextless" ( font : ^ParserFontInfo, glyph_index : Glyph ) -> b32
|
parser_is_glyph_empty :: #force_inline proc "contextless" ( font : ^Parser_Font_Info, glyph_index : Glyph ) -> b32
|
||||||
{
|
{
|
||||||
switch font.kind
|
switch font.kind
|
||||||
{
|
{
|
||||||
@@ -262,7 +262,7 @@ parser_is_glyph_empty :: #force_inline proc "contextless" ( font : ^ParserFontIn
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
parser_scale :: #force_inline proc "contextless" ( font : ^ParserFontInfo, size : f32 ) -> f32
|
parser_scale :: #force_inline proc "contextless" ( font : ^Parser_Font_Info, size : f32 ) -> f32
|
||||||
{
|
{
|
||||||
size_scale := size < 0.0 ? \
|
size_scale := size < 0.0 ? \
|
||||||
parser_scale_for_pixel_height( font, -size ) \
|
parser_scale_for_pixel_height( font, -size ) \
|
||||||
@@ -271,7 +271,7 @@ parser_scale :: #force_inline proc "contextless" ( font : ^ParserFontInfo, size
|
|||||||
return size_scale
|
return size_scale
|
||||||
}
|
}
|
||||||
|
|
||||||
parser_scale_for_pixel_height :: #force_inline proc "contextless" ( font : ^ParserFontInfo, size : f32 ) -> f32
|
parser_scale_for_pixel_height :: #force_inline proc "contextless" ( font : ^Parser_Font_Info, size : f32 ) -> f32
|
||||||
{
|
{
|
||||||
switch font.kind {
|
switch font.kind {
|
||||||
case .Freetype:
|
case .Freetype:
|
||||||
@@ -285,7 +285,7 @@ parser_scale_for_pixel_height :: #force_inline proc "contextless" ( font : ^Pars
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
parser_scale_for_mapping_em_to_pixels :: #force_inline proc "contextless" ( font : ^ParserFontInfo, size : f32 ) -> f32
|
parser_scale_for_mapping_em_to_pixels :: #force_inline proc "contextless" ( font : ^Parser_Font_Info, size : f32 ) -> f32
|
||||||
{
|
{
|
||||||
switch font.kind {
|
switch font.kind {
|
||||||
case .Freetype:
|
case .Freetype:
|
||||||
|
@@ -1,14 +1,14 @@
|
|||||||
package vefontcache
|
package vefontcache
|
||||||
|
|
||||||
ShapedText :: struct {
|
Shaped_Text :: struct {
|
||||||
glyphs : [dynamic]Glyph,
|
glyphs : [dynamic]Glyph,
|
||||||
positions : [dynamic]Vec2,
|
positions : [dynamic]Vec2,
|
||||||
end_cursor_pos : Vec2,
|
end_cursor_pos : Vec2,
|
||||||
size : Vec2,
|
size : Vec2,
|
||||||
}
|
}
|
||||||
|
|
||||||
ShapedTextCache :: struct {
|
Shaped_Text_Cache :: struct {
|
||||||
storage : [dynamic]ShapedText,
|
storage : [dynamic]Shaped_Text,
|
||||||
state : LRU_Cache,
|
state : LRU_Cache,
|
||||||
next_cache_id : i32,
|
next_cache_id : i32,
|
||||||
}
|
}
|
||||||
@@ -19,11 +19,11 @@ shape_lru_hash :: #force_inline proc "contextless" ( hash : ^u64, bytes : []byte
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
shape_text_cached :: proc( ctx : ^Context, font : FontID, text_utf8 : string, entry : ^Entry ) -> ^ShapedText
|
shape_text_cached :: proc( ctx : ^Context, font : Font_ID, text_utf8 : string, entry : ^Entry ) -> ^Shaped_Text
|
||||||
{
|
{
|
||||||
// profile(#procedure)
|
// profile(#procedure)
|
||||||
font := font
|
font := font
|
||||||
font_bytes := slice_ptr( transmute(^byte) & font, size_of(FontID) )
|
font_bytes := slice_ptr( transmute(^byte) & font, size_of(Font_ID) )
|
||||||
text_bytes := transmute( []byte) text_utf8
|
text_bytes := transmute( []byte) text_utf8
|
||||||
|
|
||||||
lru_code : u64
|
lru_code : u64
|
||||||
@@ -33,23 +33,23 @@ shape_text_cached :: proc( ctx : ^Context, font : FontID, text_utf8 : string, en
|
|||||||
shape_cache := & ctx.shape_cache
|
shape_cache := & ctx.shape_cache
|
||||||
state := & ctx.shape_cache.state
|
state := & ctx.shape_cache.state
|
||||||
|
|
||||||
shape_cache_idx := LRU_get( state, lru_code )
|
shape_cache_idx := lru_get( state, lru_code )
|
||||||
if shape_cache_idx == -1
|
if shape_cache_idx == -1
|
||||||
{
|
{
|
||||||
if shape_cache.next_cache_id < i32(state.capacity) {
|
if shape_cache.next_cache_id < i32(state.capacity) {
|
||||||
shape_cache_idx = shape_cache.next_cache_id
|
shape_cache_idx = shape_cache.next_cache_id
|
||||||
shape_cache.next_cache_id += 1
|
shape_cache.next_cache_id += 1
|
||||||
evicted := LRU_put( state, lru_code, shape_cache_idx )
|
evicted := lru_put( state, lru_code, shape_cache_idx )
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
next_evict_idx := LRU_get_next_evicted( state )
|
next_evict_idx := lru_get_next_evicted( state )
|
||||||
assert( next_evict_idx != 0xFFFFFFFFFFFFFFFF )
|
assert( next_evict_idx != 0xFFFFFFFFFFFFFFFF )
|
||||||
|
|
||||||
shape_cache_idx = LRU_peek( state, next_evict_idx, must_find = true )
|
shape_cache_idx = lru_peek( state, next_evict_idx, must_find = true )
|
||||||
assert( shape_cache_idx != - 1 )
|
assert( shape_cache_idx != - 1 )
|
||||||
|
|
||||||
LRU_put( state, lru_code, shape_cache_idx )
|
lru_put( state, lru_code, shape_cache_idx )
|
||||||
}
|
}
|
||||||
|
|
||||||
shape_entry := & shape_cache.storage[ shape_cache_idx ]
|
shape_entry := & shape_cache.storage[ shape_cache_idx ]
|
||||||
@@ -59,7 +59,7 @@ shape_text_cached :: proc( ctx : ^Context, font : FontID, text_utf8 : string, en
|
|||||||
return & shape_cache.storage[ shape_cache_idx ]
|
return & shape_cache.storage[ shape_cache_idx ]
|
||||||
}
|
}
|
||||||
|
|
||||||
shape_text_uncached :: proc( ctx : ^Context, font : FontID, text_utf8 : string, entry : ^Entry, output : ^ShapedText )
|
shape_text_uncached :: proc( ctx : ^Context, font : Font_ID, text_utf8 : string, entry : ^Entry, output : ^Shaped_Text )
|
||||||
{
|
{
|
||||||
// profile(#procedure)
|
// profile(#procedure)
|
||||||
assert( ctx != nil )
|
assert( ctx != nil )
|
||||||
@@ -106,7 +106,7 @@ shape_text_uncached :: proc( ctx : ^Context, font : FontID, text_utf8 : string,
|
|||||||
prev_codepoint = rune(0)
|
prev_codepoint = rune(0)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if abs( entry.size ) <= Advance_Snap_Smallfont_Size {
|
if abs( entry.size ) <= ADVANCE_SNAP_SMALLFONT_SIZE {
|
||||||
position.x = position.x
|
position.x = position.x
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -6,35 +6,35 @@ Note(Ed): The only reason I didn't directly use harfbuzz is because hamza exists
|
|||||||
import "core:c"
|
import "core:c"
|
||||||
import "thirdparty:harfbuzz"
|
import "thirdparty:harfbuzz"
|
||||||
|
|
||||||
ShaperKind :: enum {
|
Shaper_Kind :: enum {
|
||||||
Naive = 0,
|
Naive = 0,
|
||||||
Harfbuzz = 1,
|
Harfbuzz = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaperContext :: struct {
|
Shaper_Context :: struct {
|
||||||
hb_buffer : harfbuzz.Buffer,
|
hb_buffer : harfbuzz.Buffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaperInfo :: struct {
|
Shaper_Info :: struct {
|
||||||
blob : harfbuzz.Blob,
|
blob : harfbuzz.Blob,
|
||||||
face : harfbuzz.Face,
|
face : harfbuzz.Face,
|
||||||
font : harfbuzz.Font,
|
font : harfbuzz.Font,
|
||||||
}
|
}
|
||||||
|
|
||||||
shaper_init :: proc( ctx : ^ShaperContext )
|
shaper_init :: proc( ctx : ^Shaper_Context )
|
||||||
{
|
{
|
||||||
ctx.hb_buffer = harfbuzz.buffer_create()
|
ctx.hb_buffer = harfbuzz.buffer_create()
|
||||||
assert( ctx.hb_buffer != nil, "VEFontCache.shaper_init: Failed to create harfbuzz buffer")
|
assert( ctx.hb_buffer != nil, "VEFontCache.shaper_init: Failed to create harfbuzz buffer")
|
||||||
}
|
}
|
||||||
|
|
||||||
shaper_shutdown :: proc( ctx : ^ShaperContext )
|
shaper_shutdown :: proc( ctx : ^Shaper_Context )
|
||||||
{
|
{
|
||||||
if ctx.hb_buffer != nil {
|
if ctx.hb_buffer != nil {
|
||||||
harfbuzz.buffer_destroy( ctx.hb_buffer )
|
harfbuzz.buffer_destroy( ctx.hb_buffer )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
shaper_load_font :: proc( ctx : ^ShaperContext, label : string, data : []byte, user_data : rawptr ) -> (info : ShaperInfo)
|
shaper_load_font :: proc( ctx : ^Shaper_Context, label : string, data : []byte, user_data : rawptr ) -> (info : Shaper_Info)
|
||||||
{
|
{
|
||||||
using info
|
using info
|
||||||
blob = harfbuzz.blob_create( raw_data(data), cast(c.uint) len(data), harfbuzz.Memory_Mode.READONLY, user_data, nil )
|
blob = harfbuzz.blob_create( raw_data(data), cast(c.uint) len(data), harfbuzz.Memory_Mode.READONLY, user_data, nil )
|
||||||
@@ -43,7 +43,7 @@ shaper_load_font :: proc( ctx : ^ShaperContext, label : string, data : []byte, u
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
shaper_unload_font :: proc( ctx : ^ShaperInfo )
|
shaper_unload_font :: proc( ctx : ^Shaper_Info )
|
||||||
{
|
{
|
||||||
using ctx
|
using ctx
|
||||||
if blob != nil do harfbuzz.font_destroy( font )
|
if blob != nil do harfbuzz.font_destroy( font )
|
||||||
@@ -51,7 +51,7 @@ shaper_unload_font :: proc( ctx : ^ShaperInfo )
|
|||||||
if blob != nil do harfbuzz.blob_destroy( blob )
|
if blob != nil do harfbuzz.blob_destroy( blob )
|
||||||
}
|
}
|
||||||
|
|
||||||
shaper_shape_from_text :: proc( ctx : ^ShaperContext, info : ^ShaperInfo, output :^ShapedText, text_utf8 : string,
|
shaper_shape_from_text :: proc( ctx : ^Shaper_Context, info : ^Shaper_Info, output :^Shaped_Text, text_utf8 : string,
|
||||||
ascent, descent, line_gap : i32, size, size_scale : f32 )
|
ascent, descent, line_gap : i32, size, size_scale : f32 )
|
||||||
{
|
{
|
||||||
// profile(#procedure)
|
// profile(#procedure)
|
||||||
@@ -69,7 +69,7 @@ shaper_shape_from_text :: proc( ctx : ^ShaperContext, info : ^ShaperInfo, output
|
|||||||
line_height := (ascent - descent + line_gap) * size_scale
|
line_height := (ascent - descent + line_gap) * size_scale
|
||||||
|
|
||||||
position, vertical_position : f32
|
position, vertical_position : f32
|
||||||
shape_run :: proc( buffer : harfbuzz.Buffer, script : harfbuzz.Script, font : harfbuzz.Font, output : ^ShapedText,
|
shape_run :: proc( buffer : harfbuzz.Buffer, script : harfbuzz.Script, font : harfbuzz.Font, output : ^Shaped_Text,
|
||||||
position, vertical_position, max_line_width: ^f32, line_count: ^int,
|
position, vertical_position, max_line_width: ^f32, line_count: ^int,
|
||||||
ascent, descent, line_gap, size, size_scale: f32 )
|
ascent, descent, line_gap, size, size_scale: f32 )
|
||||||
{
|
{
|
||||||
@@ -105,7 +105,7 @@ shaper_shape_from_text :: proc( ctx : ^ShaperContext, info : ^ShaperInfo, output
|
|||||||
(line_count^) += 1
|
(line_count^) += 1
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if abs( size ) <= Advance_Snap_Smallfont_Size
|
if abs( size ) <= ADVANCE_SNAP_SMALLFONT_SIZE
|
||||||
{
|
{
|
||||||
(position^) = ceil( position^ )
|
(position^) = ceil( position^ )
|
||||||
}
|
}
|
||||||
|
@@ -7,15 +7,15 @@ package vefontcache
|
|||||||
|
|
||||||
import "base:runtime"
|
import "base:runtime"
|
||||||
|
|
||||||
Advance_Snap_Smallfont_Size :: 0
|
ADVANCE_SNAP_SMALLFONT_SIZE :: 0
|
||||||
|
|
||||||
FontID :: distinct i64
|
Font_ID :: distinct i64
|
||||||
Glyph :: distinct i32
|
Glyph :: distinct i32
|
||||||
|
|
||||||
Entry :: struct {
|
Entry :: struct {
|
||||||
parser_info : ParserFontInfo,
|
parser_info : Parser_Font_Info,
|
||||||
shaper_info : ShaperInfo,
|
shaper_info : Shaper_Info,
|
||||||
id : FontID,
|
id : Font_ID,
|
||||||
used : b32,
|
used : b32,
|
||||||
curve_quality : f32,
|
curve_quality : f32,
|
||||||
size : f32,
|
size : f32,
|
||||||
@@ -32,8 +32,8 @@ Entry_Default :: Entry {
|
|||||||
Context :: struct {
|
Context :: struct {
|
||||||
backing : Allocator,
|
backing : Allocator,
|
||||||
|
|
||||||
parser_ctx : ParserContext,
|
parser_ctx : Parser_Context,
|
||||||
shaper_ctx : ShaperContext,
|
shaper_ctx : Shaper_Context,
|
||||||
|
|
||||||
entries : [dynamic]Entry,
|
entries : [dynamic]Entry,
|
||||||
|
|
||||||
@@ -54,10 +54,10 @@ Context :: struct {
|
|||||||
calls_offset : int,
|
calls_offset : int,
|
||||||
},
|
},
|
||||||
|
|
||||||
draw_list : DrawList,
|
draw_list : Draw_List,
|
||||||
atlas : Atlas,
|
atlas : Atlas,
|
||||||
glyph_buffer : GlyphDrawBuffer,
|
glyph_buffer : Glyph_Draw_Buffer,
|
||||||
shape_cache : ShapedTextCache,
|
shape_cache : Shaped_Text_Cache,
|
||||||
|
|
||||||
default_curve_quality : i32,
|
default_curve_quality : i32,
|
||||||
text_shape_adv : b32,
|
text_shape_adv : b32,
|
||||||
@@ -69,23 +69,23 @@ Context :: struct {
|
|||||||
|
|
||||||
//#region("lifetime")
|
//#region("lifetime")
|
||||||
|
|
||||||
InitAtlasRegionParams :: struct {
|
Init_Atlas_Region_Params :: struct {
|
||||||
width : u32,
|
width : u32,
|
||||||
height : u32,
|
height : u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
InitAtlasParams :: struct {
|
Init_Atlas_Params :: struct {
|
||||||
width : u32,
|
width : u32,
|
||||||
height : u32,
|
height : u32,
|
||||||
glyph_padding : u32,
|
glyph_padding : u32,
|
||||||
|
|
||||||
region_a : InitAtlasRegionParams,
|
region_a : Init_Atlas_Region_Params,
|
||||||
region_b : InitAtlasRegionParams,
|
region_b : Init_Atlas_Region_Params,
|
||||||
region_c : InitAtlasRegionParams,
|
region_c : Init_Atlas_Region_Params,
|
||||||
region_d : InitAtlasRegionParams,
|
region_d : Init_Atlas_Region_Params,
|
||||||
}
|
}
|
||||||
|
|
||||||
InitAtlasParams_Default :: InitAtlasParams {
|
Init_Atlas_Params_Default :: Init_Atlas_Params {
|
||||||
width = 4096,
|
width = 4096,
|
||||||
height = 2048,
|
height = 2048,
|
||||||
glyph_padding = 4,
|
glyph_padding = 4,
|
||||||
@@ -108,34 +108,34 @@ InitAtlasParams_Default :: InitAtlasParams {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
InitGlyphDrawParams :: struct {
|
Init_Glyph_Draw_Params :: struct {
|
||||||
over_sample : Vec2i,
|
over_sample : Vec2i,
|
||||||
buffer_batch : u32,
|
buffer_batch : u32,
|
||||||
draw_padding : u32,
|
draw_padding : u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
InitGlyphDrawParams_Default :: InitGlyphDrawParams {
|
Init_Glyph_Draw_Params_Default :: Init_Glyph_Draw_Params {
|
||||||
over_sample = { 8, 8 },
|
over_sample = { 8, 8 },
|
||||||
buffer_batch = 4,
|
buffer_batch = 4,
|
||||||
draw_padding = InitAtlasParams_Default.glyph_padding,
|
draw_padding = Init_Atlas_Params_Default.glyph_padding,
|
||||||
}
|
}
|
||||||
|
|
||||||
InitShapeCacheParams :: struct {
|
Init_Shape_Cache_Params :: struct {
|
||||||
capacity : u32,
|
capacity : u32,
|
||||||
reserve_length : u32,
|
reserve_length : u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
InitShapeCacheParams_Default :: InitShapeCacheParams {
|
Init_Shape_Cache_Params_Default :: Init_Shape_Cache_Params {
|
||||||
capacity = 8 * 1024,
|
capacity = 8 * 1024,
|
||||||
reserve_length = 256,
|
reserve_length = 256,
|
||||||
}
|
}
|
||||||
|
|
||||||
// ve_fontcache_init
|
// ve_fontcache_init
|
||||||
startup :: proc( ctx : ^Context, parser_kind : ParserKind,
|
startup :: proc( ctx : ^Context, parser_kind : Parser_Kind = .STB_TrueType,
|
||||||
allocator := context.allocator,
|
allocator := context.allocator,
|
||||||
atlas_params := InitAtlasParams_Default,
|
atlas_params := Init_Atlas_Params_Default,
|
||||||
glyph_draw_params := InitGlyphDrawParams_Default,
|
glyph_draw_params := Init_Glyph_Draw_Params_Default,
|
||||||
shape_cache_params := InitShapeCacheParams_Default,
|
shape_cache_params := Init_Shape_Cache_Params_Default,
|
||||||
use_advanced_text_shaper : b32 = true,
|
use_advanced_text_shaper : b32 = true,
|
||||||
snap_shape_position : b32 = true,
|
snap_shape_position : b32 = true,
|
||||||
default_curve_quality : u32 = 3,
|
default_curve_quality : u32 = 3,
|
||||||
@@ -158,7 +158,7 @@ startup :: proc( ctx : ^Context, parser_kind : ParserKind,
|
|||||||
}
|
}
|
||||||
ctx.default_curve_quality = default_curve_quality
|
ctx.default_curve_quality = default_curve_quality
|
||||||
|
|
||||||
error : AllocatorError
|
error : Allocator_Error
|
||||||
entries, error = make( [dynamic]Entry, len = 0, cap = entires_reserve )
|
entries, error = make( [dynamic]Entry, len = 0, cap = entires_reserve )
|
||||||
assert(error == .None, "VEFontCache.init : Failed to allocate entries")
|
assert(error == .None, "VEFontCache.init : Failed to allocate entries")
|
||||||
|
|
||||||
@@ -174,10 +174,10 @@ startup :: proc( ctx : ^Context, parser_kind : ParserKind,
|
|||||||
draw_list.indices, error = make( [dynamic]u32, len = 0, cap = 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")
|
assert(error == .None, "VEFontCache.init : Failed to allocate draw_list.indices")
|
||||||
|
|
||||||
draw_list.calls, error = make( [dynamic]DrawCall, len = 0, cap = 512 )
|
draw_list.calls, error = make( [dynamic]Draw_Call, len = 0, cap = 512 )
|
||||||
assert(error == .None, "VEFontCache.init : Failed to allocate draw_list.calls")
|
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 : ^Atlas_Region, params : Init_Atlas_Params, region_params : Init_Atlas_Region_Params, factor : Vec2i, expected_cap : i32 )
|
||||||
{
|
{
|
||||||
using region
|
using region
|
||||||
|
|
||||||
@@ -194,8 +194,8 @@ startup :: proc( ctx : ^Context, parser_kind : ParserKind,
|
|||||||
}
|
}
|
||||||
assert( capacity.x * capacity.y == expected_cap )
|
assert( capacity.x * capacity.y == expected_cap )
|
||||||
|
|
||||||
error : AllocatorError
|
error : Allocator_Error
|
||||||
LRU_init( & state, capacity.x * capacity.y )
|
lru_init( & state, capacity.x * capacity.y )
|
||||||
}
|
}
|
||||||
init_atlas_region( & atlas.region_a, atlas_params, atlas_params.region_a, { 4, 2}, 1024 )
|
init_atlas_region( & atlas.region_a, atlas_params, atlas_params.region_a, { 4, 2}, 1024 )
|
||||||
init_atlas_region( & atlas.region_b, atlas_params, atlas_params.region_b, { 4, 2}, 512 )
|
init_atlas_region( & atlas.region_b, atlas_params, atlas_params.region_b, { 4, 2}, 512 )
|
||||||
@@ -214,9 +214,9 @@ startup :: proc( ctx : ^Context, parser_kind : ParserKind,
|
|||||||
atlas.region_d.offset.x = atlas.width / 2
|
atlas.region_d.offset.x = atlas.width / 2
|
||||||
atlas.region_d.offset.y = 0
|
atlas.region_d.offset.y = 0
|
||||||
|
|
||||||
LRU_init( & shape_cache.state, i32(shape_cache_params.capacity) )
|
lru_init( & shape_cache.state, i32(shape_cache_params.capacity) )
|
||||||
|
|
||||||
shape_cache.storage, error = make( [dynamic]ShapedText, shape_cache_params.capacity )
|
shape_cache.storage, error = make( [dynamic]Shaped_Text, shape_cache_params.capacity )
|
||||||
assert(error == .None, "VEFontCache.init : Failed to allocate shape_cache.storage")
|
assert(error == .None, "VEFontCache.init : Failed to allocate shape_cache.storage")
|
||||||
|
|
||||||
for idx : u32 = 0; idx < shape_cache_params.capacity; idx += 1 {
|
for idx : u32 = 0; idx < shape_cache_params.capacity; idx += 1 {
|
||||||
@@ -228,7 +228,7 @@ startup :: proc( ctx : ^Context, parser_kind : ParserKind,
|
|||||||
positions, error = make( [dynamic]Vec2, len = 0, cap = 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" )
|
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 )
|
draw_list.calls, error = make( [dynamic]Draw_Call, len = 0, cap = 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( [dynamic]u32, len = 0, cap = glyph_draw_params.buffer_batch * 2 * 6 )
|
draw_list.indices, error = make( [dynamic]u32, len = 0, cap = glyph_draw_params.buffer_batch * 2 * 6 )
|
||||||
@@ -247,7 +247,7 @@ startup :: proc( ctx : ^Context, parser_kind : ParserKind,
|
|||||||
height = atlas.region_d.height * i32(over_sample.y)
|
height = atlas.region_d.height * i32(over_sample.y)
|
||||||
draw_padding = cast(i32) glyph_draw_params.draw_padding
|
draw_padding = cast(i32) glyph_draw_params.draw_padding
|
||||||
|
|
||||||
draw_list.calls, error = make( [dynamic]DrawCall, len = 0, cap = glyph_draw_params.buffer_batch * 2 )
|
draw_list.calls, error = make( [dynamic]Draw_Call, len = 0, cap = 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( [dynamic]u32, len = 0, cap = glyph_draw_params.buffer_batch * 2 * 6 )
|
draw_list.indices, error = make( [dynamic]u32, len = 0, cap = glyph_draw_params.buffer_batch * 2 * 6 )
|
||||||
@@ -256,7 +256,7 @@ startup :: proc( ctx : ^Context, parser_kind : ParserKind,
|
|||||||
draw_list.vertices, error = make( [dynamic]Vertex, len = 0, cap = 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" )
|
assert( error == .None, "VEFontCache.init : Failed to allocate vertices array for draw_list" )
|
||||||
|
|
||||||
clear_draw_list.calls, error = make( [dynamic]DrawCall, len = 0, cap = glyph_draw_params.buffer_batch * 2 )
|
clear_draw_list.calls, error = make( [dynamic]Draw_Call, len = 0, cap = 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( [dynamic]u32, len = 0, cap = 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 )
|
||||||
@@ -285,12 +285,12 @@ hot_reload :: proc( ctx : ^Context, allocator : Allocator )
|
|||||||
reload_array( & draw_list.indices, allocator )
|
reload_array( & draw_list.indices, allocator )
|
||||||
reload_array( & draw_list.calls, allocator )
|
reload_array( & draw_list.calls, allocator )
|
||||||
|
|
||||||
LRU_reload( & atlas.region_a.state, allocator)
|
lru_reload( & atlas.region_a.state, allocator)
|
||||||
LRU_reload( & atlas.region_b.state, allocator)
|
lru_reload( & atlas.region_b.state, allocator)
|
||||||
LRU_reload( & atlas.region_c.state, allocator)
|
lru_reload( & atlas.region_c.state, allocator)
|
||||||
LRU_reload( & atlas.region_d.state, allocator)
|
lru_reload( & atlas.region_d.state, allocator)
|
||||||
|
|
||||||
LRU_reload( & shape_cache.state, allocator )
|
lru_reload( & shape_cache.state, allocator )
|
||||||
for idx : i32 = 0; idx < i32(len(shape_cache.storage)); idx += 1 {
|
for idx : i32 = 0; idx < i32(len(shape_cache.storage)); idx += 1 {
|
||||||
stroage_entry := & shape_cache.storage[idx]
|
stroage_entry := & shape_cache.storage[idx]
|
||||||
using stroage_entry
|
using stroage_entry
|
||||||
@@ -308,7 +308,7 @@ hot_reload :: proc( ctx : ^Context, allocator : Allocator )
|
|||||||
reload_array( & glyph_buffer.clear_draw_list.vertices, allocator )
|
reload_array( & glyph_buffer.clear_draw_list.vertices, allocator )
|
||||||
|
|
||||||
reload_array( & shape_cache.storage, allocator )
|
reload_array( & shape_cache.storage, allocator )
|
||||||
LRU_reload( & shape_cache.state, allocator )
|
lru_reload( & shape_cache.state, allocator )
|
||||||
}
|
}
|
||||||
|
|
||||||
// ve_foncache_shutdown
|
// ve_foncache_shutdown
|
||||||
@@ -330,10 +330,10 @@ shutdown :: proc( ctx : ^Context )
|
|||||||
delete( draw_list.indices )
|
delete( draw_list.indices )
|
||||||
delete( draw_list.calls )
|
delete( draw_list.calls )
|
||||||
|
|
||||||
LRU_free( & atlas.region_a.state )
|
lru_free( & atlas.region_a.state )
|
||||||
LRU_free( & atlas.region_b.state )
|
lru_free( & atlas.region_b.state )
|
||||||
LRU_free( & atlas.region_c.state )
|
lru_free( & atlas.region_c.state )
|
||||||
LRU_free( & atlas.region_d.state )
|
lru_free( & atlas.region_d.state )
|
||||||
|
|
||||||
for idx : i32 = 0; idx < i32(len(shape_cache.storage)); idx += 1 {
|
for idx : i32 = 0; idx < i32(len(shape_cache.storage)); idx += 1 {
|
||||||
stroage_entry := & shape_cache.storage[idx]
|
stroage_entry := & shape_cache.storage[idx]
|
||||||
@@ -342,7 +342,7 @@ shutdown :: proc( ctx : ^Context )
|
|||||||
delete( glyphs )
|
delete( glyphs )
|
||||||
delete( positions )
|
delete( positions )
|
||||||
}
|
}
|
||||||
LRU_free( & shape_cache.state )
|
lru_free( & shape_cache.state )
|
||||||
|
|
||||||
delete( glyph_buffer.draw_list.vertices )
|
delete( glyph_buffer.draw_list.vertices )
|
||||||
delete( glyph_buffer.draw_list.indices )
|
delete( glyph_buffer.draw_list.indices )
|
||||||
@@ -357,7 +357,7 @@ shutdown :: proc( ctx : ^Context )
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ve_fontcache_load
|
// ve_fontcache_load
|
||||||
load_font :: proc( ctx : ^Context, label : string, data : []byte, size_px : f32, glyph_curve_quality : u32 = 0 ) -> (font_id : FontID)
|
load_font :: proc( ctx : ^Context, label : string, data : []byte, size_px : f32, glyph_curve_quality : u32 = 0 ) -> (font_id : Font_ID)
|
||||||
{
|
{
|
||||||
assert( ctx != nil )
|
assert( ctx != nil )
|
||||||
assert( len(data) > 0 )
|
assert( len(data) > 0 )
|
||||||
@@ -386,9 +386,9 @@ load_font :: proc( ctx : ^Context, label : string, data : []byte, size_px : f32,
|
|||||||
shaper_info = shaper_load_font( & shaper_ctx, label, data, transmute(rawptr) id )
|
shaper_info = shaper_load_font( & shaper_ctx, label, data, transmute(rawptr) id )
|
||||||
|
|
||||||
size = size_px
|
size = size_px
|
||||||
size_scale = size_px < 0.0 ? \
|
size_scale = size_px < 0.0 ? \
|
||||||
parser_scale_for_pixel_height( & parser_info, -size_px ) \
|
parser_scale_for_pixel_height( & parser_info, -size_px ) \
|
||||||
: parser_scale_for_mapping_em_to_pixels( & parser_info, size_px )
|
: parser_scale_for_mapping_em_to_pixels( & parser_info, size_px )
|
||||||
|
|
||||||
if glyph_curve_quality == 0 {
|
if glyph_curve_quality == 0 {
|
||||||
curve_quality = f32(ctx.default_curve_quality)
|
curve_quality = f32(ctx.default_curve_quality)
|
||||||
@@ -397,15 +397,15 @@ load_font :: proc( ctx : ^Context, label : string, data : []byte, size_px : f32,
|
|||||||
curve_quality = f32(glyph_curve_quality)
|
curve_quality = f32(glyph_curve_quality)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
entry.id = FontID(id)
|
entry.id = Font_ID(id)
|
||||||
ctx.entries[ id ].id = FontID(id)
|
ctx.entries[ id ].id = Font_ID(id)
|
||||||
|
|
||||||
font_id = FontID(id)
|
font_id = Font_ID(id)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// ve_fontcache_unload
|
// ve_fontcache_unload
|
||||||
unload_font :: proc( ctx : ^Context, font : FontID )
|
unload_font :: proc( ctx : ^Context, font : Font_ID )
|
||||||
{
|
{
|
||||||
assert( ctx != nil )
|
assert( ctx != nil )
|
||||||
assert( font >= 0 && int(font) < len(ctx.entries) )
|
assert( font >= 0 && int(font) < len(ctx.entries) )
|
||||||
@@ -430,10 +430,10 @@ configure_snap :: #force_inline proc( ctx : ^Context, snap_width, snap_height :
|
|||||||
ctx.snap_height = f32(snap_height)
|
ctx.snap_height = f32(snap_height)
|
||||||
}
|
}
|
||||||
|
|
||||||
get_cursor_pos :: #force_inline proc "contextless" ( ctx : ^Context ) -> Vec2 { return ctx.cursor_pos }
|
get_cursor_pos :: #force_inline proc( ctx : ^Context ) -> Vec2 { assert(ctx != nil); return ctx.cursor_pos }
|
||||||
set_colour :: #force_inline proc "contextless" ( ctx : ^Context, colour : Colour ) { ctx.colour = colour }
|
set_colour :: #force_inline proc( ctx : ^Context, colour : Colour ) { assert(ctx != nil); ctx.colour = colour }
|
||||||
|
|
||||||
draw_text :: proc( ctx : ^Context, font : FontID, text_utf8 : string, position, scale : Vec2 ) -> b32
|
draw_text :: proc( ctx : ^Context, font : Font_ID, text_utf8 : string, position, scale : Vec2 ) -> b32
|
||||||
{
|
{
|
||||||
// profile(#procedure)
|
// profile(#procedure)
|
||||||
assert( ctx != nil )
|
assert( ctx != nil )
|
||||||
@@ -463,14 +463,14 @@ draw_text :: proc( ctx : ^Context, font : FontID, text_utf8 : string, position,
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// ve_fontcache_drawlist
|
// ve_fontcache_Draw_List
|
||||||
get_draw_list :: proc( ctx : ^Context, optimize_before_returning := true ) -> ^DrawList {
|
get_draw_list :: proc( ctx : ^Context, optimize_before_returning := true ) -> ^Draw_List {
|
||||||
assert( ctx != nil )
|
assert( ctx != nil )
|
||||||
if optimize_before_returning do optimize_draw_list( & ctx.draw_list, 0 )
|
if optimize_before_returning do optimize_draw_list( & ctx.draw_list, 0 )
|
||||||
return & ctx.draw_list
|
return & ctx.draw_list
|
||||||
}
|
}
|
||||||
|
|
||||||
get_draw_list_layer :: proc( ctx : ^Context, optimize_before_returning := true ) -> (vertices : []Vertex, indices : []u32, calls : []DrawCall) {
|
get_draw_list_layer :: proc( ctx : ^Context, optimize_before_returning := true ) -> (vertices : []Vertex, indices : []u32, calls : []Draw_Call) {
|
||||||
assert( ctx != nil )
|
assert( ctx != nil )
|
||||||
if optimize_before_returning do optimize_draw_list( & ctx.draw_list, ctx.draw_layer.calls_offset )
|
if optimize_before_returning do optimize_draw_list( & ctx.draw_list, ctx.draw_layer.calls_offset )
|
||||||
vertices = ctx.draw_list.vertices[ ctx.draw_layer.vertices_offset : ]
|
vertices = ctx.draw_list.vertices[ ctx.draw_layer.vertices_offset : ]
|
||||||
@@ -479,7 +479,7 @@ get_draw_list_layer :: proc( ctx : ^Context, optimize_before_returning := true )
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// ve_fontcache_flush_drawlist
|
// ve_fontcache_flush_Draw_List
|
||||||
flush_draw_list :: proc( ctx : ^Context ) {
|
flush_draw_list :: proc( ctx : ^Context ) {
|
||||||
assert( ctx != nil )
|
assert( ctx != nil )
|
||||||
using ctx
|
using ctx
|
||||||
@@ -501,7 +501,7 @@ flush_draw_list_layer :: proc( ctx : ^Context ) {
|
|||||||
|
|
||||||
//#region("metrics")
|
//#region("metrics")
|
||||||
|
|
||||||
measure_text_size :: proc( ctx : ^Context, font : FontID, text_utf8 : string ) -> (measured : Vec2)
|
measure_text_size :: proc( ctx : ^Context, font : Font_ID, text_utf8 : string ) -> (measured : Vec2)
|
||||||
{
|
{
|
||||||
// profile(#procedure)
|
// profile(#procedure)
|
||||||
assert( ctx != nil )
|
assert( ctx != nil )
|
||||||
@@ -512,7 +512,7 @@ measure_text_size :: proc( ctx : ^Context, font : FontID, text_utf8 : string ) -
|
|||||||
return shaped.size
|
return shaped.size
|
||||||
}
|
}
|
||||||
|
|
||||||
get_font_vertical_metrics :: #force_inline proc ( ctx : ^Context, font : FontID ) -> ( ascent, descent, line_gap : f32 )
|
get_font_vertical_metrics :: #force_inline proc ( ctx : ^Context, font : Font_ID ) -> ( ascent, descent, line_gap : f32 )
|
||||||
{
|
{
|
||||||
assert( ctx != nil )
|
assert( ctx != nil )
|
||||||
assert( font >= 0 && int(font) < len(ctx.entries) )
|
assert( font >= 0 && int(font) < len(ctx.entries) )
|
||||||
|
Reference in New Issue
Block a user