Misc changes (refactors, notes)
This commit is contained in:
		| @@ -1,3 +0,0 @@ | ||||
| package sectr | ||||
|  | ||||
| import fstash "codebase:font/fontstash" | ||||
| @@ -1,319 +0,0 @@ | ||||
| package sectr | ||||
|  | ||||
| import "core:os" | ||||
| import "core:strings" | ||||
| import "core:unicode" | ||||
| import sokol_gfx "thirdparty:sokol/gfx" | ||||
| import "thirdparty:freetype" | ||||
|  | ||||
| Font_Provider_Use_Freetype :: true | ||||
|  | ||||
| Font_Largest_Px_Size :: 32 | ||||
|  | ||||
| Font_Size_Interval :: 2 | ||||
|  | ||||
| // Font_Default :: "" | ||||
| Font_Default            :: FontID { 0, "" } | ||||
| Font_Default_Point_Size :: 18.0 | ||||
|  | ||||
| Font_TTF_Default_Chars_Padding :: 4 | ||||
|  | ||||
| Font_Load_Use_Default_Size :: -1 | ||||
| Font_Load_Gen_ID           :: "" | ||||
|  | ||||
| FontID  :: struct { | ||||
| 	key   : u64, | ||||
| 	label : string, | ||||
| } | ||||
| FontTag :: struct { | ||||
| 	key        : FontID, | ||||
| 	point_size : f32 | ||||
| } | ||||
|  | ||||
| when Font_Provider_Use_Freetype | ||||
| { | ||||
| 	FontParserFontData :: struct { | ||||
| 		using face : freetype.Face, | ||||
| 	} | ||||
| 	FontParserData :: struct { | ||||
| 		lib : freetype.Library, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| FontGlyph :: struct { | ||||
| 	size       : Vec2i, | ||||
| 	bearing    : Vec2i, | ||||
| 	advance    : u32, | ||||
| 	texture    : sokol_gfx.Image, | ||||
| } | ||||
|  | ||||
| FontDef :: struct { | ||||
| 	path_file   : string, | ||||
| 	parser_info : FontParserFontData, | ||||
| 	glyphs      : [256]FontGlyph, | ||||
| } | ||||
|  | ||||
| FontProviderData :: struct { | ||||
| 	font_cache    : HMapChained(FontDef), | ||||
| 	parser        : FontParserData, | ||||
| 	glyph_shader  : sokol_gfx.Shader, | ||||
| 	gfx_bindings  : sokol_gfx.Bindings, | ||||
| 	gfx_pipeline  : sokol_gfx.Pipeline, | ||||
| 	gfx_v_buffer  : sokol_gfx.Buffer, | ||||
| 	gfx_uv_buffer : sokol_gfx.Buffer, | ||||
| 	gfx_sampler   : sokol_gfx.Sampler, | ||||
| } | ||||
|  | ||||
| Font_Quad_Vert_Size            :: size_of(Vec2) * 6 | ||||
| Font_Provider_Gfx_vBuffer_Size :: Font_Quad_Vert_Size * Kilo * 64 | ||||
|  | ||||
| font_provider_startup :: proc() | ||||
| { | ||||
| 	profile(#procedure) | ||||
| 	state := get_state() | ||||
| 	font_provider_data := & get_state().font_provider_data; using font_provider_data | ||||
|  | ||||
| 	font_cache_alloc_error : AllocatorError | ||||
| 	font_cache, font_cache_alloc_error = make( HMapChained(FontDef), hmap_closest_prime(1 * Kilo), persistent_allocator() /*dbg_name = "font_cache"*/ ) | ||||
| 	verify( font_cache_alloc_error == AllocatorError.None, "Failed to allocate font_cache" ) | ||||
|  | ||||
| 	log("font_cache created") | ||||
|  | ||||
| 	when Font_Provider_Use_Freetype | ||||
| 	{ | ||||
| 		result := freetype.init_free_type( & font_provider_data.parser.lib ) | ||||
| 		if result != freetype.Error.Ok { | ||||
| 			fatal( "font_provider_setup: Failed to initialize freetype" ) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Setup Graphics Pipeline | ||||
| 	{ | ||||
| 		BlendFactor             :: sokol_gfx.Blend_Factor | ||||
| 		BlendOp                 :: sokol_gfx.Blend_Op | ||||
| 		BlendState              :: sokol_gfx.Blend_State | ||||
| 		BorderColor             :: sokol_gfx.Border_Color | ||||
| 		BufferDesciption        :: sokol_gfx.Buffer_Desc | ||||
| 		BufferUsage             :: sokol_gfx.Usage | ||||
| 		BufferType              :: sokol_gfx.Buffer_Type | ||||
| 		ColorTargetState        :: sokol_gfx.Color_Target_State | ||||
| 		Filter                  :: sokol_gfx.Filter | ||||
| 		Range                   :: sokol_gfx.Range | ||||
| 		SamplerDescription      :: sokol_gfx.Sampler_Desc | ||||
| 		Wrap                    :: sokol_gfx.Wrap | ||||
| 		VertexAttributeState    :: sokol_gfx.Vertex_Attr_State | ||||
| 		VertexBufferLayoutState :: sokol_gfx.Vertex_Buffer_Layout_State | ||||
| 		VertexIndexType         :: sokol_gfx.Index_Type | ||||
| 		VertexFormat            :: sokol_gfx.Vertex_Format | ||||
| 		VertexLayoutState       :: sokol_gfx.Vertex_Layout_State | ||||
| 		VertexStep              :: sokol_gfx.Vertex_Step | ||||
|  | ||||
| 		using font_provider_data | ||||
| 		backend := sokol_gfx.query_backend() | ||||
|  | ||||
| 		glyph_shader = sokol_gfx.make_shader(font_glyph_shader_desc(backend)) | ||||
|  | ||||
| 		// Glyphs append to a large vertex buffer that must be able to hold all verts per frame, the budget is fixed. | ||||
| 		// TODO(Ed): Add a way to relase and remake the buffer when an overflow is detected for a frame. | ||||
| 		gfx_v_buffer = sokol_gfx.make_buffer( BufferDesciption { | ||||
| 			size  = Font_Provider_Gfx_vBuffer_Size, | ||||
| 			usage = BufferUsage.DYNAMIC, | ||||
| 			type  = BufferType.VERTEXBUFFER, | ||||
| 		}) | ||||
| 		verify( sokol_gfx.query_buffer_state(gfx_v_buffer) != sokol_gfx.Resource_State.INVALID, | ||||
| 			"Failed to make font provider's gfx_v_buffer" ) | ||||
|  | ||||
| 		uv_coords : [6]Vec2 = { | ||||
| 			0 = { 0.0, 0.0 }, | ||||
| 			1 = { 0.0, 1.0 }, | ||||
| 			2 = { 1.0, 1.0 }, | ||||
|  | ||||
| 			3 = { 0.0, 0.0 }, | ||||
| 			4 = { 1.0, 1.0 }, | ||||
| 			5 = { 1.0, 0.0 }, | ||||
| 		} | ||||
|  | ||||
| 		// All quads will use the same vertex buffer for texture coordinates. | ||||
| 		gfx_uv_buffer = sokol_gfx.make_buffer( BufferDesciption { | ||||
| 			size  = 0, | ||||
| 			usage = BufferUsage.IMMUTABLE, | ||||
| 			type  = BufferType.VERTEXBUFFER, | ||||
| 			data  = Range { & uv_coords[0], size_of(uv_coords) }, | ||||
| 		}) | ||||
| 		verify( sokol_gfx.query_buffer_state(gfx_uv_buffer) != sokol_gfx.Resource_State.INVALID, | ||||
| 			"Failed to make font provider's gfx_uv_buffer" ) | ||||
|  | ||||
|  | ||||
| 		gfx_sampler = sokol_gfx.make_sampler( SamplerDescription { | ||||
| 			min_filter    = Filter.NEAREST, | ||||
| 			mag_filter    = Filter.NEAREST, | ||||
| 			mipmap_filter = Filter.NONE, | ||||
| 			wrap_u        = Wrap.CLAMP_TO_EDGE, | ||||
| 			wrap_v        = Wrap.CLAMP_TO_EDGE, | ||||
| 			border_color  = BorderColor.OPAQUE_BLACK, | ||||
| 		}) | ||||
|  | ||||
| 		glyph_vs_layout : VertexLayoutState | ||||
| 		{ | ||||
| 			using glyph_vs_layout | ||||
| 			attrs[ATTR_font_glyph_vs_vertex] = VertexAttributeState { | ||||
| 				format       = VertexFormat.FLOAT2, | ||||
| 				offset       = 0, | ||||
| 				buffer_index = ATTR_font_glyph_vs_vertex, | ||||
| 			} | ||||
| 			buffers[ATTR_font_glyph_vs_vertex] = VertexBufferLayoutState { | ||||
| 				stride    = size_of(Vec2), | ||||
| 				step_func = VertexStep.PER_VERTEX, | ||||
| 			} | ||||
|  | ||||
| 			attrs[ATTR_font_glyph_vs_texture_coord] = VertexAttributeState { | ||||
| 				format       = VertexFormat.FLOAT2, | ||||
| 				offset       = 0, | ||||
| 				buffer_index = ATTR_font_glyph_vs_texture_coord, | ||||
| 			} | ||||
| 			buffers[ATTR_font_glyph_vs_texture_coord] = VertexBufferLayoutState { | ||||
| 				stride    = size_of(Vec2), | ||||
| 				step_func = VertexStep.PER_VERTEX, | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		gfx_pipeline = sokol_gfx.make_pipeline( | ||||
| 		{ | ||||
| 			shader     = glyph_shader, | ||||
| 			layout     = glyph_vs_layout, | ||||
| 			index_type = VertexIndexType.NONE, | ||||
| 			colors = { | ||||
| 				0 = ColorTargetState \ | ||||
| 				{ | ||||
| 					blend = BlendState { | ||||
| 						enabled = true, | ||||
| 						src_factor_rgb   = BlendFactor.SRC_ALPHA, | ||||
| 						dst_factor_rgb   = BlendFactor.ONE_MINUS_SRC_ALPHA, | ||||
| 						op_rgb           = BlendOp.ADD, | ||||
| 						src_factor_alpha = BlendFactor.ONE, | ||||
| 						dst_factor_alpha = BlendFactor.ZERO, | ||||
| 						op_alpha         = BlendOp.ADD, | ||||
| 					} | ||||
| 				}, | ||||
| 			}, | ||||
| 			color_count  = 1, | ||||
| 			sample_count = 1, | ||||
| 		}) | ||||
| 	} | ||||
|  | ||||
| 	log("font_provider initialized") | ||||
| } | ||||
|  | ||||
| font_provider_reload :: proc() | ||||
| { | ||||
| 	 | ||||
| } | ||||
|  | ||||
| font_provider_shutdown :: proc() | ||||
| { | ||||
| 	font_provider_data := & get_state().font_provider_data; using font_provider_data | ||||
| 	for & entry in font_cache.lookup | ||||
| 	{ | ||||
| 		if entry == nil do continue | ||||
| 		def := entry.value | ||||
|  | ||||
| 		// TODO(Ed): Free entry resources. | ||||
| 	} | ||||
| } | ||||
|  | ||||
| when Font_Provider_Use_Freetype | ||||
| { | ||||
| 	font_load :: proc(path_file : string, | ||||
| 		default_size : f32    = Font_Load_Use_Default_Size, | ||||
| 		desired_id   : string = Font_Load_Gen_ID | ||||
| 	) -> FontID | ||||
| 	{ | ||||
| 		profile(#procedure) | ||||
|  | ||||
| 		logf("Loading font: %v", path_file) | ||||
| 		font_provider_data := & get_state().font_provider_data; using font_provider_data | ||||
|  | ||||
| 		font_data, read_succeded : = os.read_entire_file( path_file ) | ||||
| 		verify( b32(read_succeded), str_fmt("Failed to read font file for: %v", path_file) ) | ||||
| 		font_data_size := cast(i32) len(font_data) | ||||
|  | ||||
| 		desired_id := desired_id | ||||
| 		// Use file name as key | ||||
| 		if len(desired_id) == 0 { | ||||
| 			// NOTE(Ed): This should never be used except for laziness so I'll be throwing a warning everytime. | ||||
| 			log("desired_key not provided, using file name. Give it a proper name!", LogLevel.Warning) | ||||
| 			// desired_id = cast(FontID) file_name_from_path(path_file) | ||||
| 			desired_id = file_name_from_path(path_file) | ||||
| 		} | ||||
|  | ||||
| 		key            := cast(u64) crc32( transmute([]byte) desired_id ) | ||||
| 		def, set_error := hmap_chained_set(font_cache, key, FontDef{}) | ||||
| 		verify( set_error == AllocatorError.None, "Failed to add new font entry to cache" ) | ||||
|  | ||||
| 		def.path_file = path_file | ||||
|  | ||||
| 		face_index :: 0 | ||||
| 		freetype.new_memory_face( font_provider_data.parser.lib, raw_data(font_data), font_data_size, face_index, & def.parser_info.face ) | ||||
|  | ||||
| 		// Hardcoding to 24 pt for testing (until we have a proper cached atlas) | ||||
| 		freetype.set_pixel_sizes( def.parser_info.face, 0, 72 ) | ||||
|  | ||||
| 		for ascii_code in 0 ..< 128 | ||||
| 		{ | ||||
| 			load_error := freetype.load_char(def.parser_info.face, u32(ascii_code), {freetype.Load_Flag.Render}) | ||||
| 			verify( load_error == .Ok, "Failed to load character using freetype" ) | ||||
|  | ||||
| 			// using def.parser_info | ||||
| 			using def | ||||
| 			// glyph  := parser_info.face.glyph | ||||
| 			// bitmap := & glyph.bitmap | ||||
| 			using parser_info.face.glyph | ||||
|  | ||||
| 			codepoint := rune(ascii_code) | ||||
| 			if ! unicode.is_print(codepoint) || bitmap.width <= 0 do continue | ||||
|  | ||||
| 			ImageDescription :: sokol_gfx.Image_Desc | ||||
| 			ImageUsage       :: sokol_gfx.Usage | ||||
| 			Range            :: sokol_gfx.Range | ||||
| 			PixelFormat      :: sokol_gfx.Pixel_Format | ||||
|  | ||||
| 			glyph_data : sokol_gfx.Image_Data | ||||
| 			glyph_data.subimage[0][0] = Range { bitmap.buffer, u64(bitmap.width * bitmap.rows)	} | ||||
|  | ||||
| 			desc := sokol_gfx.Image_Desc { | ||||
| 				type          = sokol_gfx.Image_Type._2D, | ||||
| 				render_target = false, | ||||
| 				width         = i32(bitmap.width), | ||||
| 				height        = i32(bitmap.rows), | ||||
| 				num_slices    = 1, | ||||
| 				num_mipmaps   = 1, | ||||
| 				usage         = ImageUsage.IMMUTABLE, | ||||
| 				pixel_format  = PixelFormat.R8, | ||||
| 				sample_count  = 0, | ||||
| 				data          = glyph_data, | ||||
| 				label         = strings.clone_to_cstring(str_fmt("font_ascii %v", ascii_code)) | ||||
| 			} | ||||
|  | ||||
| 			// width := i32(bitmap.width) | ||||
| 			// rows  := i32(bitmap.rows) | ||||
| 			// logf("font_ascii      : %v", ascii_code ) | ||||
| 			// logf("font_ascii glyph: %v", rune(ascii_code) ) | ||||
|  | ||||
| 			sokol_img := sokol_gfx.make_image( desc ) | ||||
| 			verify( sokol_gfx.query_image_state(sokol_img) != sokol_gfx.Resource_State.INVALID, | ||||
| 				"Failed to create image on sokol gfx" ); | ||||
|  | ||||
| 			def.glyphs[ascii_code] = FontGlyph { | ||||
| 				size     = { i32(bitmap.width), i32(bitmap.rows) }, | ||||
| 				bearing  = { bitmap_left,  bitmap_top }, | ||||
| 				texture  = sokol_img, | ||||
| 				advance  = u32(advance.x), | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		freetype.done_face( def.parser_info.face ) | ||||
|  | ||||
| 		fid := FontID { key, desired_id } | ||||
| 		return fid | ||||
| 	} | ||||
| } | ||||
		Reference in New Issue
	
	Block a user