|  |  |  | @@ -11,6 +11,7 @@ Changes: | 
		
	
		
			
				|  |  |  |  | - Font Parser & Glyph Shaper are abstracted to their own interface | 
		
	
		
			
				|  |  |  |  | - Font Face parser info stored separately from entries | 
		
	
		
			
				|  |  |  |  | - ve_fontcache_loadfile not ported (just use odin's core:os or os2), then call load_font | 
		
	
		
			
				|  |  |  |  | - Macro defines have been made into runtime parameters | 
		
	
		
			
				|  |  |  |  | */ | 
		
	
		
			
				|  |  |  |  | package VEFontCache | 
		
	
		
			
				|  |  |  |  |  | 
		
	
	
		
			
				
					
					|  |  |  | @@ -21,12 +22,13 @@ Colour :: [4]f32 | 
		
	
		
			
				|  |  |  |  | Vec2   :: [2]f32 | 
		
	
		
			
				|  |  |  |  | Vec2i  :: [2]u32 | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | AtlasRegionKind :: enum { | 
		
	
		
			
				|  |  |  |  | 	A = 0, | 
		
	
		
			
				|  |  |  |  | 	B = 1, | 
		
	
		
			
				|  |  |  |  | 	C = 2, | 
		
	
		
			
				|  |  |  |  | 	D = 3, | 
		
	
		
			
				|  |  |  |  | 	E = 4, | 
		
	
		
			
				|  |  |  |  | AtlasRegionKind :: enum u8 { | 
		
	
		
			
				|  |  |  |  | 	None = 0x00, | 
		
	
		
			
				|  |  |  |  | 	A    = 0x41, | 
		
	
		
			
				|  |  |  |  | 	B    = 0x42, | 
		
	
		
			
				|  |  |  |  | 	C    = 0x43, | 
		
	
		
			
				|  |  |  |  | 	D    = 0x44, | 
		
	
		
			
				|  |  |  |  | 	E    = 0x45, | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | Vertex :: struct { | 
		
	
	
		
			
				
					
					|  |  |  | @@ -34,15 +36,6 @@ Vertex :: struct { | 
		
	
		
			
				|  |  |  |  | 	u, v : f32, | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | // GlyphDrawBuffer :: struct { | 
		
	
		
			
				|  |  |  |  | // 	over_sample : Vec2, | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | // 	batch   : i32, | 
		
	
		
			
				|  |  |  |  | // 	width   : i32, | 
		
	
		
			
				|  |  |  |  | // 	height  : i32, | 
		
	
		
			
				|  |  |  |  | // 	padding : i32, | 
		
	
		
			
				|  |  |  |  | // } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | ShapedText :: struct { | 
		
	
		
			
				|  |  |  |  | 	glyphs         : Array(Glyph), | 
		
	
		
			
				|  |  |  |  | 	positions      : Array(Vec2), | 
		
	
	
		
			
				
					
					|  |  |  | @@ -97,6 +90,7 @@ Context :: struct { | 
		
	
		
			
				|  |  |  |  | 	atlas       : Atlas, | 
		
	
		
			
				|  |  |  |  | 	shape_cache : ShapedTextCache, | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	curve_quality  : u32, | 
		
	
		
			
				|  |  |  |  | 	text_shape_adv : b32, | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	debug_print_verbose : b32 | 
		
	
	
		
			
				
					
					|  |  |  | @@ -150,15 +144,15 @@ InitAtlasParams_Default :: InitAtlasParams { | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | InitGlyphDrawParams :: struct { | 
		
	
		
			
				|  |  |  |  | 	over_sample  : Vec2i, | 
		
	
		
			
				|  |  |  |  | 	buffer_batch : u32, | 
		
	
		
			
				|  |  |  |  | 	padding      : u32, | 
		
	
		
			
				|  |  |  |  | 	over_sample   : Vec2, | 
		
	
		
			
				|  |  |  |  | 	buffer_batch  : u32, | 
		
	
		
			
				|  |  |  |  | 	draw_padding  : u32, | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | InitGlyphDrawParams_Default :: InitGlyphDrawParams { | 
		
	
		
			
				|  |  |  |  | 	over_sample  = { 4, 4 }, | 
		
	
		
			
				|  |  |  |  | 	buffer_batch = 4, | 
		
	
		
			
				|  |  |  |  | 	padding      = InitAtlasParams_Default.glyph_padding, | 
		
	
		
			
				|  |  |  |  | 	over_sample   = { 4, 4 }, | 
		
	
		
			
				|  |  |  |  | 	buffer_batch  = 4, | 
		
	
		
			
				|  |  |  |  | 	draw_padding  = InitAtlasParams_Default.glyph_padding, | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | InitShapeCacheParams :: struct { | 
		
	
	
		
			
				
					
					|  |  |  | @@ -177,6 +171,7 @@ init :: proc( ctx : ^Context, | 
		
	
		
			
				|  |  |  |  | 	atlas_params                := InitAtlasParams_Default, | 
		
	
		
			
				|  |  |  |  | 	glyph_draw_params           := InitGlyphDrawParams_Default, | 
		
	
		
			
				|  |  |  |  | 	shape_cache_params          := InitShapeCacheParams_Default, | 
		
	
		
			
				|  |  |  |  | 	curve_quality               : u32 = 6, | 
		
	
		
			
				|  |  |  |  | 	advance_snap_smallfont_size : u32 = 12, | 
		
	
		
			
				|  |  |  |  | 	entires_reserve             : u32 = Kilobyte, | 
		
	
		
			
				|  |  |  |  | 	temp_path_reserve           : u32 = Kilobyte, | 
		
	
	
		
			
				
					
					|  |  |  | @@ -189,6 +184,8 @@ init :: proc( ctx : ^Context, | 
		
	
		
			
				|  |  |  |  | 	ctx.backing       = allocator | 
		
	
		
			
				|  |  |  |  | 	context.allocator = ctx.backing | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	ctx.curve_quality = curve_quality | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	error : AllocatorError | 
		
	
		
			
				|  |  |  |  | 	entries, error = make( Array(Entry), u64(entires_reserve) ) | 
		
	
		
			
				|  |  |  |  | 	assert(error == .None, "VEFontCache.init : Failed to allocate entries") | 
		
	
	
		
			
				
					
					|  |  |  | @@ -233,6 +230,10 @@ init :: proc( ctx : ^Context, | 
		
	
		
			
				|  |  |  |  | 	init_atlas_region( & atlas.region_c, atlas_params, atlas_params.region_c ) | 
		
	
		
			
				|  |  |  |  | 	init_atlas_region( & atlas.region_d, atlas_params, atlas_params.region_d ) | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	atlas.width         = atlas_params.width | 
		
	
		
			
				|  |  |  |  | 	atlas.height        = atlas_params.height | 
		
	
		
			
				|  |  |  |  | 	atlas.glyph_padding = atlas_params.glyph_padding | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	atlas.region_b.offset.y = atlas.region_a.size.y | 
		
	
		
			
				|  |  |  |  | 	atlas.region_c.offset.x = atlas.region_a.size.x | 
		
	
		
			
				|  |  |  |  | 	atlas.region_d.offset.x = atlas.width / 2 | 
		
	
	
		
			
				
					
					|  |  |  | @@ -251,6 +252,12 @@ init :: proc( ctx : ^Context, | 
		
	
		
			
				|  |  |  |  | 	// Note(From original author): We can actually go over VE_FONTCACHE_GLYPHDRAW_BUFFER_BATCH batches due to smart packing! | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		using atlas | 
		
	
		
			
				|  |  |  |  | 		over_sample   = glyph_draw_params.over_sample | 
		
	
		
			
				|  |  |  |  | 		buffer_batch  = glyph_draw_params.buffer_batch | 
		
	
		
			
				|  |  |  |  | 		buffer_width  = region_d.width  * u32(over_sample.x) * buffer_batch | 
		
	
		
			
				|  |  |  |  | 		buffer_height = region_d.height * u32(over_sample.y) | 
		
	
		
			
				|  |  |  |  | 		draw_padding  = glyph_draw_params.draw_padding | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		draw_list.calls, error = make( Array(DrawCall), cast(u64) glyph_draw_params.buffer_batch * 2 ) | 
		
	
		
			
				|  |  |  |  | 		assert( error != .None, "VEFontCache.init : Failed to allocate calls for draw_list" ) | 
		
	
		
			
				|  |  |  |  |  | 
		
	
	
		
			
				
					
					|  |  |  | @@ -348,53 +355,6 @@ configure_snap :: proc( ctx : ^Context, snap_width, snap_height : u32 ) { | 
		
	
		
			
				|  |  |  |  | 	ctx.snap_height = snap_height | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | // ve_fontcache_drawlist | 
		
	
		
			
				|  |  |  |  | get_draw_list :: proc( ctx : ^Context ) -> ^DrawList { | 
		
	
		
			
				|  |  |  |  | 	assert( ctx != nil ) | 
		
	
		
			
				|  |  |  |  | 	return & ctx.draw_list | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | // ve_fontcache_clear_drawlist | 
		
	
		
			
				|  |  |  |  | clear_draw_list :: proc( draw_list : ^DrawList ) { | 
		
	
		
			
				|  |  |  |  | 	clear( draw_list.calls ) | 
		
	
		
			
				|  |  |  |  | 	clear( draw_list.indices ) | 
		
	
		
			
				|  |  |  |  | 	clear( draw_list.vertices ) | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | // ve_fontcache_merge_drawlist | 
		
	
		
			
				|  |  |  |  | merge_draw_list :: proc( dst, src : ^DrawList ) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	error : AllocatorError | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	v_offset := cast(u32) dst.vertices.num | 
		
	
		
			
				|  |  |  |  | 	// for index : u32 = 0; index < cast(u32) src.vertices.num; index += 1 { | 
		
	
		
			
				|  |  |  |  | 	// 	error = append( & dst.vertices, src.vertices.data[index] ) | 
		
	
		
			
				|  |  |  |  | 	// 	assert( error == .None ) | 
		
	
		
			
				|  |  |  |  | 	// } | 
		
	
		
			
				|  |  |  |  | 	error = append( & dst.vertices, src.vertices ) | 
		
	
		
			
				|  |  |  |  | 	assert( error == .None ) | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	i_offset := cast(u32) dst.indices.num | 
		
	
		
			
				|  |  |  |  | 	for index : u32 = 0; index < cast(u32) src.indices.num; index += 1 { | 
		
	
		
			
				|  |  |  |  | 		error = append( & dst.indices, src.indices.data[index] + v_offset ) | 
		
	
		
			
				|  |  |  |  | 		assert( error == .None ) | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	for index : u32 = 0; index < cast(u32) src.calls.num; index += 1 { | 
		
	
		
			
				|  |  |  |  | 		src_call := src.calls.data[ index ] | 
		
	
		
			
				|  |  |  |  | 		src_call.start_index += i_offset | 
		
	
		
			
				|  |  |  |  | 		src_call.end_index   += i_offset | 
		
	
		
			
				|  |  |  |  | 		append( & dst.calls, src_call ) | 
		
	
		
			
				|  |  |  |  | 		assert( error == .None ) | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | // ve_fontcache_flush_drawlist | 
		
	
		
			
				|  |  |  |  | flush_draw_list :: proc( ctx : ^Context ) { | 
		
	
		
			
				|  |  |  |  | 	assert( ctx != nil ) | 
		
	
		
			
				|  |  |  |  | 	clear_draw_list( & ctx.draw_list ) | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | // 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 | 
		
	
		
			
				|  |  |  |  | // ve_fontcache_eval_bezier (quadratic) | 
		
	
	
		
			
				
					
					|  |  |  | @@ -422,92 +382,6 @@ eval_point_on_bezier4 :: proc( p0, p1, p2, p3 : Vec2, alpha : f32 ) -> Vec2 | 
		
	
		
			
				|  |  |  |  | 	return point | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | // Constructs a triangle fan to fill a shape using the provided path | 
		
	
		
			
				|  |  |  |  | // outside_point represents the center point of the fan. | 
		
	
		
			
				|  |  |  |  | // | 
		
	
		
			
				|  |  |  |  | // Note(Original Author): | 
		
	
		
			
				|  |  |  |  | // WARNING: doesn't actually append drawcall; caller is responsible for actually appending the drawcall. | 
		
	
		
			
				|  |  |  |  | // ve_fontcache_draw_filled_path | 
		
	
		
			
				|  |  |  |  | draw_filled_path :: proc( draw_list : ^DrawList, outside_point : Vec2, path : []Vec2, | 
		
	
		
			
				|  |  |  |  | 	scale     := Vec2 { 1, 1 }, | 
		
	
		
			
				|  |  |  |  | 	translate := Vec2 { 0, 0 }, | 
		
	
		
			
				|  |  |  |  | 	debug_print_verbose : b32 = false | 
		
	
		
			
				|  |  |  |  | ) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	if debug_print_verbose | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		log("outline_path: \n") | 
		
	
		
			
				|  |  |  |  | 		for point in path { | 
		
	
		
			
				|  |  |  |  | 			logf("    %.2f %.2f\n", point.x * scale ) | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	v_offset := cast(u32) draw_list.vertices.num | 
		
	
		
			
				|  |  |  |  | 	for point in path { | 
		
	
		
			
				|  |  |  |  | 		vertex := Vertex { | 
		
	
		
			
				|  |  |  |  | 			pos = point * scale + translate, | 
		
	
		
			
				|  |  |  |  | 			u = 0, | 
		
	
		
			
				|  |  |  |  | 			v = 0, | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 		append( & draw_list.vertices, vertex ) | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	outside_vertex := cast(u32) draw_list.vertices.num | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		vertex := Vertex { | 
		
	
		
			
				|  |  |  |  | 			pos = outside_point * scale + translate, | 
		
	
		
			
				|  |  |  |  | 			u = 0, | 
		
	
		
			
				|  |  |  |  | 			v = 0, | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 		append( & draw_list.vertices, vertex ) | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	for index : u32 = 1; index < u32(len(path)); index += 1 { | 
		
	
		
			
				|  |  |  |  | 		indices := & draw_list.indices | 
		
	
		
			
				|  |  |  |  | 		append( indices, outside_vertex ) | 
		
	
		
			
				|  |  |  |  | 		append( indices, v_offset + index - 1 ) | 
		
	
		
			
				|  |  |  |  | 		append( indices, v_offset + index ) | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | blit_quad :: proc( draw_list : ^DrawList, p0, p1 : Vec2, uv0, uv1 : Vec2 ) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	v_offset := cast(u32) draw_list.vertices.num | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	vertex := Vertex { | 
		
	
		
			
				|  |  |  |  | 		{p0.x, p0.y}, | 
		
	
		
			
				|  |  |  |  | 		uv0.x, | 
		
	
		
			
				|  |  |  |  | 		uv0.y | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	append( & draw_list.vertices, vertex ) | 
		
	
		
			
				|  |  |  |  | 	vertex = Vertex { | 
		
	
		
			
				|  |  |  |  | 		{p0.x, p1.y}, | 
		
	
		
			
				|  |  |  |  | 		uv0.x, | 
		
	
		
			
				|  |  |  |  | 		uv1.y | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	append( & draw_list.vertices, vertex ) | 
		
	
		
			
				|  |  |  |  | 	vertex = Vertex { | 
		
	
		
			
				|  |  |  |  | 		{p1.x, p0.y}, | 
		
	
		
			
				|  |  |  |  | 		uv1.x, | 
		
	
		
			
				|  |  |  |  | 		uv0.y | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	append( & draw_list.vertices, vertex ) | 
		
	
		
			
				|  |  |  |  | 	vertex = Vertex { | 
		
	
		
			
				|  |  |  |  | 		{p1.x, p1.y}, | 
		
	
		
			
				|  |  |  |  | 		uv1.x, | 
		
	
		
			
				|  |  |  |  | 		uv1.y | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	append( & draw_list.vertices, vertex ) | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	quad_indices : []u32 = { | 
		
	
		
			
				|  |  |  |  | 		0, 1, 2, | 
		
	
		
			
				|  |  |  |  | 		2, 1, 3 | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	for index : i32 = 0; index < 6; index += 1 { | 
		
	
		
			
				|  |  |  |  | 		append( & draw_list.indices, v_offset + quad_indices[ index ] ) | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | cache_glyph :: proc( ctx : ^Context, font : FontID, glyph_index : Glyph, scale, translate : Vec2  ) -> b32 | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	assert( ctx != nil ) | 
		
	
	
		
			
				
					
					|  |  |  | @@ -531,7 +405,24 @@ cache_glyph :: proc( ctx : ^Context, font : FontID, glyph_index : Glyph, scale, | 
		
	
		
			
				|  |  |  |  | 	if ctx.debug_print_verbose | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		log( "shape: \n") | 
		
	
		
			
				|  |  |  |  | 		// for  | 
		
	
		
			
				|  |  |  |  | 		for vertex in shape | 
		
	
		
			
				|  |  |  |  | 		{ | 
		
	
		
			
				|  |  |  |  | 			if vertex.type == .Move { | 
		
	
		
			
				|  |  |  |  | 				logf("move_to %d %d\n", vertex.x, vertex.y ) | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  | 			else if vertex.type == .Line { | 
		
	
		
			
				|  |  |  |  | 				logf("line_to %d %d\n", vertex.x, vertex.y ) | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  | 			else if vertex.type == .Curve { | 
		
	
		
			
				|  |  |  |  | 				logf("curve_to %d %d through %d %d\n", vertex.x, vertex.y, vertex.contour_x0, vertex.contour_y0 ) | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  | 			else if vertex.type == .Cubic { | 
		
	
		
			
				|  |  |  |  | 				logf("cubic_to %d %d through %d %d and %d %d\n", | 
		
	
		
			
				|  |  |  |  | 					vertex.x, vertex.y, | 
		
	
		
			
				|  |  |  |  | 					vertex.contour_x0, vertex.contour_y0, | 
		
	
		
			
				|  |  |  |  | 					vertex.contour_x1, vertex.contour_y1 ) | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	/* | 
		
	
	
		
			
				
					
					|  |  |  | @@ -556,16 +447,130 @@ cache_glyph :: proc( ctx : ^Context, font : FontID, glyph_index : Glyph, scale, | 
		
	
		
			
				|  |  |  |  | 	// Instead of involving fragment shader code we simply make use of modern GPU ability to crunch triangles and brute force curve definitions. | 
		
	
		
			
				|  |  |  |  | 	path := ctx.temp_path | 
		
	
		
			
				|  |  |  |  | 	clear(path) | 
		
	
		
			
				|  |  |  |  | 	for vertex in shape { | 
		
	
		
			
				|  |  |  |  | 		 | 
		
	
		
			
				|  |  |  |  | 	for edge in shape	do switch edge.type | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		case .Move: | 
		
	
		
			
				|  |  |  |  | 			if path.num > 0 { | 
		
	
		
			
				|  |  |  |  | 				draw_filled_path( & ctx.draw_list, outside, array_to_slice(path), scale, translate ) | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  | 			clear(path) | 
		
	
		
			
				|  |  |  |  | 			fallthrough | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		case .Line: | 
		
	
		
			
				|  |  |  |  | 			append( & path, Vec2{ f32(edge.x), f32(edge.y) }) | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		case .Curve: | 
		
	
		
			
				|  |  |  |  | 			assert( path.num > 0 ) | 
		
	
		
			
				|  |  |  |  | 			p0 := path.data[ path.num - 1 ] | 
		
	
		
			
				|  |  |  |  | 			p1 := Vec2{ f32(edge.contour_x0), f32(edge.contour_y0) } | 
		
	
		
			
				|  |  |  |  | 			p2 := Vec2{ f32(edge.x), f32(edge.y) } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 			step  := 1.0 / f32(ctx.curve_quality) | 
		
	
		
			
				|  |  |  |  | 			alpha := step | 
		
	
		
			
				|  |  |  |  | 			for index := i32(0); index < i32(ctx.curve_quality); index += 1 { | 
		
	
		
			
				|  |  |  |  | 				append( & path, eval_point_on_bezier3( p0, p1, p2, alpha )) | 
		
	
		
			
				|  |  |  |  | 				alpha += step | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		case .Cubic: | 
		
	
		
			
				|  |  |  |  | 			assert( path.num > 0 ) | 
		
	
		
			
				|  |  |  |  | 			p0 := path.data[ path.num - 1] | 
		
	
		
			
				|  |  |  |  | 			p1 := Vec2{ f32(edge.contour_x0), f32(edge.contour_y0) } | 
		
	
		
			
				|  |  |  |  | 			p2 := Vec2{ f32(edge.contour_x1), f32(edge.contour_y1) } | 
		
	
		
			
				|  |  |  |  | 			p3 := Vec2{ f32(edge.x), f32(edge.y) } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 			step  := 1.0 / f32(ctx.curve_quality) | 
		
	
		
			
				|  |  |  |  | 			alpha := step | 
		
	
		
			
				|  |  |  |  | 			for index := i32(0); index < i32(ctx.curve_quality); index += 1 { | 
		
	
		
			
				|  |  |  |  | 				append( & path, eval_point_on_bezier4( p0, p1, p2, p3, alpha )) | 
		
	
		
			
				|  |  |  |  | 				alpha += step | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		case .None: | 
		
	
		
			
				|  |  |  |  | 			assert(false, "Unknown edge type or invalid") | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	if path.num > 0 { | 
		
	
		
			
				|  |  |  |  | 		draw_filled_path( & ctx.draw_list, outside, array_to_slice(path), scale, translate ) | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	// Note(Original Author): Apend the draw call | 
		
	
		
			
				|  |  |  |  | 	draw.end_index = cast(u32) ctx.draw_list.indices.num | 
		
	
		
			
				|  |  |  |  | 	if draw.end_index > draw.start_index { | 
		
	
		
			
				|  |  |  |  | 		append(& ctx.draw_list.calls, draw) | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	parser_free_shape( entry.parser_info, shape ) | 
		
	
		
			
				|  |  |  |  | 	return false | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | decide_codepoint_region :: proc() -> AtlasRegionKind | 
		
	
		
			
				|  |  |  |  | decide_codepoint_region :: proc( ctx : ^Context, entry : ^Entry, glyph_index : Glyph | 
		
	
		
			
				|  |  |  |  | ) -> (region : AtlasRegionKind, state : ^LRU_Cache, next_idx : ^u32, over_sample : ^Vec2) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	return {} | 
		
	
		
			
				|  |  |  |  | 	if parser_is_glyph_empty( entry.parser_info, glyph_index ) { | 
		
	
		
			
				|  |  |  |  | 		region = .None | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	bounds_0, bounds_1 := parser_get_glyph_box( entry.parser_info, glyph_index ) | 
		
	
		
			
				|  |  |  |  | 	bounds_width  := bounds_1.x - bounds_0.x | 
		
	
		
			
				|  |  |  |  | 	bounds_height := bounds_1.y - bounds_0.y | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	atlas := & ctx.atlas | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	bounds_width_scaled  := cast(u32) (f32(bounds_width)  * entry.size_scale + 2.0 * f32(atlas.glyph_padding)) | 
		
	
		
			
				|  |  |  |  | 	bounds_height_scaled := cast(u32) (f32(bounds_height) * entry.size_scale + 2.0 * f32(atlas.glyph_padding)) | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	if bounds_width_scaled <= atlas.region_a.width && bounds_height_scaled <= atlas.region_a.height | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		// Region A for small glyphs. These are good for things such as punctuation. | 
		
	
		
			
				|  |  |  |  | 		region   = .A | 
		
	
		
			
				|  |  |  |  | 		state    = & atlas.region_a.state | 
		
	
		
			
				|  |  |  |  | 		next_idx = & atlas.region_a.next_idx | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	else if bounds_width_scaled <= atlas.region_b.width && bounds_height_scaled <= atlas.region_b.height | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		// Region B for tall glyphs. These are good for things such as european alphabets. | 
		
	
		
			
				|  |  |  |  | 		region   = .B | 
		
	
		
			
				|  |  |  |  | 		state    = & atlas.region_b.state | 
		
	
		
			
				|  |  |  |  | 		next_idx = & atlas.region_b.next_idx | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	else if bounds_width_scaled <= atlas.region_c.width && bounds_height_scaled <= atlas.region_c.height | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		// Region C for big glyphs. These are good for things such as asian typography. | 
		
	
		
			
				|  |  |  |  | 		region   = .C | 
		
	
		
			
				|  |  |  |  | 		state    = & atlas.region_c.state | 
		
	
		
			
				|  |  |  |  | 		next_idx = & atlas.region_c.next_idx | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	else if bounds_width_scaled <= atlas.region_d.width && bounds_height_scaled <= atlas.region_d.height | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		// Region D for huge glyphs. These are good for things such as titles and 4k. | 
		
	
		
			
				|  |  |  |  | 		region   = .D | 
		
	
		
			
				|  |  |  |  | 		state    = & atlas.region_d.state | 
		
	
		
			
				|  |  |  |  | 		next_idx = & atlas.region_d.next_idx | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	else if bounds_width_scaled <= atlas.buffer_width && bounds_height_scaled <= atlas.buffer_height | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		// Region 'E' for massive glyphs. These are rendered uncached and un-oversampled. | 
		
	
		
			
				|  |  |  |  | 		region   = .E | 
		
	
		
			
				|  |  |  |  | 		state    = nil | 
		
	
		
			
				|  |  |  |  | 		next_idx = nil | 
		
	
		
			
				|  |  |  |  | 		if bounds_width_scaled <= atlas.buffer_width / 2 && bounds_height_scaled <= atlas.buffer_height / 2 | 
		
	
		
			
				|  |  |  |  | 		{ | 
		
	
		
			
				|  |  |  |  | 			(over_sample^) = { 2.0, 2.0 } | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 		else | 
		
	
		
			
				|  |  |  |  | 		{ | 
		
	
		
			
				|  |  |  |  | 			(over_sample^) = { 1.0, 1.0 } | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 		return | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	else { | 
		
	
		
			
				|  |  |  |  | 		region = .None | 
		
	
		
			
				|  |  |  |  | 		return | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	assert(state    != nil) | 
		
	
		
			
				|  |  |  |  | 	assert(next_idx != nil) | 
		
	
		
			
				|  |  |  |  | 	return | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | flush_glyph_buffer_to_atlas :: proc() | 
		
	
	
		
			
				
					
					|  |  |  |   |