Starting the process of porting VEFontCache
This commit is contained in:
69
code/font/VEFontCache/LRU.odin
Normal file
69
code/font/VEFontCache/LRU.odin
Normal file
@ -0,0 +1,69 @@
|
||||
package VEFontCache
|
||||
|
||||
/*
|
||||
The choice was made to keep the LUR cache implementation as close to the original as possible.
|
||||
*/
|
||||
|
||||
PoolListIter :: u32
|
||||
PoolListValue :: u64
|
||||
|
||||
PoolListItem :: struct {
|
||||
prev : PoolListIter,
|
||||
next : PoolListIter,
|
||||
value : PoolListValue,
|
||||
}
|
||||
|
||||
PoolList :: struct {
|
||||
items : Array( PoolListItem ),
|
||||
free_list : Array( PoolListIter ),
|
||||
front : PoolListIter,
|
||||
back : PoolListIter,
|
||||
size : i32,
|
||||
capacity : i32,
|
||||
}
|
||||
|
||||
pool_list_init :: proc( pool : ^PoolList, capacity : u32 )
|
||||
{
|
||||
error : AllocatorError
|
||||
pool.items, error = make( Array( PoolListItem ), u64(capacity) )
|
||||
assert( error == .None, "VEFontCache.pool_list_init : Failed to allocate items array")
|
||||
|
||||
pool.free_list, error = make( Array( PoolListIter ), u64(capacity) )
|
||||
assert( error == .None, "VEFontCache.pool_list_init : Failed to allocate free_list array")
|
||||
|
||||
pool.capacity = i32(capacity)
|
||||
|
||||
for id in 0 ..< capacity do pool.free_list.data[id] = id
|
||||
}
|
||||
|
||||
pool_list_push_front :: proc( pool : ^PoolList, value : PoolListValue )
|
||||
{
|
||||
using pool
|
||||
if size >= capacity do return
|
||||
assert( free_list.num > 0 )
|
||||
assert( free_list.num == u64(capacity - size) )
|
||||
|
||||
id := array_back( free_list )
|
||||
}
|
||||
|
||||
LRU_Link :: struct {
|
||||
value : i32,
|
||||
ptr : PoolListIter,
|
||||
}
|
||||
|
||||
LRU_Cache :: struct {
|
||||
capacity : i32,
|
||||
table : HMapChained(LRU_Link),
|
||||
key_queue : PoolList,
|
||||
}
|
||||
|
||||
LRU_init :: proc( cache : ^LRU_Cache, capacity : u32 )
|
||||
{
|
||||
error : AllocatorError
|
||||
cache.capacity = i32(capacity)
|
||||
cache.table, error = make( HMapChained(LRU_Link), uint(capacity) )
|
||||
assert( error != .None, "VEFontCache.LRU_init : Failed to allocate cache's table")
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,204 @@
|
||||
/*
|
||||
A port of (https://github.com/hypernewbie/VEFontCache) to Odin.
|
||||
|
||||
Status:
|
||||
This port is heavily tied to the grime package in SectrPrototype.
|
||||
|
||||
TODO(Ed): Make an idiomatic port of this for Odin (or just dupe the data structures...)
|
||||
*/
|
||||
package VEFontCache
|
||||
|
||||
Font_ID :: i64
|
||||
Glyph :: i32
|
||||
|
||||
Colour :: [4]f32
|
||||
Vec2 :: [2]f32
|
||||
Vec2i :: [2]u32
|
||||
|
||||
AtlasRegionKind :: enum {
|
||||
A = 0,
|
||||
B = 1,
|
||||
C = 2,
|
||||
D = 3
|
||||
}
|
||||
|
||||
Vertex :: struct {
|
||||
pos : Vec2,
|
||||
u, v : f32,
|
||||
}
|
||||
|
||||
// GlyphDrawBuffer :: struct {
|
||||
// over_sample : Vec2,
|
||||
|
||||
// batch : i32,
|
||||
// width : i32,
|
||||
// height : i32,
|
||||
// padding : i32,
|
||||
// }
|
||||
|
||||
ShapedText :: struct {
|
||||
Glyphs : Array(Glyph),
|
||||
Positions : Array(Vec2),
|
||||
end_cursor_pos : Vec2,
|
||||
}
|
||||
|
||||
ShapedTextCache :: struct {
|
||||
storage : Array(ShapedText),
|
||||
state : LRU_Cache,
|
||||
next_cache_id : i32,
|
||||
}
|
||||
|
||||
Entry :: struct {
|
||||
parser_info : ParserInfo,
|
||||
shaper_info : ShaperInfo,
|
||||
id : Font_ID,
|
||||
used : b32,
|
||||
size : f32,
|
||||
size_scale : f32,
|
||||
}
|
||||
|
||||
Entry_Default :: Entry {
|
||||
id = 0,
|
||||
used = false,
|
||||
size = 24.0,
|
||||
size_scale = 1.0,
|
||||
}
|
||||
|
||||
Context :: struct {
|
||||
backing : Allocator,
|
||||
|
||||
parser_kind : ParserKind,
|
||||
parser_ctx : ParserContext,
|
||||
shaper_ctx : ShaperContext,
|
||||
|
||||
entries : Array(Entry),
|
||||
|
||||
temp_path : Array(Vec2),
|
||||
temp_codepoint_seen : HMapChained(bool),
|
||||
|
||||
snap_width : u32,
|
||||
snap_height : u32,
|
||||
|
||||
colour : Colour,
|
||||
cursor_pos : Vec2,
|
||||
|
||||
draw_list : DrawList,
|
||||
atlas : Atlas,
|
||||
shape_cache : ShapedTextCache,
|
||||
|
||||
text_shape_adv : b32,
|
||||
}
|
||||
|
||||
Module_Ctx :: Context
|
||||
|
||||
InitAtlasRegionParams :: struct {
|
||||
width : u32,
|
||||
height : u32,
|
||||
offset : Vec2i,
|
||||
}
|
||||
|
||||
InitAtlasParams :: struct {
|
||||
width : u32,
|
||||
height : u32,
|
||||
glyph_padding : u32,
|
||||
|
||||
region_a : InitAtlasRegionParams,
|
||||
region_b : InitAtlasRegionParams,
|
||||
region_c : InitAtlasRegionParams,
|
||||
region_d : InitAtlasRegionParams,
|
||||
}
|
||||
|
||||
InitAtlasParams_Default :: InitAtlasParams {
|
||||
width = 4 * Kilobyte,
|
||||
height = 2 * Kilobyte,
|
||||
glyph_padding = 1,
|
||||
|
||||
|
||||
}
|
||||
|
||||
InitGlyphDrawParams :: struct {
|
||||
over_sample : Vec2i,
|
||||
buffer_batch : u32,
|
||||
padding : u32,
|
||||
}
|
||||
|
||||
InitGlyphDrawParams_Default :: InitGlyphDrawParams {
|
||||
over_sample = { 4, 4 },
|
||||
buffer_batch = 4,
|
||||
padding = InitAtlasParams_Default.glyph_padding,
|
||||
}
|
||||
|
||||
InitShapeCacheParams :: struct {
|
||||
capacity : u32,
|
||||
reserve_length : u32,
|
||||
}
|
||||
|
||||
InitShapeCacheParams_Default :: InitShapeCacheParams {
|
||||
capacity = 256,
|
||||
reserve_length = 64,
|
||||
}
|
||||
|
||||
init :: proc( ctx : ^Context,
|
||||
allocator := context.allocator,
|
||||
atlas_params := InitAtlasParams_Default,
|
||||
glyph_draw_params := InitGlyphDrawParams_Default,
|
||||
shape_cache_params := InitShapeCacheParams_Default,
|
||||
advance_snap_smallfont_size : u32 = 12,
|
||||
entires_reserve : u32 = Kilobyte,
|
||||
temp_path_reserve : u32 = Kilobyte,
|
||||
temp_codepoint_seen_reserve : u32 = 4 * Kilobyte,
|
||||
)
|
||||
{
|
||||
assert( ctx != nil, "Must provide a valid context" )
|
||||
using ctx
|
||||
|
||||
ctx.backing = allocator
|
||||
context.allocator = ctx.backing
|
||||
|
||||
error : AllocatorError
|
||||
entries, error = make( Array(Entry), u64(entires_reserve) )
|
||||
assert(error == .None, "VEFontCache.init : Failed to allocate entries")
|
||||
|
||||
temp_path, error = make( Array(Vec2), u64(temp_path_reserve) )
|
||||
assert(error == .None, "VEFontCache.init : Failed to allocate temp_path")
|
||||
|
||||
temp_codepoint_seen, error = make( HMapChained(bool), uint(temp_codepoint_seen_reserve) )
|
||||
assert(error == .None, "VEFontCache.init : Failed to allocate temp_path")
|
||||
|
||||
draw_list.vertices, error = make( Array(Vertex), 4 * Kilobyte )
|
||||
assert(error == .None, "VEFontCache.init : Failed to allocate draw_list.vertices")
|
||||
|
||||
draw_list.indices, error = make( Array(u32), 8 * Kilobyte )
|
||||
assert(error == .None, "VEFontCache.init : Failed to allocate draw_list.indices")
|
||||
|
||||
draw_list.calls, error = make( Array(DrawCall), 512 )
|
||||
assert(error == .None, "VEFontCache.init : Failed to allocate draw_list.calls")
|
||||
|
||||
init_atlas_region :: proc( region : ^AtlasRegion, params : InitAtlasParams, region_params : InitAtlasRegionParams ) {
|
||||
using region
|
||||
|
||||
next_idx = 0;
|
||||
width = region_params.width
|
||||
height = region_params.height
|
||||
size = {
|
||||
params.width / 4,
|
||||
params.height / 2,
|
||||
}
|
||||
capacity = {
|
||||
size.x / width,
|
||||
size.y / height,
|
||||
}
|
||||
offset = region_params.offset
|
||||
|
||||
error : AllocatorError
|
||||
// state.cache, error = make( HMapChained(LRU_Link), uint(capacity.x * capacity.y) )
|
||||
// assert( error == .None, "VEFontCache.init_atlas_region : Failed to allocate state.cache")
|
||||
LRU_init( & state, capacity.x * capacity.y )
|
||||
}
|
||||
init_atlas_region( & atlas.region_a, atlas_params, atlas_params.region_a )
|
||||
init_atlas_region( & atlas.region_b, atlas_params, atlas_params.region_b )
|
||||
init_atlas_region( & atlas.region_c, atlas_params, atlas_params.region_c )
|
||||
init_atlas_region( & atlas.region_d, atlas_params, atlas_params.region_d )
|
||||
|
||||
|
||||
}
|
||||
|
34
code/font/VEFontCache/atlas.odin
Normal file
34
code/font/VEFontCache/atlas.odin
Normal file
@ -0,0 +1,34 @@
|
||||
package VEFontCache
|
||||
|
||||
GlyphUpdateBatch :: struct {
|
||||
update_batch_x : i32,
|
||||
clear_draw_list : DrawList,
|
||||
draw_list : DrawList,
|
||||
}
|
||||
|
||||
AtlasRegion :: struct {
|
||||
state : LRU_Cache,
|
||||
|
||||
width : u32,
|
||||
height : u32,
|
||||
|
||||
size : Vec2i,
|
||||
capacity : Vec2i,
|
||||
offset : Vec2i,
|
||||
|
||||
next_idx : u32,
|
||||
}
|
||||
|
||||
Atlas :: struct {
|
||||
width : u32,
|
||||
height : u32,
|
||||
|
||||
glyph_pad : u16,
|
||||
|
||||
region_a : AtlasRegion,
|
||||
region_b : AtlasRegion,
|
||||
region_c : AtlasRegion,
|
||||
region_d : AtlasRegion,
|
||||
|
||||
using glyph_update_batch : GlyphUpdateBatch,
|
||||
}
|
32
code/font/VEFontCache/draw.odin
Normal file
32
code/font/VEFontCache/draw.odin
Normal file
@ -0,0 +1,32 @@
|
||||
package VEFontCache
|
||||
|
||||
FrameBufferPass :: enum {
|
||||
Glyph = 1,
|
||||
Atlas = 2,
|
||||
Target = 3,
|
||||
Target_Unchanged = 4,
|
||||
}
|
||||
|
||||
DrawCall :: struct {
|
||||
pass : u32,
|
||||
start_index : u32,
|
||||
end_index : u32,
|
||||
clear_before_draw : b32,
|
||||
region : AtlasRegionKind,
|
||||
colour : [4]f32,
|
||||
}
|
||||
|
||||
DrawCall_Default :: DrawCall {
|
||||
pass = 0,
|
||||
start_index = 0,
|
||||
end_index = 0,
|
||||
clear_before_draw = false,
|
||||
region = .A,
|
||||
colour = { 1.0, 1.0, 1.0, 1.0 }
|
||||
}
|
||||
|
||||
DrawList :: struct {
|
||||
vertices : Array(Vertex),
|
||||
indices : Array(u32),
|
||||
calls : Array(DrawCall),
|
||||
}
|
84
code/font/VEFontCache/mappings.odin
Normal file
84
code/font/VEFontCache/mappings.odin
Normal file
@ -0,0 +1,84 @@
|
||||
package VEFontCache
|
||||
|
||||
import "core:mem"
|
||||
|
||||
Kilobyte :: mem.Kilobyte
|
||||
|
||||
Allocator :: mem.Allocator
|
||||
AllocatorError :: mem.Allocator_Error
|
||||
|
||||
import "codebase:grime"
|
||||
|
||||
// asserts
|
||||
ensure :: grime.ensure
|
||||
verify :: grime.verify
|
||||
|
||||
// container
|
||||
|
||||
Array :: grime.Array
|
||||
|
||||
array_init :: grime.array_init
|
||||
array_append :: grime.array_append
|
||||
array_append_at :: grime.array_append_at
|
||||
array_back :: grime.array_back
|
||||
array_clear :: grime.array_clear
|
||||
array_free :: grime.array_free
|
||||
array_remove_at :: grime.array_remove_at
|
||||
array_to_slice :: grime.array_to_slice
|
||||
array_to_slice_cpacity :: grime.array_to_slice_capacity
|
||||
array_underlying_slice :: grime.array_underlying_slice
|
||||
|
||||
HMapChained :: grime.HMapChained
|
||||
|
||||
hmap_chained_init :: grime.hmap_chained_init
|
||||
|
||||
// Pool :: grime.Pool
|
||||
|
||||
StackFixed :: grime.StackFixed
|
||||
|
||||
stack_clear :: grime.stack_clear
|
||||
stack_push :: grime.stack_push
|
||||
stack_pop :: grime.stack_pop
|
||||
stack_peek_ref :: grime.stack_peek_ref
|
||||
stack_peek :: grime.stack_peek
|
||||
stack_push_contextless :: grime.stack_push_contextless
|
||||
|
||||
//#region("Proc overload mappings")
|
||||
|
||||
append :: proc {
|
||||
grime.array_append_array,
|
||||
grime.array_append_slice,
|
||||
grime.array_append_value,
|
||||
}
|
||||
|
||||
append_at :: proc {
|
||||
grime.array_append_at_slice,
|
||||
grime.array_append_at_value,
|
||||
}
|
||||
|
||||
clear :: proc {
|
||||
array_clear,
|
||||
}
|
||||
|
||||
delete :: proc {
|
||||
array_free,
|
||||
}
|
||||
|
||||
make :: proc {
|
||||
array_init,
|
||||
hmap_chained_init,
|
||||
}
|
||||
|
||||
remove_at :: proc {
|
||||
array_remove_at,
|
||||
}
|
||||
|
||||
to_slice :: proc {
|
||||
array_to_slice,
|
||||
}
|
||||
|
||||
underlying_slice :: proc {
|
||||
array_underlying_slice,
|
||||
}
|
||||
|
||||
//#endregion("Proc overload mappings")
|
19
code/font/VEFontCache/parser.odin
Normal file
19
code/font/VEFontCache/parser.odin
Normal file
@ -0,0 +1,19 @@
|
||||
package VEFontCache
|
||||
|
||||
import stbtt "vendor:stb/truetype"
|
||||
import freetype "thirdparty:freetype"
|
||||
|
||||
ParserKind :: enum u32 {
|
||||
stb_true_type,
|
||||
freetype,
|
||||
}
|
||||
|
||||
ParserInfo :: struct #raw_union {
|
||||
stbtt_info : stbtt.fontinfo,
|
||||
freetype_info : freetype.Face
|
||||
}
|
||||
|
||||
ParserContext :: struct {
|
||||
ft_library : freetype.Library
|
||||
}
|
||||
|
14
code/font/VEFontCache/shaper.odin
Normal file
14
code/font/VEFontCache/shaper.odin
Normal file
@ -0,0 +1,14 @@
|
||||
package VEFontCache
|
||||
|
||||
import "thirdparty:harfbuzz"
|
||||
|
||||
ShaperContext :: struct {
|
||||
hb_buffer : harfbuzz.Buffer,
|
||||
}
|
||||
|
||||
ShaperInfo :: struct {
|
||||
blob : harfbuzz.Blob,
|
||||
face : harfbuzz.Face,
|
||||
font : harfbuzz.Font,
|
||||
}
|
||||
|
3
code/sectr/font/provider_VEFontCache.odin
Normal file
3
code/sectr/font/provider_VEFontCache.odin
Normal file
@ -0,0 +1,3 @@
|
||||
package sectr
|
||||
|
||||
import "codebase:font/VEFontCache"
|
Reference in New Issue
Block a user