Minor cleanup to current bad impl of font rendering
Just trying to really "get" sokol_gfx.h
This commit is contained in:
@ -50,7 +50,6 @@ FontGlyph :: struct {
|
||||
bearing : Vec2i,
|
||||
advance : u32,
|
||||
texture : sokol_gfx.Image,
|
||||
bindings : sokol_gfx.Bindings,
|
||||
}
|
||||
|
||||
FontDef :: struct {
|
||||
@ -60,15 +59,18 @@ FontDef :: struct {
|
||||
}
|
||||
|
||||
FontProviderData :: struct {
|
||||
font_cache : HMapChainedPtr(FontDef),
|
||||
parser : FontParserData,
|
||||
gfx_bindings : sokol_gfx.Bindings,
|
||||
gfx_pipeline : sokol_gfx.Pipeline,
|
||||
gfx_vbuffer : sokol_gfx.Buffer,
|
||||
gfx_sampler : sokol_gfx.Sampler,
|
||||
font_cache : HMapChainedPtr(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_Provider_Ggfx_Buffer_Size :: 6 * 4 * size_of(f32) * Kilobyte * 32
|
||||
Font_Quad_Vert_Size :: size_of(Vec2) * 6
|
||||
Font_Provider_Gfx_vBuffer_Size :: Font_Quad_Vert_Size * Kilo * 64
|
||||
|
||||
font_provider_startup :: proc()
|
||||
{
|
||||
@ -92,57 +94,110 @@ font_provider_startup :: proc()
|
||||
|
||||
// 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()
|
||||
learngl_font_glyph_shader := sokol_gfx.make_shader(learngl_font_glyph_shader_desc(backend))
|
||||
|
||||
gfx_vbuffer = sokol_gfx.make_buffer( sokol_gfx.Buffer_Desc {
|
||||
size = Font_Provider_Ggfx_Buffer_Size, // (6 verts, 4 f32 each) * 32 kilos
|
||||
usage = sokol_gfx.Usage.DYNAMIC,
|
||||
type = sokol_gfx.Buffer_Type.VERTEXBUFFER,
|
||||
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" )
|
||||
|
||||
gfx_sampler = sokol_gfx.make_sampler( sokol_gfx.Sampler_Desc {
|
||||
min_filter = sokol_gfx.Filter.LINEAR,
|
||||
mag_filter = sokol_gfx.Filter.LINEAR,
|
||||
mipmap_filter = sokol_gfx.Filter.NONE,
|
||||
wrap_u = sokol_gfx.Wrap.CLAMP_TO_EDGE,
|
||||
wrap_v = sokol_gfx.Wrap.CLAMP_TO_EDGE,
|
||||
// min_lod = 1.0,
|
||||
// max_lod = 1.0,
|
||||
border_color = sokol_gfx.Border_Color.OPAQUE_BLACK,
|
||||
})
|
||||
uv_coords : [6]Vec2 = {
|
||||
0 = { 0.0, 0.0 },
|
||||
1 = { 0.0, 1.0 },
|
||||
2 = { 1.0, 1.0 },
|
||||
|
||||
glyph_vs_layout : sokol_gfx.Vertex_Layout_State
|
||||
glyph_vs_layout.attrs[ATTR_glyph_vs_vertex] = sokol_gfx.Vertex_Attr_State {
|
||||
format = sokol_gfx.Vertex_Format.FLOAT4,
|
||||
offset = 0,
|
||||
3 = { 0.0, 0.0 },
|
||||
4 = { 1.0, 1.0 },
|
||||
5 = { 1.0, 0.0 },
|
||||
}
|
||||
glyph_vs_layout.buffers[0] = sokol_gfx.Vertex_Buffer_Layout_State {
|
||||
stride = size_of(f32) * 4, // Total stride ( pos2 + tex2 )
|
||||
step_func = sokol_gfx.Vertex_Step.PER_VERTEX,
|
||||
|
||||
// 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 = learngl_font_glyph_shader,
|
||||
layout = glyph_vs_layout,
|
||||
colors ={
|
||||
0 = sokol_gfx.Color_Target_State \
|
||||
shader = glyph_shader,
|
||||
layout = glyph_vs_layout,
|
||||
index_type = VertexIndexType.NONE,
|
||||
colors = {
|
||||
0 = ColorTargetState \
|
||||
{
|
||||
// pixel_format = sokol_gfx.Pixel_Format.R8,
|
||||
// write_mask = sokol_gfx.Color_Mask.R,
|
||||
blend = sokol_gfx.Blend_State {
|
||||
blend = BlendState {
|
||||
enabled = true,
|
||||
src_factor_rgb = sokol_gfx.Blend_Factor.SRC_ALPHA,
|
||||
dst_factor_rgb = sokol_gfx.Blend_Factor.ONE_MINUS_SRC_ALPHA,
|
||||
// op_rgb = sokol_gfx.Blend_Op.ADD,
|
||||
|
||||
src_factor_alpha= sokol_gfx.Blend_Factor.ONE,
|
||||
dst_factor_alpha = sokol_gfx.Blend_Factor.ZERO,
|
||||
// src_factor_alpha = sokol_gfx.Blend_Factor.ONE,
|
||||
// dst_factor_alpha = sokol_gfx.Blend_Factor.ZERO,
|
||||
// op_alpha = sokol_gfx.Blend_Op.DEFAULT,
|
||||
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,
|
||||
}
|
||||
},
|
||||
},
|
||||
@ -157,117 +212,108 @@ font_provider_startup :: 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
|
||||
// for & px_render in def.size_table {
|
||||
// using px_render
|
||||
// rl.UnloadFontData( glyphs, count )
|
||||
// rl.UnloadTexture ( texture )
|
||||
// rl.MemFree( recs )
|
||||
// }
|
||||
|
||||
// TODO(Ed): Free entry resources.
|
||||
}
|
||||
}
|
||||
|
||||
font_load :: proc(path_file : string,
|
||||
default_size : f32 = Font_Load_Use_Default_Size,
|
||||
desired_id : string = Font_Load_Gen_ID
|
||||
) -> FontID
|
||||
when Font_Provider_Use_Freetype
|
||||
{
|
||||
profile(#procedure)
|
||||
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
|
||||
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)
|
||||
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)
|
||||
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
|
||||
}
|
||||
|
||||
// default_size := default_size
|
||||
// if default_size == Font_Load_Use_Default_Size {
|
||||
// default_size = Font_Default_Point_Size
|
||||
// }
|
||||
|
||||
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
|
||||
// def.default_size = i32(points_to_pixels(default_size))
|
||||
|
||||
face_index :: 0
|
||||
freetype.new_memory_face( font_provider_data.parser.lib, raw_data(font_data), cast(i32) len(font_data), 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
|
||||
|
||||
codepoint := rune(ascii_code)
|
||||
|
||||
if ! unicode.is_print(codepoint) || face.glyph.bitmap.width <= 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
glyph_data : sokol_gfx.Image_Data
|
||||
glyph_data.subimage[0][0] = sokol_gfx.Range {
|
||||
face.glyph.bitmap.buffer,
|
||||
u64(face.glyph.bitmap.width * face.glyph.bitmap.rows)
|
||||
}
|
||||
desc := sokol_gfx.Image_Desc {
|
||||
type = sokol_gfx.Image_Type._2D,
|
||||
render_target = false,
|
||||
width = i32(face.glyph.bitmap.width),
|
||||
height = i32(face.glyph.bitmap.rows),
|
||||
num_slices = 1,
|
||||
num_mipmaps = 1,
|
||||
usage = sokol_gfx.Usage.IMMUTABLE,
|
||||
pixel_format = sokol_gfx.Pixel_Format.R8,
|
||||
sample_count = 0,
|
||||
data = glyph_data,
|
||||
label = strings.clone_to_cstring(str_fmt("font_ascii %v", ascii_code))
|
||||
}
|
||||
width := i32(face.glyph.bitmap.width)
|
||||
rows := i32(face.glyph.bitmap.rows)
|
||||
logf("font_ascii : %v", ascii_code )
|
||||
logf("font_ascii glyph: %v", rune(ascii_code) )
|
||||
rhi_img := sokol_gfx.make_image( desc )
|
||||
verify( sokol_gfx.query_image_state(rhi_img) != sokol_gfx.Resource_State.INVALID,
|
||||
"Failed to create image on sokol gfx" );
|
||||
|
||||
def_bindings := sokol_gfx.Bindings {
|
||||
vertex_buffers = { ATTR_glyph_vs_vertex = gfx_vbuffer, },
|
||||
fs = {
|
||||
images = { SLOT_glyph_bitmap = rhi_img, },
|
||||
samplers = { SLOT_glyph_bitmap_sampler = gfx_sampler }
|
||||
},
|
||||
}
|
||||
|
||||
def.glyphs[ascii_code] = FontGlyph {
|
||||
size = { i32(face.glyph.bitmap.width), i32(face.glyph.bitmap.rows) },
|
||||
bearing = { face.glyph.bitmap_left, face.glyph.bitmap_top },
|
||||
texture = rhi_img,
|
||||
bindings = def_bindings,
|
||||
advance = u32(face.glyph.advance.x),
|
||||
}
|
||||
}
|
||||
|
||||
fid := FontID { key, desired_id }
|
||||
return fid
|
||||
}
|
||||
|
Reference in New Issue
Block a user