From 9b927bd4109a6041119bd607a928ad276fe2ecec Mon Sep 17 00:00:00 2001 From: Simon Anciaux <14198779+mrmixer@users.noreply.github.com> Date: Sat, 15 Mar 2025 15:12:07 +0100 Subject: [PATCH] Fixed slice index not being passed correctly. It was normalized instead of pass as an integer value. This commit is setup for testing the texture array slices, it shouldn't be shipped to users. --- code/4ed_font_provider_freetype.cpp | 220 +++++++++++------------- code/platform_win32/4ed_dx11_render.cpp | 12 +- 2 files changed, 110 insertions(+), 122 deletions(-) diff --git a/code/4ed_font_provider_freetype.cpp b/code/4ed_font_provider_freetype.cpp index be4e10eb..8450eaf9 100644 --- a/code/4ed_font_provider_freetype.cpp +++ b/code/4ed_font_provider_freetype.cpp @@ -33,13 +33,13 @@ ft__load_flags(b32 use_hinting){ internal FT_Codepoint_Index_Pair_Array ft__get_codepoint_index_pairs(Arena *arena, FT_Face face, u16 *maximum_index_out){ FT_Long glyph_count = face->num_glyphs; - + FT_Codepoint_Index_Pair_Array array = {}; array.count = glyph_count; array.vals = push_array(arena, FT_Codepoint_Index_Pair, glyph_count); - + u16 maximum_index = 0; - + i32 counter = 0; FT_UInt index = 0; FT_ULong codepoint = FT_Get_First_Char(face, &index); @@ -57,22 +57,22 @@ ft__get_codepoint_index_pairs(Arena *arena, FT_Face face, u16 *maximum_index_out break; } } - + *maximum_index_out = maximum_index; - + return(array); } internal Codepoint_Index_Map ft__get_codepoint_index_map(Base_Allocator *base_allocator, FT_Face face){ FT_Long glyph_count = face->num_glyphs; - + Codepoint_Index_Map map = {}; map.zero_index = max_u16; map.table = make_table_u32_u16(base_allocator, glyph_count*4); - + u16 maximum_index = 0; - + i32 counter = 0; FT_UInt index = 0; FT_ULong codepoint = FT_Get_First_Char(face, &index); @@ -94,9 +94,9 @@ ft__get_codepoint_index_map(Base_Allocator *base_allocator, FT_Face face){ break; } } - + map.max_index = maximum_index; - + return(map); } @@ -125,29 +125,29 @@ ft__bad_rect_pack_end_line(Bad_Rect_Pack *pack){ internal Vec3_i32 ft__bad_rect_pack_next(Bad_Rect_Pack *pack, Vec2_i32 dim){ - + Vec3_i32 result = { }; - + // NOTE(simon, 28/02/24): Does this character fit in the texture if it's the only character ? if ( dim.x <= pack->max_dim.x && dim.y <= pack->max_dim.y ){ - + b8 end_line = false; - + if ( pack->p.x + dim.x > pack->max_dim.x ) { // NOTE(simon, 28/02/24): Can't fit the character horizontally. end_line = true; } - + if ( pack->current_line_h < dim.y && pack->p.y + dim.y > pack->max_dim.y ) { // NOTE(simon, 28/02/24): Character doesn't fit in the current line height, AND we // can't grow the line height. end_line = true; } - + if ( end_line ) { ft__bad_rect_pack_end_line( pack ); } - + if ( pack->p.y + dim.y > pack->max_dim.y ) { Assert( end_line ); // NOTE(simon, 28/02/24): We ended a line. There isn't enough space on a new line to @@ -156,22 +156,19 @@ ft__bad_rect_pack_next(Bad_Rect_Pack *pack, Vec2_i32 dim){ pack->p.y = 0; pack->dim.z += 1; pack->p.z += 1; - + // NOTE(simon, 28/02/24): There are no checks on the z axis range, but texture arrays // have a limit. At the moment it's 2048 on both OpenGL and DirectX. } - + // NOTE(simon, 28/02/24): We are now sure that the character will fit. - - if ( pack->current_line_h < dim.y ) { - pack->current_line_h = dim.y; - } - + pack->current_line_h = Max(pack->current_line_h, dim.y); + result = pack->p; pack->p.x += dim.x; pack->dim.x = Max( pack->dim.x, pack->p.x ); } - + return(result); } @@ -189,31 +186,31 @@ ft__glyph_bounds_store_uv_raw(Vec3_i32 p, Vec2_i32 dim, Glyph_Bounds *bounds){ internal Face* ft__font_make_face(Arena *arena, Face_Description *description, f32 scale_factor){ String_Const_u8 file_name = push_string_copy(arena, description->font.file_name); - + FT_Library ft; FT_Init_FreeType(&ft); - + FT_Face ft_face; FT_Error error = FT_New_Face(ft, (char*)file_name.str, 0, &ft_face); - + Face *face = 0; if (error == 0){ face = push_array_zero(arena, Face, 1); - + u32 pt_size_unscaled = Max(description->parameters.pt_size, 8); u32 pt_size = (u32)(pt_size_unscaled*scale_factor); b32 hinting = description->parameters.hinting; - + FT_Size_RequestRec_ size = {}; size.type = FT_SIZE_REQUEST_TYPE_NOMINAL; size.height = (pt_size << 6); FT_Request_Size(ft_face, &size); - + face->description.font.file_name = file_name; face->description.parameters = description->parameters; - + Face_Metrics *met = &face->metrics; - + met->max_advance = f32_ceil32(ft_face->size->metrics.max_advance/64.f); met->ascent = f32_ceil32(ft_face->size->metrics.ascender/64.f); met->descent = f32_floor32(ft_face->size->metrics.descender/64.f); @@ -221,19 +218,19 @@ ft__font_make_face(Arena *arena, Face_Description *description, f32 scale_factor met->line_skip = met->text_height - (met->ascent - met->descent); met->line_skip = clamp_bot(1.f, met->line_skip); met->line_height = met->text_height + met->line_skip; - + { f32 real_over_notional = met->line_height/(f32)ft_face->height; f32 relative_center = -1.f*real_over_notional*ft_face->underline_position; f32 relative_thickness = real_over_notional*ft_face->underline_thickness; - + f32 center = f32_floor32(met->ascent + relative_center); f32 thickness = clamp_bot(1.f, relative_thickness); - + met->underline_yoff1 = center - thickness*0.5f; met->underline_yoff2 = center + thickness*0.5f; } - + face->advance_map.codepoint_to_index = ft__get_codepoint_index_map(arena->base_allocator, ft_face); u16 index_count = @@ -241,40 +238,40 @@ ft__font_make_face(Arena *arena, Face_Description *description, f32 scale_factor face->advance_map.index_count = index_count; face->advance_map.advance = push_array_zero(arena, f32, index_count); face->bounds = push_array(arena, Glyph_Bounds, index_count); - + Temp_Memory_Block temp_memory(arena); struct Bitmap{ Vec2_i32 dim; u8 *data; }; Bitmap *glyph_bitmaps = push_array(arena, Bitmap, index_count); - + u32 load_flags = ft__load_flags(hinting); for (u16 i = 0; i < index_count; i += 1){ Bitmap *bitmap = &glyph_bitmaps[i]; - + error = FT_Load_Glyph(ft_face, i, load_flags); if (error == 0){ FT_GlyphSlot ft_glyph = ft_face->glyph; Vec2_i32 dim = V2i32(ft_glyph->bitmap.width, ft_glyph->bitmap.rows); bitmap->dim = dim; bitmap->data = push_array(arena, u8, dim.x*dim.y); - + face->bounds[i].xy_off.x0 = (f32)(ft_face->glyph->bitmap_left); face->bounds[i].xy_off.y0 = (f32)(met->ascent - ft_face->glyph->bitmap_top); face->bounds[i].xy_off.x1 = (f32)(face->bounds[i].xy_off.x0 + dim.x); face->bounds[i].xy_off.y1 = (f32)(face->bounds[i].xy_off.y0 + dim.y); - + switch (ft_glyph->bitmap.pixel_mode){ case FT_PIXEL_MODE_MONO: { NotImplemented; }break; - + case FT_PIXEL_MODE_GRAY: { b32 aa_1bit_mono = (description->parameters.aa_mode == FaceAntialiasingMode_1BitMono); - + u8 *src_line = ft_glyph->bitmap.buffer; if (ft_glyph->bitmap.pitch < 0){ src_line = ft_glyph->bitmap.buffer + (-ft_glyph->bitmap.pitch)*(dim.y - 1); @@ -299,107 +296,98 @@ ft__font_make_face(Arena *arena, Face_Description *description, f32 scale_factor src_line += ft_glyph->bitmap.pitch; } }break; - + default: { NotImplemented; }break; } - + face->advance_map.advance[i] = f32_ceil32(ft_glyph->advance.x/64.0f); } } - + u8 white_data[16] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }; - + Bitmap white = {}; white.dim = V2i32(4, 4); white.data = white_data; - + Bad_Rect_Pack pack = {}; - ft__bad_rect_pack_init(&pack, V2i32(1024, 1024)); + // ft__bad_rect_pack_init(&pack, V2i32(1024, 1024)); + ft__bad_rect_pack_init(&pack, V2i32(128, 128)); ft__glyph_bounds_store_uv_raw(ft__bad_rect_pack_next(&pack, white.dim), white.dim, &face->white); for (u16 i = 0; i < index_count; i += 1){ Vec2_i32 dim = glyph_bitmaps[i].dim; ft__glyph_bounds_store_uv_raw(ft__bad_rect_pack_next(&pack, dim), dim, &face->bounds[i]); } ft__bad_rect_store_finish(&pack); - + Texture_Kind texture_kind = TextureKind_Mono; u32 texture = graphics_get_texture(pack.dim, texture_kind); - - /* NOTE simon (06/01/25): This assumes that every platforms don't use 0 as a valid texture id. - This is valid for OpenGL and the DX11 implementaion. Someone needs to check the MAC versions. */ - if (texture != 0 ){ - - face->texture_kind = texture_kind; - face->texture = texture; - - Vec3_f32 texture_dim = V3f32(pack.dim); - face->texture_dim = texture_dim; - - { - Vec3_i32 p = V3i32((i32)face->white.uv.x0, (i32)face->white.uv.y0, (i32)face->white.w); - Vec3_i32 dim = V3i32(white.dim.x, white.dim.y, 1); - graphics_fill_texture(texture_kind, texture, p, dim, white.data); - face->white.uv.x1 = (face->white.uv.x0 + face->white.uv.x1)/texture_dim.x; - face->white.uv.y1 = (face->white.uv.y0 + face->white.uv.y1)/texture_dim.y; - face->white.uv.x0 = face->white.uv.x0/texture_dim.x; - face->white.uv.y0 = face->white.uv.y0/texture_dim.y; - face->white.w /= texture_dim.z; - } - - for (u16 i = 0; i < index_count; i += 1){ - Vec3_i32 p = V3i32((i32)face->bounds[i].uv.x0, (i32)face->bounds[i].uv.y0, (i32)face->bounds[i].w); - Vec3_i32 dim = V3i32(glyph_bitmaps[i].dim.x, glyph_bitmaps[i].dim.y, 1); - graphics_fill_texture(texture_kind, texture, p, dim, glyph_bitmaps[i].data); - face->bounds[i].uv.x1 = (face->bounds[i].uv.x0 + face->bounds[i].uv.x1)/texture_dim.x; - face->bounds[i].uv.y1 = (face->bounds[i].uv.y0 + face->bounds[i].uv.y1)/texture_dim.y; - face->bounds[i].uv.x0 = face->bounds[i].uv.x0/texture_dim.x; - face->bounds[i].uv.y0 = face->bounds[i].uv.y0/texture_dim.y; - face->bounds[i].w /= texture_dim.z; - } - - { - Face_Advance_Map *advance_map = &face->advance_map; - - met->space_advance = font_get_glyph_advance(advance_map, met, ' ', 0); - met->decimal_digit_advance = - font_get_max_glyph_advance_range(advance_map, met, '0', '9', 0); - met->hex_digit_advance = - font_get_max_glyph_advance_range(advance_map, met, 'A', 'F', 0); - met->hex_digit_advance = - Max(met->hex_digit_advance, met->decimal_digit_advance); - met->byte_sub_advances[0] = - font_get_glyph_advance(advance_map, met, '\\', 0); - met->byte_sub_advances[1] = met->hex_digit_advance; - met->byte_sub_advances[2] = met->hex_digit_advance; - met->byte_advance = - met->byte_sub_advances[0] + - met->byte_sub_advances[1] + - met->byte_sub_advances[2]; - met->normal_lowercase_advance = - font_get_average_glyph_advance_range(advance_map, met, 'a', 'z', 0); - met->normal_uppercase_advance = - font_get_average_glyph_advance_range(advance_map, met, 'A', 'Z', 0); - met->normal_advance = (26*met->normal_lowercase_advance + - 26*met->normal_uppercase_advance + - 10*met->decimal_digit_advance)/62.f; - } - - } else { - pop_array(arena, Face, 1); - face = 0; + + Vec3_f32 texture_dim = V3f32(pack.dim); + face->texture_dim = texture_dim; + + { + Vec3_i32 p = V3i32((i32)face->white.uv.x0, (i32)face->white.uv.y0, (i32)face->white.w); + Vec3_i32 dim = V3i32(white.dim.x, white.dim.y, 1); + graphics_fill_texture(texture_kind, texture, p, dim, white.data); + face->white.uv.x1 = (face->white.uv.x0 + face->white.uv.x1)/texture_dim.x; + face->white.uv.y1 = (face->white.uv.y0 + face->white.uv.y1)/texture_dim.y; + face->white.uv.x0 = face->white.uv.x0/texture_dim.x; + face->white.uv.y0 = face->white.uv.y0/texture_dim.y; + face->white.w /= texture_dim.z; + } + + for (u16 i = 0; i < index_count; i += 1){ + Vec3_i32 p = V3i32((i32)face->bounds[i].uv.x0, (i32)face->bounds[i].uv.y0, (i32)face->bounds[i].w); + Vec3_i32 dim = V3i32(glyph_bitmaps[i].dim.x, glyph_bitmaps[i].dim.y, 1); + graphics_fill_texture(texture_kind, texture, p, dim, glyph_bitmaps[i].data); + face->bounds[i].uv.x1 = (face->bounds[i].uv.x0 + face->bounds[i].uv.x1)/texture_dim.x; + face->bounds[i].uv.y1 = (face->bounds[i].uv.y0 + face->bounds[i].uv.y1)/texture_dim.y; + face->bounds[i].uv.x0 = face->bounds[i].uv.x0/texture_dim.x; + face->bounds[i].uv.y0 = face->bounds[i].uv.y0/texture_dim.y; +#if 0 + face->bounds[i].w /= texture_dim.z; +#endif + } + + { + Face_Advance_Map *advance_map = &face->advance_map; + + met->space_advance = font_get_glyph_advance(advance_map, met, ' ', 0); + met->decimal_digit_advance = + font_get_max_glyph_advance_range(advance_map, met, '0', '9', 0); + met->hex_digit_advance = + font_get_max_glyph_advance_range(advance_map, met, 'A', 'F', 0); + met->hex_digit_advance = + Max(met->hex_digit_advance, met->decimal_digit_advance); + met->byte_sub_advances[0] = + font_get_glyph_advance(advance_map, met, '\\', 0); + met->byte_sub_advances[1] = met->hex_digit_advance; + met->byte_sub_advances[2] = met->hex_digit_advance; + met->byte_advance = + met->byte_sub_advances[0] + + met->byte_sub_advances[1] + + met->byte_sub_advances[2]; + met->normal_lowercase_advance = + font_get_average_glyph_advance_range(advance_map, met, 'a', 'z', 0); + met->normal_uppercase_advance = + font_get_average_glyph_advance_range(advance_map, met, 'A', 'Z', 0); + met->normal_advance = (26*met->normal_lowercase_advance + + 26*met->normal_uppercase_advance + + 10*met->decimal_digit_advance)/62.f; } } - + FT_Done_FreeType(ft); - + return(face); } diff --git a/code/platform_win32/4ed_dx11_render.cpp b/code/platform_win32/4ed_dx11_render.cpp index e1fcbfc9..8eb6763b 100644 --- a/code/platform_win32/4ed_dx11_render.cpp +++ b/code/platform_win32/4ed_dx11_render.cpp @@ -154,7 +154,7 @@ gl__fill_texture(Texture_Kind texture_kind, u32 texid, Vec3_i32 p, Vec3_i32 dim, // font rendering code and other platforms. Fortunately the only call that specified 0 for the // texture handle was for the creation of the fallback texture in gl_render, and we can modify // that call to pass the fallback texture handle. - Assert( texid != 0 ); + Assert( texid != 0 ); if (dim.x > 0 && dim.y > 0 && dim.z > 0){ @@ -220,20 +220,20 @@ struct output_t { }; output_t main(input_t input) { - + output_t output; output.position = float4( mul( view_m, ( input.vertex_p - view_t ) ), 0.0, 1.0 ); // NOTE(simon, 28/02/24): The input colors are BGRA, we need them as RGBA. output.color = input.vertex_c.zyxw; output.uvw = input.vertex_t; - output.xy = input.vertex_p; - output.half_thickness = input.vertex_ht; - + output.xy = input.vertex_p; + output.half_thickness = input.vertex_ht; + float2 center = input.vertex_t.xy; float2 half_dim = abs( input.vertex_p - center ); output.adjusted_half_dim = half_dim - input.vertex_t.zz + float2( 0.5, 0.5 ); - + return output; } )foo";