From 1de141288fc00fa649ca2a9b73762428a4b3d3dc Mon Sep 17 00:00:00 2001 From: Ed_ Date: Tue, 27 Feb 2024 09:32:26 -0500 Subject: [PATCH] Made font_cache use the zpl hash map, make a proper setup for how many atlases to sore in the size_table --- code/font_provider.odin | 58 ++++++++++++++------------ code/text.odin | 4 +- code/tick_render.odin | 2 +- scripts/build.ps1 | 92 ++++++++++++++++++++++------------------- 4 files changed, 84 insertions(+), 72 deletions(-) diff --git a/code/font_provider.odin b/code/font_provider.odin index 2e9be45..702c34b 100644 --- a/code/font_provider.odin +++ b/code/font_provider.odin @@ -9,10 +9,10 @@ import "core:os" import rl "vendor:raylib" Font_Arena_Size :: 32 * Megabyte -Font_Largest_Px_Size :: 32 +Font_Largest_Px_Size :: 96 // Font_Default :: "" -Font_Default :: 0 +Font_Default :: FontID { 0, "" } Font_Default_Point_Size :: 18.0 Font_TTF_Default_Chars_Padding :: 4 @@ -21,14 +21,17 @@ Font_Load_Use_Default_Size :: -1 Font_Load_Gen_ID :: "" Font_Atlas_Packing_Method :: enum u32 { - Raylib_Basic = 0, // Basic packing algo + Raylib_Basic = 0, // Basic packing algo Skyeline_Rect = 1, // stb_pack_rect } // TODO(Ed) : These are currently i32, I wanted them to be string ids for debug ease of use. // There is an issue with the hash map type preventing me from doing so. Its allocator reference breaks. // FontID :: distinct string -FontID :: distinct i32 +FontID :: struct { + key : u64, + label : string, +} FontTag :: struct { key : FontID, point_size : f32 @@ -47,7 +50,7 @@ FontDef :: struct { path_file : string, data : [] u8, default_size : i32, - size_table : [Font_Largest_Px_Size] FontGlyphsRender, + size_table : [Font_Largest_Px_Size / 2] FontGlyphsRender, // TODO(Ed) : This is a rough way to do even multiplies, we are wasting half the array, I'll make a proper accessor/generation to it eventually. } @@ -55,10 +58,7 @@ FontProviderData :: struct { font_arena : Arena, //TODO(Ed) : There is an issue with hot-reload and map allocations that I can't figure out right now.. - // font_cache : ^ map [FontID](FontDef), - // font_cache : HMapZPL(FontDef), - font_cache : [10] FontDef, - open_id : i32 + font_cache : HMapZPL(FontDef), } font_provider_startup :: proc() @@ -71,9 +71,10 @@ font_provider_startup :: proc() arena_init( & font_arena, data ) - // font_cache = new( map[FontID](FontDef), arena_allocator( & font_arena ) ) - // font_cache^ = make_map( map[FontID](FontDef), capacity = 10, allocator = arena_allocator( & font_arena ) ) - open_id = 0 + font_cache_alloc_error : AllocatorError + font_cache, font_cache_alloc_error = zpl_hmap_init_reserve( FontDef, persistent_allocator(), 8 ) + verify( font_cache_alloc_error == AllocatorError.None, "Failed to allocate font_cache" ) + log("font_cache created") log("font_provider initialized") } @@ -82,8 +83,10 @@ font_provider_shutdown :: proc() { font_provider_data := & get_state().font_provider_data; using font_provider_data - // for key, & def in font_cache { - for & def in font_cache { + for id in 0 ..< font_cache.entries.num + { + def := & font_cache.entries.data[id].value + for & px_render in def.size_table { using px_render rl.UnloadFontData( glyphs, count ) @@ -108,7 +111,7 @@ font_load :: proc( path_file : string, // 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!") + 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) } @@ -118,10 +121,10 @@ font_load :: proc( path_file : string, default_size = Font_Default_Point_Size } - // font_cache[desired_id] = {} - // def := & font_cache[desired_id]; - def := & font_cache[open_id] - open_id += 1 + key := cast(u64) crc32( transmute([]byte) desired_id ) + def, set_error := zpl_hmap_set( & font_cache, key,FontDef {} ) + verify( set_error == AllocatorError.None, "Failed to add new font entry to cache" ) + def.path_file = path_file def.data = font_data def.default_size = i32(points_to_pixels(default_size)) @@ -129,11 +132,13 @@ font_load :: proc( path_file : string, // TODO(Ed): this is extremely slow // Render all sizes at once // Note(Ed) : We only generate textures for even multiples of the font. - for id : i32 = 1; id < Font_Largest_Px_Size; id += 2 + for font_size : i32 = 2; font_size <= Font_Largest_Px_Size; font_size += 2 { - px_render := & def.size_table[id] + id := (font_size / 2) + (font_size % 2) + + px_render := & def.size_table[id - 1] using px_render - size = id + 1 + size = font_size count = 95 // This is the default codepoint count from raylib when loading a font. padding = Font_TTF_Default_Chars_Padding glyphs = rl.LoadFontData( raw_data(font_data), font_data_size, @@ -160,8 +165,7 @@ font_load :: proc( path_file : string, rl.UnloadImage( atlas ) } - // return desired_id - return cast(FontID) open_id - 1 + return { key, desired_id } } Font_Use_Default_Size :: f32(0.0) @@ -171,9 +175,11 @@ to_rl_Font :: proc( id : FontID, size := Font_Use_Default_Size ) -> rl.Font { even_size := math.round(size * 0.5) * 2.0 size := clamp( i32( even_size), 8, Font_Largest_Px_Size ) - def := & font_cache[id] + def := zpl_hmap_get( & font_cache, id.key ) size = size if size != i32(Font_Use_Default_Size) else def.default_size - px_render := & def.size_table[ size - 1 ] + + id := (size / 2) + (size % 2) + px_render := & def.size_table[ id - 1 ] // This is free for now perf wise... may have to move this out to on a setting change later. rl.SetTextureFilter( px_render.texture, rl.TextureFilter.TRILINEAR ) diff --git a/code/text.odin b/code/text.odin index b05f917..1dbf7ed 100644 --- a/code/text.odin +++ b/code/text.odin @@ -14,7 +14,7 @@ debug_draw_text :: proc( content : string, pos : Vec2, size : f32, color : rl.Co runes := to_runes( content, context.temp_allocator ) font := font - if font == 0 { + if font.key == Font_Default.key { // if ( len(font) == 0 ) { font = default_font } @@ -41,7 +41,7 @@ debug_draw_text_world :: proc( content : string, pos : Vec2, size : f32, color : runes := to_runes( content, context.temp_allocator ) font := font - if font == 0 { + if font.key == Font_Default.key { // if len(font) == 0 { font = default_font } diff --git a/code/tick_render.odin b/code/tick_render.odin index 78a4c80..7e6ffea 100644 --- a/code/tick_render.odin +++ b/code/tick_render.odin @@ -21,7 +21,7 @@ render :: proc() render_mode_2d() //region Render Screenspace { - fps_msg := str_fmt_tmp( "FPS:", rl.GetFPS() ) + fps_msg := str_fmt_tmp( "FPS: %v", rl.GetFPS() ) fps_msg_width := measure_text_size( fps_msg, default_font, 16.0, 0.0 ).x fps_msg_pos := screen_get_corners().top_right - { fps_msg_width, 0 } debug_draw_text( fps_msg, fps_msg_pos, 16.0, color = rl.GREEN ) diff --git a/scripts/build.ps1 b/scripts/build.ps1 index a53a063..ff6fe86 100644 --- a/scripts/build.ps1 +++ b/scripts/build.ps1 @@ -17,49 +17,50 @@ if ( $IsWindows ) { # Odin Compiler Flags +# For a beakdown of any flag, type -help $command_build = 'build' $command_check = 'check' $command_query = 'query' $command_report = 'report' $command_run = 'run' -$flag_build_mode = '-build-mode:' -$flag_build_mode_dll = '-build-mode:dll' -$flag_collection = '-collection:' -$flag_debug = '-debug' -$flag_define = '-define:' -$flag_disable_assert = '-disable-assert' -$flag_extra_assembler_flags = '-extra_assembler-flags:' -$flag_extra_linker_flags = '-extra-linker-flags:' -$flag_ignore_unknown_attributes = '-ignore-unknown-attributes' -$flag_keep_temp_files = '-keep-temp-files' -$flag_no_bounds_check = '-no-bounds-check' -$flag_no_crt = '-no-crt' -$flag_no_entrypoint = '-no-entry-point' -$flag_no_thread_local = '-no-thread-local' -$flag_no_thread_checker = '-no-thread-checker' -$flag_output_path = '-out=' -$flag_optimization_level = '-opt:' -$flag_optimize_none = '-o:none' -$flag_optimize_minimal = '-o:minimal' -$flag_optimize_size = '-o:size' -$flag_optimize_speed = '-o:speed' -$falg_optimize_aggressive = '-o:aggressive' -$flag_pdb_name = '-pdb-name:' -$flag_sanitize = '-sanitize:' -$flag_subsystem = '-subsystem:' -$flag_show_timings = '-show-timings' -$flag_show_more_timings = '-show-more-timings' -$flag_show_system_calls = '-show-system-calls' -$flag_target = '-target:' -$flag_thread_count = '-thread-count:' -$flag_use_lld = '-lld' -$flag_use_separate_modules = '-use-separate-modules' -$flag_vet_all = '-vet' -$flag_vet_unused_entities = '-vet-unused' -$flag_vet_semicolon = '-vet-semicolon' -$flag_vet_shadow_vars = '-vet-shadowing' -$flag_vet_using_stmt = '-vet-using-stmt' +$flag_build_mode = '-build-mode:' +$flag_build_mode_dll = '-build-mode:dll' +$flag_collection = '-collection:' +$flag_debug = '-debug' +$flag_define = '-define:' +$flag_disable_assert = '-disable-assert' +$flag_extra_assembler_flags = '-extra_assembler-flags:' +$flag_extra_linker_flags = '-extra-linker-flags:' +$flag_ignore_unknown_attributes = '-ignore-unknown-attributes' +$flag_keep_temp_files = '-keep-temp-files' +$flag_no_bounds_check = '-no-bounds-check' +$flag_no_crt = '-no-crt' +$flag_no_entrypoint = '-no-entry-point' +$flag_no_thread_local = '-no-thread-local' +$flag_no_thread_checker = '-no-thread-checker' +$flag_output_path = '-out=' +$flag_optimization_level = '-opt:' +$flag_optimize_none = '-o:none' +$flag_optimize_minimal = '-o:minimal' +$flag_optimize_size = '-o:size' +$flag_optimize_speed = '-o:speed' +$falg_optimize_aggressive = '-o:aggressive' +$flag_pdb_name = '-pdb-name:' +$flag_sanitize = '-sanitize:' +$flag_subsystem = '-subsystem:' +$flag_show_timings = '-show-timings' +$flag_show_more_timings = '-show-more-timings' +$flag_show_system_calls = '-show-system-calls' +$flag_target = '-target:' +$flag_thread_count = '-thread-count:' +$flag_use_lld = '-lld' +$flag_use_separate_modules = '-use-separate-modules' +$flag_vet_all = '-vet' +$flag_vet_unused_entities = '-vet-unused' +$flag_vet_semicolon = '-vet-semicolon' +$flag_vet_shadow_vars = '-vet-shadowing' +$flag_vet_using_stmt = '-vet-using-stmt' $flag_msvc_link_disable_dynamic_base = '/DYNAMICBASE:NO' $flag_msvc_link_base_address = '/BASE:' @@ -87,8 +88,8 @@ push-location $path_root $pkg_collection_thirdparty = 'thirdparty=' + $path_thirdparty $host_process_active = Get-Process | Where-Object {$_.Name -like 'sectr_host*'} - if ( -not $host_process_active ) { + # We cannot update thidparty dependencies during hot-reload. & $update_deps write-host } @@ -98,9 +99,10 @@ push-location $path_root $should_build = check-ModuleForChanges $module_sectr if ( -not( $should_build)) { write-host 'Skipping sectr build, module up to date' - return + return $false } + write-host 'Building Sectr Module' $module_dll = join-path $path_build ( $project_name + '.dll' ) $pdb = join-path $path_build ( $project_name + '.pdb' ) @@ -125,11 +127,15 @@ push-location $path_root # $build_args += $flag_show_system_calls # $build_args += $flag_show_timings - write-host 'Building Sectr Module' + if ( Test-Path $module_dll) { + $module_dll_pre_build_hash = get-filehash -path $module_dll -Algorithm MD5 + } & $odin_compiler $build_args - write-host + $module_dll_post_build_hash = get-filehash -path $module_dll -Algorithm MD5 + return $module_dll_pre_build_hash -ne $module_dll_post_build_hash } - build-sectr + $sectr_built = build-sectr + write-host # newline pad function build-host { @@ -141,7 +147,7 @@ push-location $path_root return } - $should_build = (check-ModuleForChanges $module_host) + $should_build = (check-ModuleForChanges $module_host) && (-not $sectr_built) if ( -not( $should_build)) { write-host 'Skipping sectr_host build, module up to date' return