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