From 0350a0c282d6bd68edbafacfcc9645904c84e30c Mon Sep 17 00:00:00 2001 From: Ed_ Date: Mon, 6 Jan 2025 14:12:55 -0500 Subject: [PATCH] Remove rune tracking for string cache, + vecache changes Getting ready to de-hardcode vefontcache shaders --- code/font/vefontcache/draw.odin | 23 +++++- code/font/vefontcache/mappings.odin | 1 + code/font/vefontcache/vefontcache.odin | 92 ++++++++++++++++------ code/grime/profiler.odin | 1 - code/grime/string_cache.odin | 32 +++----- code/sectr/app/settings_menu.odin | 41 ++++++++-- code/sectr/engine/client_api.odin | 10 +-- code/sectr/engine/render.odin | 14 ++-- code/sectr/font/provider.odin | 12 ++- code/sectr/font/render_sokol.odin | 12 +-- code/sectr/grime/mappings.odin | 4 +- code/sectr/parser/whitespace.odin | 4 +- code/sectr/project/project.odin | 4 +- code/sectr/project/serialize.odin | 8 +- code/sectr/project/workspace.odin | 2 +- code/sectr/shaders/ve_blit_atlas.shdc.glsl | 28 ++++--- code/sectr/shaders/ve_draw_text.shdc.glsl | 23 +++--- code/sectr/ui/core/base.odin | 11 ++- code/sectr/ui/core/box.odin | 6 +- code/sectr/ui/core/layout.odin | 6 +- code/sectr/ui/core/layout_compute.odin | 4 +- code/sectr/ui/core/signal.odin | 2 +- code/sectr/ui/floating.odin | 2 +- code/sectr/ui/tests.odin | 59 ++++++++------ code/sectr/ui/widgets.odin | 39 ++++----- code/sectr/ui/window.odin | 18 ++--- 26 files changed, 284 insertions(+), 174 deletions(-) diff --git a/code/font/vefontcache/draw.odin b/code/font/vefontcache/draw.odin index ac76139..efd29c5 100644 --- a/code/font/vefontcache/draw.odin +++ b/code/font/vefontcache/draw.odin @@ -249,6 +249,23 @@ generate_glyph_pass_draw_list :: proc(draw_list : ^Draw_List, path : ^[dynamic]V } } +generate_shapes_draw_list :: proc ( ctx : ^Context, font : Font_ID, colour : Colour, entry : Entry, font_scale : f32, position, scale : Vec2, shapes : []Shaped_Text ) +{ + assert(len(shapes) > 0) + for shape in shapes { + ctx.cursor_pos = {} + ctx.cursor_pos = generate_shape_draw_list( & ctx.draw_list, shape, & ctx.atlas, & ctx.glyph_buffer, + colour, + entry, + font_scale, + position, + scale, + ctx.snap_width, + ctx.snap_height + ) + } +} + generate_shape_draw_list :: #force_no_inline proc( draw_list : ^Draw_List, shape : Shaped_Text, atlas : ^Atlas, glyph_buffer : ^Glyph_Draw_Buffer, @@ -626,12 +643,12 @@ batch_generate_glyphs_draw_list :: proc ( draw_list : ^Draw_List, dst_glyph_pos := glyph.region_pos dst_glyph_size := glyph.bounds_size_scaled + atlas.glyph_padding - // dst_glyph_size.y = ceil(dst_glyph_size.y) // Note(Ed): Seems to improve hinting + dst_glyph_size.y = ceil(dst_glyph_size.y) // Note(Ed): Seems to improve hinting to_glyph_buffer_space( & dst_glyph_pos, & dst_glyph_size, atlas_size ) src_position := Vec2 { glyph.buffer_x, 0 } - src_size := (glyph.bounds_size_scaled + atlas.glyph_padding) * glyph_buffer.over_sample - // src_size.y = ceil(src_size.y) // Note(Ed): Seems to improve hinting + src_size := (glyph.bounds_size_scaled + atlas.glyph_padding) * glyph_buffer.over_sample + src_size.y = ceil(src_size.y) // Note(Ed): Seems to improve hinting to_target_space( & src_position, & src_size, glyph_buffer_size ) blit_to_atlas : Draw_Call diff --git a/code/font/vefontcache/mappings.odin b/code/font/vefontcache/mappings.odin index 8f8a275..6d306f3 100644 --- a/code/font/vefontcache/mappings.odin +++ b/code/font/vefontcache/mappings.odin @@ -90,6 +90,7 @@ make :: proc { make_dynamic_array, make_dynamic_array_len, make_dynamic_array_len_cap, + make_slice, make_map, make_map_cap, } diff --git a/code/font/vefontcache/vefontcache.odin b/code/font/vefontcache/vefontcache.odin index 7b5c392..380c10e 100644 --- a/code/font/vefontcache/vefontcache.odin +++ b/code/font/vefontcache/vefontcache.odin @@ -21,11 +21,12 @@ Load_Font_Error :: enum(i32) { } Entry :: struct { - parser_info : Parser_Font_Info, - shaper_info : Shaper_Info, - id : Font_ID, - used : b32, - curve_quality : f32, + parser_info : Parser_Font_Info, + shaper_info : Shaper_Info, + id : Font_ID, + used : b32, + curve_quality : f32, + // snap_glyph_pos : ascent : f32, descent : f32, @@ -98,26 +99,26 @@ Init_Atlas_Params :: struct { } Init_Atlas_Params_Default :: Init_Atlas_Params { - width = 4096, - height = 2048, + width = 4096 * 2, + height = 2048 * 2, glyph_padding = 1, glyph_over_scalar = 1, region_a = { - width = 32, - height = 32, + width = 32 * 2, + height = 32 * 2, }, region_b = { - width = 32, - height = 64, + width = 32 * 2, + height = 64 * 2, }, region_c = { - width = 64, - height = 64, + width = 64 * 2, + height = 64 * 2, }, region_d = { - width = 128, - height = 128, + width = 128 * 2, + height = 128 * 2, } } @@ -224,10 +225,10 @@ startup :: proc( ctx : ^Context, parser_kind : Parser_Kind = .STB_TrueType, error : Allocator_Error lru_init( & region.state, region.capacity.x * region.capacity.y ) } - init_atlas_region( & atlas.region_a, atlas_params, atlas_params.region_a, { 4, 2}, 1024 ) - init_atlas_region( & atlas.region_b, atlas_params, atlas_params.region_b, { 4, 2}, 512 ) - init_atlas_region( & atlas.region_c, atlas_params, atlas_params.region_c, { 4, 1}, 512 ) - init_atlas_region( & atlas.region_d, atlas_params, atlas_params.region_d, { 2, 1}, 256 ) + init_atlas_region( & atlas.region_a, atlas_params, atlas_params.region_a, { 4, 2}, 1024 * 4 ) + init_atlas_region( & atlas.region_b, atlas_params, atlas_params.region_b, { 4, 2}, 512 * 4 ) + init_atlas_region( & atlas.region_c, atlas_params, atlas_params.region_c, { 4, 1}, 512 * 4 ) + init_atlas_region( & atlas.region_d, atlas_params, atlas_params.region_d, { 2, 1}, 256 * 4 ) atlas.width = i32(atlas_params.width) atlas.height = i32(atlas_params.height) @@ -494,10 +495,15 @@ configure_snap :: #force_inline proc( ctx : ^Context, snap_width, snap_height : ctx.snap_height = f32(snap_height) } -get_cursor_pos :: #force_inline proc( ctx : ^Context ) -> Vec2 { assert(ctx != nil); return ctx.cursor_pos } -set_alpha_scalar :: #force_inline proc( ctx : ^Context, scalar : f32 ) { assert(ctx != nil); ctx.alpha_sharpen = scalar } -set_px_scalar :: #force_inline proc( ctx : ^Context, scalar : f32 ) { assert(ctx != nil); ctx.px_scalar = scalar } -set_colour :: #force_inline proc( ctx : ^Context, colour : Colour ) { assert(ctx != nil); ctx.colour = colour } +get_cursor_pos :: #force_inline proc( ctx : ^Context ) -> Vec2 { assert(ctx != nil); return ctx.cursor_pos } +set_alpha_scalar :: #force_inline proc( ctx : ^Context, scalar : f32 ) { assert(ctx != nil); ctx.alpha_sharpen = scalar } +set_px_scalar :: #force_inline proc( ctx : ^Context, scalar : f32 ) { assert(ctx != nil); ctx.px_scalar = scalar } +set_colour :: #force_inline proc( ctx : ^Context, colour : Colour ) { assert(ctx != nil); ctx.colour = colour } + +set_snap_glyph_pos :: #force_inline proc( ctx : ^Context, should_snap : b32 ) { + assert(ctx != nil) + ctx.shaper_ctx.snap_glyph_position = should_snap +} draw_text :: #force_inline proc( ctx : ^Context, font : Font_ID, px_size : f32, position, scale : Vec2, text_utf8 : string ) { @@ -541,6 +547,46 @@ draw_text :: #force_inline proc( ctx : ^Context, font : Font_ID, px_size : f32, ) } +draw_text_slice :: #force_inline proc( ctx : ^Context, font : Font_ID, px_size : f32, position, scale : Vec2, texts : []string ) +{ + profile(#procedure) + assert( ctx != nil ) + assert( font >= 0 && int(font) < len(ctx.entries) ) + assert( len(texts) > 0 ) + + entry := ctx.entries[ font ] + + ctx.cursor_pos = {} + + position := position + position.x = ceil(position.x * ctx.snap_width ) / ctx.snap_width + position.y = ceil(position.y * ctx.snap_height) / ctx.snap_height + + colour := ctx.colour + colour.a = 1.0 + ctx.alpha_sharpen + + font_scale := parser_scale( entry.parser_info, px_size ) + + px_upscale := px_size * ctx.px_scalar + downscale := scale * (1 / ctx.px_scalar) + font_scale_upscale := parser_scale( entry.parser_info, px_upscale ) + + shapes := make( []Shaped_Text, len(texts) ) + for str, id in texts { + assert( len(str) > 0 ) + shape := shaper_shape_text_cached( str, & ctx.shaper_ctx, & ctx.shape_cache, + font, + entry, + px_upscale, + font_scale_upscale, + shaper_shape_text_uncached_advanced + ) + shapes[id] = shape + } + generate_shapes_draw_list(ctx, font, colour, entry, font_scale_upscale, position, scale, shapes ) +} + + // draw_text_no_snap :: #force_inline proc( ctx : ^Context, font : Font_ID, px_size : f32, position, scale : Vec2, text_utf8 : string ) // { // profile(#procedure) diff --git a/code/grime/profiler.odin b/code/grime/profiler.odin index 654578d..2fcc5f7 100644 --- a/code/grime/profiler.odin +++ b/code/grime/profiler.odin @@ -31,4 +31,3 @@ profile_begin :: #force_inline proc "contextless" ( name : string, loc := #calle profile_end :: #force_inline proc "contextless" () { spall._buffer_end( & Module_Context.ctx, & Module_Context.buffer) } - diff --git a/code/grime/string_cache.odin b/code/grime/string_cache.odin index 425f93e..ac4ff69 100644 --- a/code/grime/string_cache.odin +++ b/code/grime/string_cache.odin @@ -18,10 +18,7 @@ import "core:strings" StringKey :: distinct u64 RunesCached :: []rune -// TODO(Ed): There doesn't seem to be a need for caching the runes. -// It seems like no one has had a bottleneck just iterating through the code points on demand when needed. -// So we should problably scrap storing them that way. - +// Note(Ed): No longer using for caching but could still be useful in the future StrRunesPair :: struct { str : string, runes : []rune, @@ -29,9 +26,11 @@ StrRunesPair :: struct { to_str_runes_pair_via_string :: #force_inline proc ( content : string ) -> StrRunesPair { return { content, to_runes(content) } } to_str_runes_pair_via_runes :: #force_inline proc ( content : []rune ) -> StrRunesPair { return { to_string(content), content } } +StrCached :: string + StringCache :: struct { slab : Slab, - table : HMapChained(StrRunesPair), + table : HMapChained(StrCached), } // This is the default string cache for the runtime module. @@ -44,9 +43,9 @@ str_cache_init :: proc( table_allocator, slabs_allocator : Allocator ) -> (cache policy : SlabPolicy policy_ptr := & policy - // push( policy_ptr, SlabSizeClass { 64 * Kilobyte, 8, alignment }) - // push( policy_ptr, SlabSizeClass { 64 * Kilobyte, 16, alignment }) - // push( policy_ptr, SlabSizeClass { 128 * Kilobyte, 32, alignment }) + push( policy_ptr, SlabSizeClass { 64 * Kilobyte, 8, alignment }) + push( policy_ptr, SlabSizeClass { 64 * Kilobyte, 16, alignment }) + push( policy_ptr, SlabSizeClass { 128 * Kilobyte, 32, alignment }) push( policy_ptr, SlabSizeClass { 640 * Kilobyte, 64, alignment }) push( policy_ptr, SlabSizeClass { 64 * Kilobyte, 128, alignment }) push( policy_ptr, SlabSizeClass { 64 * Kilobyte, 256, alignment }) @@ -71,7 +70,7 @@ str_cache_init :: proc( table_allocator, slabs_allocator : Allocator ) -> (cache cache.slab, alloc_error = slab_init( & policy, allocator = slabs_allocator, dbg_name = dbg_name ) verify(alloc_error == .None, "Failed to initialize the string cache" ) - cache.table, alloc_error = make( HMapChained(StrRunesPair), 1 * Kilo, table_allocator, dbg_name = dbg_name ) + cache.table, alloc_error = make( HMapChained(StrCached), 1 * Kilo, table_allocator, dbg_name = dbg_name ) return } @@ -82,11 +81,11 @@ str_cache_reload :: #force_inline proc ( cache : ^StringCache, table_allocator, str_cache_set_module_ctx :: #force_inline proc "contextless" ( cache : ^StringCache ) { Module_String_Cache = cache } str_intern_key :: #force_inline proc( content : string ) -> StringKey { return cast(StringKey) crc32( transmute([]byte) content ) } -str_intern_lookup :: #force_inline proc( key : StringKey ) -> (^StrRunesPair) { return hmap_chained_get( Module_String_Cache.table, transmute(u64) key ) } +str_intern_lookup :: #force_inline proc( key : StringKey ) -> (^StrCached) { return hmap_chained_get( Module_String_Cache.table, transmute(u64) key ) } -str_intern :: proc( content : string ) -> StrRunesPair +str_intern :: #force_inline proc( content : string ) -> StrCached { - // profile(#procedure) + profile(#procedure) cache := Module_String_Cache key := str_intern_key(content) result := hmap_chained_get( cache.table, transmute(u64) key ) @@ -100,19 +99,14 @@ str_intern :: proc( content : string ) -> StrRunesPair copy_non_overlapping( raw_data(str_mem), raw_data(content), length ) - runes : []rune - runes, alloc_error = to_runes( content, slab_allocator(cache.slab) ) - verify( alloc_error == .None, "String cache had a backing allocator error" ) - // slab_validate_pools( cache.slab.backing ) - - result, alloc_error = hmap_chained_set( cache.table, transmute(u64) key, StrRunesPair { transmute(string) str_mem, runes } ) + result, alloc_error = hmap_chained_set( cache.table, transmute(u64) key, transmute(StrCached) str_mem ) verify( alloc_error == .None, "String cache had a backing allocator error" ) // slab_validate_pools( cache.slab.backing ) return (result ^) } -str_intern_fmt :: #force_inline proc( format : string, args : ..any, allocator := context.allocator ) -> StrRunesPair { +str_intern_fmt :: #force_inline proc( format : string, args : ..any, allocator := context.allocator ) -> StrCached { return str_intern(str_fmt(format, args, allocator = allocator)) } diff --git a/code/sectr/app/settings_menu.odin b/code/sectr/app/settings_menu.odin index 0f99a22..ccd8d8b 100644 --- a/code/sectr/app/settings_menu.odin +++ b/code/sectr/app/settings_menu.odin @@ -137,10 +137,10 @@ ui_settings_menu_builder :: proc( captures : rawptr = nil ) -> ( should_raise : if ! dd_app_config.is_open do break app_config_closed ui_size_to_content_y( dd_app_config.vbox) - ui_settings_entry_inputbox :: proc( input_box : ^UI_TextInputBox, is_even : bool, label : string, setting_title : StrRunesPair, input_policy : UI_TextInput_Policy ) + ui_settings_entry_inputbox :: proc( input_box : ^UI_TextInputBox, is_even : bool, label : string, setting_title : StrCached, input_policy : UI_TextInput_Policy ) { scope( theme_table_row(is_even)) - hb := ui_hbox(.Left_To_Right, str_intern_fmt("%v.hb", label).str); { + hb := ui_hbox(.Left_To_Right, str_fmt("%v.hb", label)); { using hb layout.size.min = {0, 25} @@ -149,14 +149,14 @@ ui_settings_menu_builder :: proc( captures : rawptr = nil ) -> ( should_raise : } scope(theme_text) - title := ui_text(str_intern_fmt("%v.title", label).str, setting_title); { + title := ui_text(str_fmt("%v.title", label), setting_title); { using title layout.anchor.ratio.x = 1.0 layout.margins.left = 10 layout.font_size = 12 } - ui_text_input_box( input_box, str_intern_fmt("%v.input_box", label).str, allocator = persistent_slab_allocator(), policy = input_policy ) + ui_text_input_box( input_box, str_fmt("%v.input_box", label), policy = input_policy, allocator = persistent_slab_allocator() ) { using input_box layout.flags |= {.Fixed_Width} @@ -357,7 +357,7 @@ ui_settings_menu_builder :: proc( captures : rawptr = nil ) -> ( should_raise : { ui_parent(dd_app_config.vbox) scope(theme_button) - btn := ui_button(str_intern_fmt("settings_menu.cam_zoom_mode.%s.btn", entry).str) + btn := ui_button(str_fmt("settings_menu.cam_zoom_mode.%s.btn", entry)) { using btn layout.size.min = {100, 25} @@ -368,7 +368,7 @@ ui_settings_menu_builder :: proc( captures : rawptr = nil ) -> ( should_raise : ui_parent(btn) scope(theme_text) - text_widget := ui_text(str_intern_fmt("settings_menu.cam_zoom_mode.%s.text", entry).str, str_intern_fmt("%s", entry)) + text_widget := ui_text(str_fmt("settings_menu.cam_zoom_mode.%s.text", entry), str_intern_fmt("%s", entry)) } if btn.pressed { @@ -553,6 +553,35 @@ ui_settings_menu_builder :: proc( captures : rawptr = nil ) -> ( should_raise : append( & input_str, to_runes(str_fmt("%v", config.font_size_canvas_scalar))) } } + + Text_Alpha_Sharpen: + { + ui_settings_entry_inputbox( & font_size_canvas_scalar_input, false, "settings_menu.font_size_canvas_scalar", str_intern("Font: Size Canvas Scalar"), + UI_TextInput_Policy { + digits_only = true, + disallow_leading_zeros = false, + disallow_decimal = false, + digit_min = 0.001, + digit_max = 10, + max_length = 4, + } + ) + using font_size_canvas_scalar_input + + if was_active + { + value, success := parse_f32(to_string(array_to_slice(input_str))) + if success { + value = clamp(value, 0.001, 9999.0) + config.font_size_canvas_scalar = value + } + } + else + { + clear( input_str ) + append( & input_str, to_runes(str_fmt("%v", config.font_size_canvas_scalar))) + } + } } } ui_vbox_end(vbox, compute_layout = false ) diff --git a/code/sectr/engine/client_api.odin b/code/sectr/engine/client_api.odin index 7db5104..16696a9 100644 --- a/code/sectr/engine/client_api.odin +++ b/code/sectr/engine/client_api.odin @@ -354,8 +354,8 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem // debug.path_lorem = str_fmt("C:/projects/SectrPrototype/examples/Lorem Ipsum (197).txt", allocator = persistent_slab_allocator()) // debug.path_lorem = str_fmt("C:/projects/SectrPrototype/examples/Lorem Ipsum (1022).txt", allocator = persistent_slab_allocator()) - debug.path_lorem = str_fmt("C:/projects/SectrPrototype/examples/sokol_gp.h", allocator = persistent_slab_allocator()) - // debug.path_lorem = str_fmt("C:/projects/SectrPrototype/examples/ve_fontcache.h", allocator = persistent_slab_allocator()) + // debug.path_lorem = str_fmt("C:/projects/SectrPrototype/examples/sokol_gp.h", allocator = persistent_slab_allocator()) + debug.path_lorem = str_fmt("C:/projects/SectrPrototype/examples/ve_fontcache.h", allocator = persistent_slab_allocator()) alloc_error : AllocatorError; success : bool debug.lorem_content, success = os.read_entire_file( debug.path_lorem, persistent_slab_allocator() ) @@ -521,8 +521,6 @@ tick_work_frame :: #force_inline proc( host_delta_time_ms : f64 ) -> b32 context.allocator = frame_slab_allocator() context.temp_allocator = transient_allocator() - // rl.PollInputEvents() - config := & get_state().config debug := & get_state().debug @@ -530,6 +528,9 @@ tick_work_frame :: #force_inline proc( host_delta_time_ms : f64 ) -> b32 debug.draw_ui_padding_bounds = false debug.draw_ui_content_bounds = false + font_provider_set_alpha_sharpen(0.45) + font_provider_set_snap_glyph_pos(true) + // config.engine_refresh_hz = 165 // config.color_theme = App_Thm_Light @@ -550,7 +551,6 @@ tick_work_frame :: #force_inline proc( host_delta_time_ms : f64 ) -> b32 should_close |= update( host_delta_time_ms ) render() - // rl.SwapScreenBuffer() return should_close } diff --git a/code/sectr/engine/render.odin b/code/sectr/engine/render.odin index 184fb06..e71b653 100644 --- a/code/sectr/engine/render.odin +++ b/code/sectr/engine/render.odin @@ -238,11 +238,11 @@ render_mode_screenspace :: proc( screen_extent : Extents2, screen_ui : ^UI_State hot_box := ui_box_from_key( ui.curr_cache, ui.hot ) active_box := ui_box_from_key( ui.curr_cache, ui.active ) if hot_box != nil { - debug_text("Worksapce Hot Box : %v", hot_box.label.str ) + debug_text("Worksapce Hot Box : %v", hot_box.label ) debug_text("Workspace Hot Range2: %v", hot_box.computed.bounds.pts) } if active_box != nil{ - debug_text("Workspace Active Box: %v", active_box.label.str ) + debug_text("Workspace Active Box: %v", active_box.label ) } } @@ -255,11 +255,11 @@ render_mode_screenspace :: proc( screen_extent : Extents2, screen_ui : ^UI_State hot_box := ui_box_from_key( ui.curr_cache, ui.hot ) active_box := ui_box_from_key( ui.curr_cache, ui.active ) if hot_box != nil { - debug_text("Hot Box : %v", hot_box.label.str ) + debug_text("Hot Box : %v", hot_box.label ) debug_text("Hot Range2: %v", hot_box.computed.bounds.pts) } if active_box != nil{ - debug_text("Active Box: %v", active_box.label.str ) + debug_text("Active Box: %v", active_box.label ) } } @@ -590,7 +590,7 @@ render_ui_via_box_list :: proc( box_list : []UI_RenderBoxInfo, text_list : []UI_ box_layer_done : b32 = false for box_id < cast(i32) len(box_list) && ! box_layer_done { - profile("GP_Render") + // profile("GP_Render") box_layer_done = b32(box_id > 0) && box_list[ box_id - 1 ].layer_signal entry := box_list[box_id] @@ -629,7 +629,7 @@ render_ui_via_box_list :: proc( box_list : []UI_RenderBoxInfo, text_list : []UI_ } if shape_enqueued { - profile("render ui box_layer") + // profile("render ui box_layer") render_flush_gp() shape_enqueued = false } @@ -638,7 +638,7 @@ render_ui_via_box_list :: proc( box_list : []UI_RenderBoxInfo, text_list : []UI_ text_layer_done : b32 = false for text_id < cast(i32) len(text_list) && ! text_layer_done { - profile("Text_Render") + // profile("Text_Render") entry := text_list[text_id] font := entry.font.key != 0 ? entry.font : default_font diff --git a/code/sectr/font/provider.odin b/code/sectr/font/provider.odin index 9c1e72d..7d83da4 100644 --- a/code/sectr/font/provider.odin +++ b/code/sectr/font/provider.odin @@ -46,14 +46,14 @@ font_provider_startup :: proc( ctx : ^FontProviderContext ) verify( error == AllocatorError.None, "Failed to allocate font_cache" ) ve.startup( & ve_ctx, .STB_TrueType, allocator = persistent_slab_allocator() ) - ve_ctx.glyph_buffer.over_sample = { 4,4 } + // ve_ctx.glyph_buffer.over_sample = { 4,4 } log("VEFontCached initialized") font_provider_setup_sokol_gfx_objects( & render, ve_ctx ) } font_provider_reload :: proc( ctx : ^FontProviderContext ) { - ctx.ve_ctx.glyph_buffer.over_sample = { 4,4 } * 1.0 + // ctx.ve_ctx.glyph_buffer.over_sample = { 4,4 } * 2 hmap_chained_reload( ctx.font_cache, persistent_allocator()) ve.hot_reload( & ctx.ve_ctx, persistent_slab_allocator() ) ve.clear_atlas_region_caches(& ctx.ve_ctx) @@ -116,10 +116,18 @@ font_load :: proc(path_file : string, return fid } +font_provider_set_alpha_sharpen :: #force_inline proc( scalar : f32 ) { + ve.set_alpha_scalar( & get_state().font_provider_ctx.ve_ctx, scalar ) +} + font_provider_set_px_scalar :: #force_inline proc( scalar : f32 ) { ve.set_px_scalar( & get_state().font_provider_ctx.ve_ctx, scalar ) } +font_provider_set_snap_glyph_pos :: #force_inline proc( should_snap : b32 ) { + ve.set_snap_glyph_pos( & get_state().font_provider_ctx.ve_ctx, should_snap ) +} + Font_Use_Default_Size :: f32(0.0) font_provider_resolve_draw_id :: #force_inline proc( id : FontID, size := Font_Use_Default_Size ) -> (ve_id :ve.Font_ID, resolved_size : i32) diff --git a/code/sectr/font/render_sokol.odin b/code/sectr/font/render_sokol.odin index a4c99ad..11ff90e 100644 --- a/code/sectr/font/render_sokol.odin +++ b/code/sectr/font/render_sokol.odin @@ -172,8 +172,8 @@ font_provider_setup_sokol_gfx_objects :: proc( ctx : ^VE_RenderData, ve_ctx : ve mipmap_filter = Filter.NEAREST, wrap_u = .CLAMP_TO_EDGE, wrap_v = .CLAMP_TO_EDGE, - min_lod = -1000.0, - max_lod = 1000.0, + min_lod = -1.0, + max_lod = 1.0, border_color = BorderColor.OPAQUE_BLACK, compare = .NEVER, max_anisotropy = 1, @@ -307,14 +307,14 @@ font_provider_setup_sokol_gfx_objects :: proc( ctx : ^VE_RenderData, ve_ctx : ve atlas_rt_sampler = sokol_gfx.make_sampler( SamplerDescription { min_filter = Image_Filter, mag_filter = Image_Filter, - mipmap_filter = Filter.LINEAR, + mipmap_filter = Filter.NEAREST, wrap_u = .CLAMP_TO_EDGE, wrap_v = .CLAMP_TO_EDGE, - min_lod = -1000.0, - max_lod = 1000.0, + min_lod = -1.0, + max_lod = 1.0, border_color = BorderColor.OPAQUE_BLACK, compare = .NEVER, - max_anisotropy = 16, + max_anisotropy = 1, }) verify( sokol_gfx.query_sampler_state( atlas_rt_sampler) < ResourceState.FAILED, "Failed to make atlas_rt_sampler" ) diff --git a/code/sectr/grime/mappings.odin b/code/sectr/grime/mappings.odin index d439412..cbc5d66 100644 --- a/code/sectr/grime/mappings.odin +++ b/code/sectr/grime/mappings.odin @@ -305,8 +305,8 @@ import "codebase:grime" to_bytes :: grime.to_bytes // strings - StrRunesPair :: grime.StrRunesPair - StringCache :: grime.StringCache + StrCached :: grime.StrCached + StringCache :: grime.StringCache str_cache_init :: grime.str_cache_init str_cache_reload :: grime.str_cache_reload diff --git a/code/sectr/parser/whitespace.odin b/code/sectr/parser/whitespace.odin index 3a5a403..1ac10ed 100644 --- a/code/sectr/parser/whitespace.odin +++ b/code/sectr/parser/whitespace.odin @@ -63,7 +63,7 @@ PWS_LexResult :: struct { PWS_Token :: struct { type : PWS_TokenType, line, column : u32, - content : StrRunesPair, + content : StrCached, } PWS_AST_Type :: enum u32 { @@ -80,7 +80,7 @@ PWS_AST :: struct { type : PWS_AST_Type, line, column : u32, - content : StrRunesPair, + content : StrCached, } PWS_ParseError :: struct { diff --git a/code/sectr/project/project.odin b/code/sectr/project/project.odin index c02b231..ce38c74 100644 --- a/code/sectr/project/project.odin +++ b/code/sectr/project/project.odin @@ -15,8 +15,8 @@ ProjectConfig :: struct { } Project :: struct { - path : StrRunesPair, - name : StrRunesPair, + path : StrCached, + name : StrCached, config : ProjectConfig, codebase : CodeBase, diff --git a/code/sectr/project/serialize.odin b/code/sectr/project/serialize.odin index 07ac711..0feb9c7 100644 --- a/code/sectr/project/serialize.odin +++ b/code/sectr/project/serialize.odin @@ -163,12 +163,12 @@ project_save :: proc( project : ^ Project, archive : ^ ArchiveData = nil ) } project_serialize( project, archive ) - if ! os.is_dir( project.path.str ) { - os.make_directory( project.path.str ) - verify( cast(b32) os.is_dir( project.path.str ), "Failed to create project path for saving" ) + if ! os.is_dir( project.path) { + os.make_directory( project.path ) + verify( cast(b32) os.is_dir( project.path ), "Failed to create project path for saving" ) } - os.write_entire_file( str_tmp_from_any( project.path.str, project.name.str, ".sectr_proj", sep = ""), archive.data ) + os.write_entire_file( str_tmp_from_any( project.path, project.name, ".sectr_proj", sep = ""), archive.data ) } project_load :: proc( path : string, project : ^ Project, archive : ^ ArchiveData = nil ) diff --git a/code/sectr/project/workspace.odin b/code/sectr/project/workspace.odin index 0eead14..e66f843 100644 --- a/code/sectr/project/workspace.odin +++ b/code/sectr/project/workspace.odin @@ -7,7 +7,7 @@ or frame tiling towards the application's screenspace. package sectr Workspace :: struct { - name : StrRunesPair, + name : StrCached, cam : Camera, zoom_target : f32, diff --git a/code/sectr/shaders/ve_blit_atlas.shdc.glsl b/code/sectr/shaders/ve_blit_atlas.shdc.glsl index 8b07b6f..7e6454c 100644 --- a/code/sectr/shaders/ve_blit_atlas.shdc.glsl +++ b/code/sectr/shaders/ve_blit_atlas.shdc.glsl @@ -15,34 +15,36 @@ layout(binding = 0) uniform texture2D ve_blit_atlas_src_texture; layout(binding = 0) uniform sampler ve_blit_atlas_src_sampler; layout(binding = 0) uniform ve_blit_atlas_fs_params { - int region; + Vec2 glyph_buffer_size; + f32 over_sample; + int region; }; -float down_sample( vec2 uv, vec2 texture_size ) +float down_sample_( vec2 uv, vec2 texture_size ) { - float down_sample_scale = 1.0f / 4.0f; + float down_sample = 1.0f / over_sample; float value = - texture(sampler2D( ve_blit_atlas_src_texture, ve_blit_atlas_src_sampler ), uv + vec2( 0.0f, 0.0f ) * texture_size ).x * down_sample_scale - + texture(sampler2D( ve_blit_atlas_src_texture, ve_blit_atlas_src_sampler ), uv + vec2( 0.0f, 1.0f ) * texture_size ).x * down_sample_scale - + texture(sampler2D( ve_blit_atlas_src_texture, ve_blit_atlas_src_sampler ), uv + vec2( 1.0f, 0.0f ) * texture_size ).x * down_sample_scale - + texture(sampler2D( ve_blit_atlas_src_texture, ve_blit_atlas_src_sampler ), uv + vec2( 1.0f, 1.0f ) * texture_size ).x * down_sample_scale; + texture(sampler2D( ve_blit_atlas_src_texture, ve_blit_atlas_src_sampler ), uv + vec2( 0.0f, 0.0f ) * glyph_buffer_size ).x * down_sample + + texture(sampler2D( ve_blit_atlas_src_texture, ve_blit_atlas_src_sampler ), uv + vec2( 0.0f, 1.0f ) * glyph_buffer_size ).x * down_sample + + texture(sampler2D( ve_blit_atlas_src_texture, ve_blit_atlas_src_sampler ), uv + vec2( 1.0f, 0.0f ) * glyph_buffer_size ).x * down_sample + + texture(sampler2D( ve_blit_atlas_src_texture, ve_blit_atlas_src_sampler ), uv + vec2( 1.0f, 1.0f ) * glyph_buffer_size ).x * down_sample; + return value; } void main() { - // TODO(Ed): The original author made these consts, I want to instead expose as uniforms... const vec2 texture_size = 1.0f / vec2( 2048.0f, 512.0f ); // VEFontCache.Context.buffer_width/buffer_height if ( region == 0 || region == 1 || region == 2 ) { - float down_sample_scale = 1.0f / 4.0f; + float down_sample = 1.0f / over_sample; float alpha = - down_sample( uv + vec2( -1.0f, -1.5f ) * texture_size, texture_size ) * down_sample_scale - + down_sample( uv + vec2( 0.5f, -1.5f ) * texture_size, texture_size ) * down_sample_scale - + down_sample( uv + vec2( -1.5f, 0.5f ) * texture_size, texture_size ) * down_sample_scale - + down_sample( uv + vec2( 0.5f, 0.5f ) * texture_size, texture_size ) * down_sample_scale; + down_sample( uv + vec2( -1.0f, -1.5f ) * texture_size, glyph_buffer_size ) * down_sample + + down_sample( uv + vec2( 0.5f, -1.5f ) * texture_size, glyph_buffer_size ) * down_sample + + down_sample( uv + vec2( -1.5f, 0.5f ) * texture_size, glyph_buffer_size ) * down_sample + + down_sample( uv + vec2( 0.5f, 0.5f ) * texture_size, glyph_buffer_size ) * down_sample; frag_color = vec4( 1.0f, 1.0f, 1.0f, alpha ); } else diff --git a/code/sectr/shaders/ve_draw_text.shdc.glsl b/code/sectr/shaders/ve_draw_text.shdc.glsl index 70b4743..63db53d 100644 --- a/code/sectr/shaders/ve_draw_text.shdc.glsl +++ b/code/sectr/shaders/ve_draw_text.shdc.glsl @@ -23,25 +23,24 @@ layout(binding = 0) uniform texture2D ve_draw_text_src_texture; layout(binding = 0) uniform sampler ve_draw_text_src_sampler; layout(binding = 0) uniform ve_draw_text_fs_params { - int down_sample; + Vec2 glyph_buffer_size; + f32 over_sample; vec4 colour; }; void main() { float alpha = texture(sampler2D( ve_draw_text_src_texture, ve_draw_text_src_sampler ), uv ).x; - if ( down_sample == 1 ) - { - // TODO(Ed): The original author made these consts, I want to instead expose as uniforms... - const vec2 texture_size = 1.0f / vec2( 2048.0f, 512.0f ); // VEFontCache.Context.buffer_width/buffer_height - const float down_sample_scale = 1.0f / 4.0f; - alpha = - (texture(sampler2D( ve_draw_text_src_texture, ve_draw_text_src_sampler), uv + vec2( -0.5f, -0.5f) * texture_size ).x * down_sample_scale) - + (texture(sampler2D( ve_draw_text_src_texture, ve_draw_text_src_sampler), uv + vec2( -0.5f, 0.5f) * texture_size ).x * down_sample_scale) - + (texture(sampler2D( ve_draw_text_src_texture, ve_draw_text_src_sampler), uv + vec2( 0.5f, -0.5f) * texture_size ).x * down_sample_scale) - + (texture(sampler2D( ve_draw_text_src_texture, ve_draw_text_src_sampler), uv + vec2( 0.5f, 0.5f) * texture_size ).x * down_sample_scale); - } + const vec2 texture_size = 1.0f / ; + const float down_sample = 1.0f / over_sample; + + alpha = + (texture(sampler2D( ve_draw_text_src_texture, ve_draw_text_src_sampler), uv + vec2( -0.5f, -0.5f) * glyph_buffer_size ).x * down_sample) + + (texture(sampler2D( ve_draw_text_src_texture, ve_draw_text_src_sampler), uv + vec2( -0.5f, 0.5f) * glyph_buffer_size ).x * down_sample) + + (texture(sampler2D( ve_draw_text_src_texture, ve_draw_text_src_sampler), uv + vec2( 0.5f, -0.5f) * glyph_buffer_size ).x * down_sample) + + (texture(sampler2D( ve_draw_text_src_texture, ve_draw_text_src_sampler), uv + vec2( 0.5f, 0.5f) * glyph_buffer_size ).x * down_sample); + frag_color = vec4( colour.xyz, colour.a * alpha ); } @end diff --git a/code/sectr/ui/core/base.odin b/code/sectr/ui/core/base.odin index 12cafe9..43fb73a 100644 --- a/code/sectr/ui/core/base.odin +++ b/code/sectr/ui/core/base.odin @@ -237,7 +237,7 @@ ui_graph_build_begin :: proc( ui : ^ UI_State, bounds : Vec2 = {} ) } ui.built_box_count = 0 - root = ui_box_make( {}, str_intern(str_fmt("%s: root#001", ui == & state.screen_ui ? "Screen" : "Workspace" )).str) + root = ui_box_make( {}, str_intern(str_fmt("%s: root#001", ui == & state.screen_ui ? "Screen" : "Workspace" ))) if ui == & state.screen_ui { root.layout.size = range2(Vec2(state.app_window.extent) * 2, {}) } @@ -283,7 +283,8 @@ ui_graph_build_end :: proc( ui : ^UI_State ) if ! current.computed.fresh { - if len(current.text.str) > 0 { + if len(current.text) > 0 { + profile("text shape") // app_window := get_state().app_window // screen_extent := app_window.extent // screen_size := screen_extent * 2 @@ -293,7 +294,7 @@ ui_graph_build_end :: proc( ui : ^UI_State ) // over_sample : f32 = f32(get_state().config.font_size_canvas_scalar) - current.computed.text_shape = shape_text_cached( current.text.str, current.style.font, current.layout.font_size, 1.0 ) + current.computed.text_shape = shape_text_cached( current.text, current.style.font, current.layout.font_size, 1.0 ) } ui_box_compute_layout( current ) } @@ -302,6 +303,8 @@ ui_graph_build_end :: proc( ui : ^UI_State ) continue } + profile("render queue resolution") + different_ancestory := b8(current.ancestors != previous_layer) entry_box := UI_RenderBoxInfo { @@ -318,7 +321,7 @@ ui_graph_build_end :: proc( ui : ^UI_State ) // if len(current.text.str) > 0 // { entry_text := UI_RenderTextInfo { - text = current.text.str, + text = current.text, shape = current.computed.text_shape, position = current.computed.text_pos, color = current.style.text_color, diff --git a/code/sectr/ui/core/box.odin b/code/sectr/ui/core/box.odin index 6d118d3..39d6c22 100644 --- a/code/sectr/ui/core/box.odin +++ b/code/sectr/ui/core/box.odin @@ -22,8 +22,8 @@ UI_NavLinks :: struct { UI_Box :: struct { // Cache ID key : UI_Key, - label : StrRunesPair, - text : StrRunesPair, + label : StrCached, + text : StrCached, // Regenerated per frame. nav : UI_NavLinks, @@ -67,7 +67,7 @@ ui_box_from_key :: #force_inline proc ( cache : ^HMapChained(UI_Box), key : UI_K ui_box_make :: proc( flags : UI_BoxFlags, label : string ) -> (^ UI_Box) { - // profile(#procedure) + profile(#procedure) using ui := get_state().ui_context key := ui_key_from_string( label ) diff --git a/code/sectr/ui/core/layout.odin b/code/sectr/ui/core/layout.odin index 0d122be..da872b9 100644 --- a/code/sectr/ui/core/layout.odin +++ b/code/sectr/ui/core/layout.odin @@ -194,21 +194,21 @@ ui_layout_pop :: #force_inline proc() { pop( & ui_set_layout :: #force_inline proc( layout : UI_Layout, preset : UI_StylePreset ) { stack_peek_ref( & get_state().ui_context.layout_combo_stack).array[preset] = layout } -ui_size_to_content_xy :: proc ( box : ^UI_Box) { +ui_size_to_content_xy :: #force_inline proc ( box : ^UI_Box) { using box children_bounds := ui_compute_children_overall_bounds(box) layout.size.min = size_range2(children_bounds) layout.flags |= { .Fixed_Width, .Fixed_Height } } -ui_size_to_content_x :: proc ( box : ^UI_Box) { +ui_size_to_content_x :: #force_inline proc ( box : ^UI_Box) { using box children_bounds := ui_compute_children_overall_bounds(box) layout.size.min.x = size_range2(children_bounds).x layout.flags |= { .Fixed_Width } } -ui_size_to_content_y :: proc ( box : ^UI_Box) { +ui_size_to_content_y :: #force_inline proc ( box : ^UI_Box) { using box children_bounds := ui_compute_children_overall_bounds(box) layout.size.min.y = size_range2(children_bounds).y diff --git a/code/sectr/ui/core/layout_compute.odin b/code/sectr/ui/core/layout_compute.odin index 6f237a0..2ccd1a6 100644 --- a/code/sectr/ui/core/layout_compute.odin +++ b/code/sectr/ui/core/layout_compute.odin @@ -71,7 +71,7 @@ ui_box_compute_layout :: proc( box : ^UI_Box, adjusted_size.y = max( adjusted_max_size_y, layout.size.min.y) text_size : Vec2 - if len(box.text.str) > 0 + if len(box.text) > 0 { text_size = computed.text_shape.size // if layout.font_size == computed.text_size.y { @@ -187,7 +187,7 @@ ui_box_compute_layout :: proc( box : ^UI_Box, computed.content = content_bounds // 8. Text position & size - if len(box.text.str) > 0 + if len(box.text) > 0 { ascent, descent, line_gap := get_font_vertical_metrics(style.font, layout.font_size) diff --git a/code/sectr/ui/core/signal.odin b/code/sectr/ui/core/signal.odin index ba2af5e..0420e16 100644 --- a/code/sectr/ui/core/signal.odin +++ b/code/sectr/ui/core/signal.odin @@ -30,7 +30,7 @@ UI_Signal :: struct { ui_signal_from_box :: proc ( box : ^ UI_Box, update_style := true, update_deltas := true ) -> UI_Signal { - // profile(#procedure) + profile(#procedure) ui := get_state().ui_context input := get_state().input diff --git a/code/sectr/ui/floating.odin b/code/sectr/ui/floating.odin index bc68d7f..5b2bc3e 100644 --- a/code/sectr/ui/floating.odin +++ b/code/sectr/ui/floating.odin @@ -22,7 +22,7 @@ ui_floating_startup :: proc( self : ^UI_FloatingManager, build_queue_cap, tracke error : AllocatorError queue_dbg_name := str_intern(str_fmt("%s: build_queue", dbg_name)) - self.build_queue, error = make( Array(UI_Floating), build_queue_cap, dbg_name = queue_dbg_name.str, allocator = allocator ) + self.build_queue, error = make( Array(UI_Floating), build_queue_cap, dbg_name = queue_dbg_name, allocator = allocator ) if error != AllocatorError.None { ensure(false, "Failed to allocate the build_queue") diff --git a/code/sectr/ui/tests.odin b/code/sectr/ui/tests.odin index dca8562..8ea017b 100644 --- a/code/sectr/ui/tests.odin +++ b/code/sectr/ui/tests.odin @@ -61,8 +61,8 @@ test_draggable :: proc() draggable.layout.pos = debug.draggable_box_pos draggable.layout.size.min = debug.draggable_box_size - draggable.text = { str_fmt("%v", debug.draggable_box_pos), {} } - draggable.text.runes = to_runes(draggable.text.str) + draggable.text = str_intern_fmt("%v", debug.draggable_box_pos) + // draggable.text.runes = to_runes(draggable.text) } test_parenting :: proc( default_layout : ^UI_Layout, frame_style_default : ^UI_Style ) @@ -195,6 +195,9 @@ test_whitespace_ast :: proc( default_layout : ^UI_Layout, frame_style_default : label_id := 0 + builder : StringBuilder + str.builder_init_len_cap( & builder, len = 0, cap = 16 * Kilobyte ) + line_id := 0 for line in array_to_slice( debug.lorem_parse.lines ) { @@ -205,11 +208,17 @@ test_whitespace_ast :: proc( default_layout : ^UI_Layout, frame_style_default : profile("line") ui_layout( text_layout ) - line_hbox := ui_widget(str_fmt( "line %v", line_id ), {.Mouse_Clickable}) - if line_hbox.key == ui.hot && false + profile_begin("label fmt") + str.builder_reset( & builder) + label := str_fmt_builder( & builder, "line %d", line_id ) + profile_end() + + line_hbox := ui_widget(label, {.Mouse_Clickable}) + + if false && line_hbox.key == ui.hot { - line_hbox.text = StrRunesPair {} + line_hbox.text = StrCached {} ui_parent(line_hbox) chunk_layout := text_layout @@ -230,33 +239,34 @@ test_whitespace_ast :: proc( default_layout : ^UI_Layout, frame_style_default : #partial switch head.type { case .Visible: - label := str_intern( str_fmt( "%v %v", head.content.str, label_id )) - widget = ui_text( label.str, head.content ) + label := str_fmt( "%v %v", head.content, label_id ) + widget = ui_text( label, head.content ) label_id += 1 chunk_layout.pos.x += size_range2( widget.computed.bounds ).x case .Spaces: - label := str_intern( str_fmt( "%v %v", "space", label_id )) - widget = ui_text_spaces( label.str ) + label := str_fmt( "%v %v", "space", label_id ) + widget = ui_text_spaces( label ) label_id += 1 - for idx in 1 ..< len( head.content.runes ) - { + // for idx in 1 ..< len( head.content.runes ) + // { // TODO(Ed): VIRTUAL WHITESPACE // widget.style.layout.size.x += range2_size( widget.computed.bounds ) - } + // } chunk_layout.pos.x += size_range2( widget.computed.bounds ).x case .Tabs: - label := str_intern( str_fmt( "%v %v", "tab", label_id )) - widget = ui_text_tabs( label.str ) + label := str_fmt( "%v %v", "tab", label_id ) + widget = ui_text_tabs( label ) label_id += 1 - for idx in 1 ..< len( head.content.runes ) - { + // for idx in 1 ..< len( head.content.runes ) + // { + // TODO(Ed): VIRTUAL WHITESPACE // widget.style.layout.size.x += range2_size( widget.computed.bounds ) - } + // } chunk_layout.pos.x += size_range2( widget.computed.bounds ).x } @@ -268,30 +278,31 @@ test_whitespace_ast :: proc( default_layout : ^UI_Layout, frame_style_default : } else { - builder_backing : [16 * Kilobyte] byte - builder := str.builder_from_bytes( builder_backing[:] ) + profile("line (single-box)") line_hbox.layout.flags |= { .Size_To_Text } + str.builder_reset( & builder) head := line.first.next for ; head != nil; { - str.write_string( & builder, head.content.str ) + profile("write ast node") + str.write_string( & builder, head.content ) head = head.next } + profile("intern") line_hbox.text = str_intern( to_string( builder ) ) - // if len(line_hbox.text.str) == 0 { - // line_hbox.text = str_intern( " " ) - // } } - if len(line_hbox.text.str) > 0 { + if len(line_hbox.text) > 0 { + profile("append actual") array_append( widgets_ptr, line_hbox ) text_layout.pos.x = text_layout.pos.x text_layout.pos.y -= size_range2(line_hbox.computed.bounds).y } else { + profile("end") widget := & widgets.data[ widgets.num - 1 ] if widget.box != nil { text_layout.pos.y -= size_range2( widget.computed.bounds ).y diff --git a/code/sectr/ui/widgets.odin b/code/sectr/ui/widgets.odin index 5d42c09..7f41078 100644 --- a/code/sectr/ui/widgets.odin +++ b/code/sectr/ui/widgets.odin @@ -11,14 +11,14 @@ UI_Widget :: struct { using signal : UI_Signal, } -ui_widget :: proc( label : string, flags : UI_BoxFlags ) -> (widget : UI_Widget) +ui_widget :: #force_inline proc( label : string, flags : UI_BoxFlags ) -> (widget : UI_Widget) { widget.box = ui_box_make( flags, label ) widget.signal = ui_signal_from_box( widget.box ) return } -ui_button :: proc( label : string, flags : UI_BoxFlags = {} ) -> (btn : UI_Widget) +ui_button :: #force_inline proc( label : string, flags : UI_BoxFlags = {} ) -> (btn : UI_Widget) { btn_flags := UI_BoxFlags { .Mouse_Clickable } btn.box = ui_box_make( btn_flags | flags, label ) @@ -36,7 +36,7 @@ UI_DropDown :: struct { } @(deferred_out = ui_drop_down_end_auto) -ui_drop_down :: proc( drop_down : ^UI_DropDown, label : string, title_text : StrRunesPair, +ui_drop_down :: proc( drop_down : ^UI_DropDown, label : string, title_text : StrCached, direction := UI_LayoutDirection_Y.Top_To_Bottom, btn_flags := UI_BoxFlags{}, vb_flags := UI_BoxFlags{}, @@ -54,7 +54,7 @@ ui_drop_down :: proc( drop_down : ^UI_DropDown, label : string, title_text : Str } // Its assumed that the drop down has a vertical box parent already pushed -ui_drop_down_begin :: proc( drop_down : ^UI_DropDown, label : string, title_text : StrRunesPair, +ui_drop_down_begin :: proc( drop_down : ^UI_DropDown, label : string, title_text : StrCached, direction := UI_LayoutDirection_Y.Top_To_Bottom, btn_flags := UI_BoxFlags{}, vb_flags := UI_BoxFlags{}, @@ -68,7 +68,7 @@ ui_drop_down_begin :: proc( drop_down : ^UI_DropDown, label : string, title_text if btn_theme == nil do push(theme_drop_down_btn) else do push(btn_theme ^) defer ui_theme_pop() - btn = ui_button( str_intern_fmt("%s.btn", label).str ); + btn = ui_button( str_fmt("%s.btn", label) ); { btn.layout.padding.left = 4 ui_parent(btn) @@ -76,7 +76,7 @@ ui_drop_down_begin :: proc( drop_down : ^UI_DropDown, label : string, title_text if title_theme == nil do push(theme_text) else do push(title_theme ^) defer ui_theme_pop() - title = ui_text( str_intern_fmt("%s.btn.title", label).str, title_text) + title = ui_text( str_fmt("%s.btn.title", label), title_text) } if btn.pressed { @@ -91,7 +91,7 @@ ui_drop_down_begin :: proc( drop_down : ^UI_DropDown, label : string, title_text if vb_parent != nil { ui_parent_push(vb_parent) } - vbox = ui_vbox_begin( direction, str_intern_fmt("%v.vbox", label).str, flags = {.Mouse_Clickable}, compute_layout = vb_compute_layout ) + vbox = ui_vbox_begin( direction, str_fmt("%v.vbox", label), flags = {.Mouse_Clickable}, compute_layout = vb_compute_layout ) vbox.layout.anchor.ratio.y = 1.0 if vb_parent != nil { @@ -328,7 +328,7 @@ ui_resizable_handles :: #force_no_inline proc( parent : ^UI_Widget, pos : ^Vec2, name :: proc( label : string ) -> string { parent_label := (transmute(^string) context.user_ptr) ^ - return str_intern(str_fmt("%v.%v", parent_label, label )).str + return str_fmt("%v.%v", parent_label, label ) } context.user_ptr = & parent.label @@ -523,9 +523,9 @@ ui_scroll_box :: proc( label : string, flags : UI_BoxFlags ) -> (scroll_box : UI } #region("Text") -ui_text :: proc( label : string, content : StrRunesPair, flags : UI_BoxFlags = {} ) -> UI_Widget +ui_text :: #force_inline proc( label : string, content : StrCached, flags : UI_BoxFlags = {} ) -> UI_Widget { - // profile(#procedure) + profile(#procedure) state := get_state(); using state box := ui_box_make( flags, label ) @@ -535,9 +535,9 @@ ui_text :: proc( label : string, content : StrRunesPair, flags : UI_BoxFlags = { return { box, signal } } -ui_text_spaces :: proc( label : string, flags : UI_BoxFlags = {} ) -> UI_Widget +ui_text_spaces :: #force_inline proc( label : string, flags : UI_BoxFlags = {} ) -> UI_Widget { - // profile(#procedure) + profile(#procedure) state := get_state(); using state // TODO(Ed) : Move this somwhere in state. @@ -550,9 +550,9 @@ ui_text_spaces :: proc( label : string, flags : UI_BoxFlags = {} ) -> UI_Widget return { box, signal } } -ui_text_tabs :: proc( label : string, flags : UI_BoxFlags = {} ) -> UI_Widget +ui_text_tabs :: #force_inline proc( label : string, flags : UI_BoxFlags = {} ) -> UI_Widget { - // profile(#procedure) + profile(#procedure) state := get_state(); using state // TODO(Ed) : Move this somwhere in state. @@ -595,8 +595,8 @@ ui_text_input_box_reload :: #force_inline proc ( text_box : ^UI_TextInputBox, al ui_text_input_box :: proc( text_input_box : ^UI_TextInputBox, label : string, flags : UI_BoxFlags = {.Mouse_Clickable, .Focusable, .Click_To_Focus}, - allocator := context.allocator, - policy : UI_TextInput_Policy = {} + policy : UI_TextInput_Policy = {}, + allocator : Allocator, ) { // state := get_state() @@ -619,6 +619,7 @@ ui_text_input_box :: proc( text_input_box : ^UI_TextInputBox, label : string, input_str, error = make( Array(rune), Kilo, allocator ) ensure(error == AllocatorError.None, "Failed to allocate array for input_str of input_box") } + input_str.backing = allocator // Always assign allocator for hot-reload purposes if active { @@ -706,19 +707,19 @@ ui_text_input_box :: proc( text_input_box : ^UI_TextInputBox, label : string, ui_parent(text_input_box) name :: proc( label : string ) -> string { parent_label := (transmute(^string) context.user_ptr) ^ - return str_intern(str_fmt("%v: %v", parent_label, label )).str + return str_intern(str_fmt("%v: %v", parent_label, label )) } context.user_ptr = & parent.label // TODO(Ed): Allow for left and center alignment of text value_txt : UI_Widget; { scope(theme_text) - value_txt = ui_text(name("input_str"), to_str_runes_pair(array_to_slice(input_str))) + value_txt = ui_text(name("input_str"), str_intern(to_string(array_to_slice(input_str)))) using value_txt layout.alignment = {0.0, 0.0} layout.text_alignment = {1.0, 0.5} layout.anchor.left = 0.0 - layout.size.min = cast(Vec2) measure_text_size( text.str, style.font, layout.font_size, 0 ) + layout.size.min = cast(Vec2) measure_text_size( text, style.font, layout.font_size, 0 ) if active { ui_parent(value_txt) diff --git a/code/sectr/ui/window.odin b/code/sectr/ui/window.odin index 85cec75..996c308 100644 --- a/code/sectr/ui/window.odin +++ b/code/sectr/ui/window.odin @@ -27,7 +27,7 @@ UI_Window_ChildLayout :: enum(i32) { @(deferred_in=ui_window_end_auto) ui_window :: proc (window : ^UI_Window, label : string, - title : StrRunesPair = {}, + title : StrCached = {}, closable := true, maximizable := true, draggable := true, @@ -41,7 +41,7 @@ ui_window :: proc (window : ^UI_Window, label : string, } ui_window_begin :: proc( window : ^UI_Window, label : string, - title : StrRunesPair = {}, + title : StrCached = {}, closable := true, maximizable := true, draggable := true, @@ -83,7 +83,7 @@ ui_window_begin :: proc( window : ^UI_Window, label : string, scope(theme_transparent) vb = ui_vbox(.Top_To_Bottom, str_fmt_tmp("%s.vb", label)) - if len(title.str) > 0 || closable || maximizable || draggable { + if len(title) > 0 || closable || maximizable || draggable { dragged, maximized, closed = ui_window_bar(window, title, closable, maximizable, draggable) } @@ -109,7 +109,7 @@ ui_window_end :: proc (window : ^UI_Window) } ui_window_end_auto :: proc( window : ^UI_Window, label : string, - title : StrRunesPair = {}, + title : StrCached = {}, closable := true, maximizable := true, draggable := true, @@ -121,7 +121,7 @@ ui_window_end_auto :: proc( window : ^UI_Window, label : string, } ui_window_bar :: proc( window : ^UI_Window, - title : StrRunesPair = {}, + title : StrCached = {}, closable := true, maximizable := true, draggable := true, @@ -132,13 +132,13 @@ ui_window_bar :: proc( window : ^UI_Window, draggable_flag : UI_BoxFlags = draggable ? {.Mouse_Clickable} : {} scope(theme_window_bar) - bar = ui_hbox(.Left_To_Right, str_fmt_tmp("%s.bar", frame.label.str), draggable_flag); + bar = ui_hbox(.Left_To_Right, str_fmt_tmp("%s.bar", frame.label), draggable_flag); ui_parent(bar) - if len(title.str) > 0 + if len(title) > 0 { scope(theme_text) - tile_text = ui_text( str_fmt_tmp("%s.title_text", bar.label.str), title, {.Disabled}); { + tile_text = ui_text( str_fmt_tmp("%s.title_text", bar.label), title, {.Disabled}); { using tile_text layout.anchor.ratio.x = 1.0 layout.margins = { 0, 0, 15, 0} @@ -149,7 +149,7 @@ ui_window_bar :: proc( window : ^UI_Window, scope(theme_window_bar_btn) if maximizable { - maximize_btn = ui_button( str_fmt_tmp("%v.maximize_btn", bar.label.str) ); { + maximize_btn = ui_button( str_fmt_tmp("%v.maximize_btn", bar.label) ); { using maximize_btn if maximize_btn.pressed { is_maximized = ~is_maximized