From 9d0cc125a95a1391cc838434532dd63ace95b4c3 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Wed, 26 Jun 2024 06:03:00 -0400 Subject: [PATCH] Misc changes * Made refactor rende procedures to specify dependencies instead of directly grabbing from state singleton --- code/grime/profiler.odin | 6 +- code/sectr/app/state.odin | 4 +- code/sectr/engine/.render_testing.odin | 26 +- code/sectr/engine/client_api.odin | 36 +- .../engine/client_api_sokol_callbacks.odin | 2 - code/sectr/engine/render.odin | 126 ++--- code/sectr/engine/update.odin | 14 +- code/sectr/font/provider.odin | 514 +----------------- code/sectr/font/render_sokol.odin | 454 ++++++++++++++++ code/sectr/grime/context.odin | 1 + code/sectr/ui/core/base.odin | 2 +- code/sectr/ui/core/box.odin | 7 +- 12 files changed, 567 insertions(+), 625 deletions(-) create mode 100644 code/sectr/font/render_sokol.odin diff --git a/code/grime/profiler.odin b/code/grime/profiler.odin index 3facc2c..d0bec4e 100644 --- a/code/grime/profiler.odin +++ b/code/grime/profiler.odin @@ -17,13 +17,13 @@ set_profiler_module_context :: #force_inline proc "contextless" ( ctx : ^SpallPr @(deferred_none = profile_end) profile :: #force_inline proc "contextless" ( name : string, loc := #caller_location ) { - // spall._buffer_begin( & Module_Context.ctx, & Module_Context.buffer, name, "", loc ) + spall._buffer_begin( & Module_Context.ctx, & Module_Context.buffer, name, "", loc ) } profile_begin :: #force_inline proc "contextless" ( name : string, loc := #caller_location ) { - // spall._buffer_begin( & Module_Context.ctx, & Module_Context.buffer, name, "", loc ) + spall._buffer_begin( & Module_Context.ctx, & Module_Context.buffer, name, "", loc ) } profile_end :: #force_inline proc "contextless" () { - // spall._buffer_end( & Module_Context.ctx, & Module_Context.buffer) + spall._buffer_end( & Module_Context.ctx, & Module_Context.buffer) } diff --git a/code/sectr/app/state.odin b/code/sectr/app/state.odin index 134bc88..6fc5860 100644 --- a/code/sectr/app/state.odin +++ b/code/sectr/app/state.odin @@ -172,7 +172,7 @@ AppWindow :: struct { } FontData :: struct { - provider : FontProviderData, + provider : FontProviderContext, // TODO(Ed): We can have font constants here I guess but eventually // I rather have fonts configurable for a 'theme' combo @@ -245,7 +245,7 @@ State :: struct { fps_avg : f64, // fonts : FontData, - font_provider_data : FontProviderData, + font_provider_ctx : FontProviderContext, font_arial_unicode_ms : FontID, font_firacode : FontID, diff --git a/code/sectr/engine/.render_testing.odin b/code/sectr/engine/.render_testing.odin index 14d0d5c..217217c 100644 --- a/code/sectr/engine/.render_testing.odin +++ b/code/sectr/engine/.render_testing.odin @@ -48,9 +48,9 @@ render :: proc() // Will need to profile how expensive it is for batching with the UI box rendering // since the the text is correlated with the box rendering - font_provider := & state.font_provider_data + font_provider := & state.font_provider_ctx using font_provider - // ve_ctx := & font_provider.ve_font_cache + // ve_ctx := & font_provider.ve_ctx // Triangle Demo if false @@ -125,14 +125,14 @@ render :: proc() // text_test_str := str_fmt("HELLO VE FONT CACHE!") // text_test_str := str_fmt("C") - // font_provider := & state.font_provider_data + // font_provider := & state.font_provider_ctx fdef := hmap_chained_get( font_cache, default_font.key ) - ve.set_colour( & ve_font_cache, { 1.0, 1.0, 1.0, 1.0 } ) - ve.configure_snap( & ve_font_cache, u32(state.app_window.extent.x * 2.0), u32(state.app_window.extent.y * 2.0) ) + ve.set_colour( & ve_ctx, { 1.0, 1.0, 1.0, 1.0 } ) + ve.configure_snap( & ve_ctx, u32(state.app_window.extent.x * 2.0), u32(state.app_window.extent.y * 2.0) ) - ve.draw_text( & ve_font_cache, fdef.ve_id, text_test_str, {0.0, 0.975}, Vec2{1 / width, 1 / height} ) + ve.draw_text( & ve_ctx, fdef.ve_id, text_test_str, {0.0, 0.975}, Vec2{1 / width, 1 / height} ) } @@ -144,8 +144,8 @@ render :: proc() { profile("VEFontCache: render frame") - ve.optimize_draw_list( & ve_font_cache ) - draw_list := ve.get_draw_list( & ve_font_cache ) + ve.optimize_draw_list( & ve_ctx ) + draw_list := ve.get_draw_list( & ve_ctx ) draw_list_vert_slice := array_to_slice(draw_list.vertices) draw_list_index_slice := array_to_slice(draw_list.indices) @@ -169,8 +169,8 @@ render :: proc() continue } - width := ve_font_cache.atlas.buffer_width - height := ve_font_cache.atlas.buffer_height + width := ve_ctx.atlas.buffer_width + height := ve_ctx.atlas.buffer_height pass := glyph_pass if draw_call.clear_before_draw { @@ -205,8 +205,8 @@ render :: proc() continue } - width := ve_font_cache.atlas.width - height := ve_font_cache.atlas.height + width := ve_ctx.atlas.width + height := ve_ctx.atlas.height pass := atlas_pass if draw_call.clear_before_draw { @@ -299,6 +299,6 @@ render :: proc() } sokol_gfx.commit() - ve.flush_draw_list( & ve_font_cache ) + ve.flush_draw_list( & ve_ctx ) } } diff --git a/code/sectr/engine/client_api.odin b/code/sectr/engine/client_api.odin index 0909028..e84c893 100644 --- a/code/sectr/engine/client_api.odin +++ b/code/sectr/engine/client_api.odin @@ -69,7 +69,7 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem // Setup Persistent Slabs & String Cache { // alignment := uint(mem.DEFAULT_ALIGNMENT) - alignment := uint(64) // Doing the cache line + alignment := uint(16) policy_ptr := & default_slab_policy push( policy_ptr, SlabSizeClass { 128 * Kilobyte, 1 * Kilobyte, alignment }) @@ -138,11 +138,11 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem refresh_rate = 0 cam_min_zoom = 0.10 - cam_max_zoom = 30.0 + cam_max_zoom = 5.0 cam_zoom_mode = .Smooth cam_zoom_smooth_snappiness = 4.0 - cam_zoom_sensitivity_digital = 0.2 - cam_zoom_sensitivity_smooth = 4.0 + cam_zoom_sensitivity_digital = 0.05 + cam_zoom_sensitivity_smooth = 2.0 engine_refresh_hz = 0 @@ -260,24 +260,24 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem // Basic Font Setup if true { - font_provider_startup() - path_rec_mono_semicasual_reg := strings.concatenate( { Path_Assets, "RecMonoSemicasual-Regular-1.084.ttf" }) - font_rec_mono_semicasual_reg = font_load( path_rec_mono_semicasual_reg, 16.0, "RecMonoSemiCasual_Regular" ) + font_provider_startup( & font_provider_ctx ) + // path_rec_mono_semicasual_reg := strings.concatenate( { Path_Assets, "RecMonoSemicasual-Regular-1.084.ttf" }) + // font_rec_mono_semicasual_reg = font_load( path_rec_mono_semicasual_reg, 16.0, "RecMonoSemiCasual_Regular" ) - path_squidgy_slimes := strings.concatenate( { Path_Assets, "Squidgy Slimes.ttf" } ) - font_squidgy_slimes = font_load( path_squidgy_slimes, 32.0, "Squidgy_Slime" ) + // path_squidgy_slimes := strings.concatenate( { Path_Assets, "Squidgy Slimes.ttf" } ) + // font_squidgy_slimes = font_load( path_squidgy_slimes, 32.0, "Squidgy_Slime" ) path_firacode := strings.concatenate( { Path_Assets, "FiraCode-Regular.ttf" } ) font_firacode = font_load( path_firacode, 16.0, "FiraCode" ) - path_open_sans := strings.concatenate( { Path_Assets, "OpenSans-Regular.ttf" } ) - font_open_sans = font_load( path_open_sans, 16.0, "OpenSans" ) + // path_open_sans := strings.concatenate( { Path_Assets, "OpenSans-Regular.ttf" } ) + // font_open_sans = font_load( path_open_sans, 16.0, "OpenSans" ) - path_noto_sans := strings.concatenate( { Path_Assets, "NotoSans-Regular.ttf" } ) - font_noto_sans = font_load( path_noto_sans, 16.0, "NotoSans" ) + // path_noto_sans := strings.concatenate( { Path_Assets, "NotoSans-Regular.ttf" } ) + // font_noto_sans = font_load( path_noto_sans, 16.0, "NotoSans" ) - path_arial_unicode_ms := strings.concatenate( { Path_Assets, "Arial Unicode MS.ttf" } ) - font_arial_unicode_ms = font_load( path_arial_unicode_ms, 16.0, "Arial_Unicode_MS" ) + // path_arial_unicode_ms := strings.concatenate( { Path_Assets, "Arial Unicode MS.ttf" } ) + // font_arial_unicode_ms = font_load( path_arial_unicode_ms, 16.0, "Arial_Unicode_MS" ) default_font = font_firacode log( "Default font loaded" ) @@ -328,8 +328,8 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem ui_startup( & workspace.ui, cache_allocator = persistent_slab_allocator() ) } - // 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/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()) alloc_error : AllocatorError; success : bool debug.lorem_content, success = os.read_entire_file( debug.path_lorem, persistent_slab_allocator() ) @@ -436,7 +436,7 @@ hot_reload :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_ staged_input_events.backing = persistent_slab_allocator() } - font_provider_reload() + font_provider_reload( & font_provider_ctx ) str_cache_reload( & string_cache, persistent_allocator(), persistent_allocator() ) str_cache_set_module_ctx( & string_cache ) diff --git a/code/sectr/engine/client_api_sokol_callbacks.odin b/code/sectr/engine/client_api_sokol_callbacks.odin index e9f2eba..b7bb485 100644 --- a/code/sectr/engine/client_api_sokol_callbacks.odin +++ b/code/sectr/engine/client_api_sokol_callbacks.odin @@ -34,8 +34,6 @@ sokol_app_frame_callback :: proc "c" () // log("sokol_app: Event-based frame callback triggered (detected a resize") // } - font_provider_reload() - // sokol_app is the only good reference for a frame-time at this point. sokol_delta_ms := sokol_app.frame_delta() sokol_delta_ns := transmute(Duration) sokol_delta_ms * MS_To_NS diff --git a/code/sectr/engine/render.odin b/code/sectr/engine/render.odin index 0b354bc..4fa08ae 100644 --- a/code/sectr/engine/render.odin +++ b/code/sectr/engine/render.odin @@ -40,33 +40,24 @@ render :: proc() } // Workspace and screen rendering passes { - render_mode_2d_workspace() - render_mode_screenspace() + render_mode_2d_workspace( screen_extent, project.workspace.cam, input^, & project.workspace.ui, & font_provider_ctx.ve_ctx, font_provider_ctx.render ) + render_mode_screenspace( app_window.extent, & screen_ui, & font_provider_ctx.ve_ctx, font_provider_ctx.render, config, & debug ) } gp.end() gfx.commit() - ve.flush_draw_list( & font_provider_data.ve_font_cache ) - font_provider_data.vbuf_layer_offset = 0 - font_provider_data.ibuf_layer_offset = 0 - font_provider_data.calls_layer_offset = 0 + ve.flush_draw_list( & font_provider_ctx.ve_ctx ) } // TODO(Ed): Eventually this needs to become a 'viewport within a UI' // This would allow the user to have more than one workspace open at the same time -render_mode_2d_workspace :: proc() +render_mode_2d_workspace :: proc( screen_extent : Vec2, cam : Camera, input : InputState, ui : ^UI_State, ve_ctx : ^ve.Context, ve_render : VE_RenderData ) { profile(#procedure) - state := get_state(); using state // TODO(Ed): Prefer passing static context to through the callstack - cam := project.workspace.cam - - screen_extent := app_window.extent - screen_size := app_window.extent * 2 - screen_ratio := screen_size.x * ( 1.0 / screen_size.y ) - cam_zoom_ratio := 1.0 / cam.zoom + screen_size := screen_extent * 2 // TODO(Ed): Eventually will be the viewport extents - ve.configure_snap( & font_provider_data.ve_font_cache, u32(state.app_window.extent.x * 2.0), u32(state.app_window.extent.y * 2.0) ) + ve.configure_snap( ve_ctx, u32(screen_size.x), u32(screen_size.y) ) Render_Debug: { @@ -111,36 +102,26 @@ render_mode_2d_workspace :: proc() render_set_view_space(screen_extent) render_set_camera(cam) - ui := & project.workspace.ui - ui_context = & project.workspace.ui - + cam := cam when UI_Render_Method == .Layers { render_list := array_to_slice( ui.render_list ) render_ui_via_box_list( render_list, & cam ) } when UI_Render_Method == .Depth_First { - render_ui_via_box_tree( ui.root, & cam ) + render_ui_via_box_tree( ui.root, screen_extent, ve_ctx, ve_render, & cam ) } - - ui_context = nil } -render_mode_screenspace :: proc() +render_mode_screenspace :: proc( screen_extent : Extents2, screen_ui : ^UI_State, ve_ctx : ^ve.Context, ve_render : VE_RenderData, config : AppConfig, debug : ^DebugData ) { profile(#procedure) - state := get_state(); using state // TODO(Ed): Prefer passing static context to through the callstack - replay := & Memory_App.replay - cam := & project.workspace.cam - win_extent := state.app_window.extent - - screen_extent := app_window.extent - screen_size := app_window.extent * 2 + screen_size := screen_extent * 2 screen_ratio := screen_size.x * ( 1.0 / screen_size.y ) - ve.configure_snap( & font_provider_data.ve_font_cache, u32(state.app_window.extent.x * 2.0), u32(state.app_window.extent.y * 2.0) ) + ve.configure_snap( ve_ctx, u32(screen_size.x), u32(screen_size.y) ) - render_screen_ui() + render_screen_ui( screen_extent, screen_ui, ve_ctx, ve_render ) Render_Reference_Dots: { @@ -152,7 +133,7 @@ render_mode_screenspace :: proc() Mouse_Position: { - mouse_pos := input.mouse.pos + mouse_pos := get_state().input.mouse.pos render_set_color( Color_White_A125 ) draw_filled_circle( mouse_pos.x, mouse_pos.y, 4, 24 ) } @@ -163,6 +144,10 @@ render_mode_screenspace :: proc() debug.debug_text_vis = true if debug.debug_text_vis { + state := get_state(); using state // TODO(Ed): Prefer passing static context to through the callstack + replay := & Memory_App.replay + cam := & project.workspace.cam + debug_draw_text :: proc( content : string, pos : Vec2, size : f32, color := Color_White, font : FontID = Font_Default ) { state := get_state(); using state @@ -271,7 +256,7 @@ render_mode_screenspace :: proc() } if true { - state.config.font_size_canvas_scalar = 1.0 + // state.config.font_size_canvas_scalar = 1 zoom_adjust_size := 16 * state.project.workspace.cam.zoom over_sample := zoom_adjust_size < 12 ? 1.0 : f32(state.config.font_size_canvas_scalar) debug_text("font_size_canvas_scalar: %v", config.font_size_canvas_scalar) @@ -279,64 +264,39 @@ render_mode_screenspace :: proc() debug_text("font_size resolved: %v px", resolved_size) } - render_text_layer() + render_text_layer( screen_extent, ve_ctx, ve_render ) } debug.draw_debug_text_y = 14 } -render_screen_ui :: proc() +render_screen_ui :: proc( screen_extent : Extents2, ui : ^UI_State, ve_ctx : ^ve.Context, ve_render : VE_RenderData ) { profile(#procedure) - state := get_state(); using state // TODO(Ed): Prefer passing static context to through the callstack - - screen_extent := app_window.extent - screen_size := app_window.extent * 2 - screen_ratio := screen_size.x * ( 1.0 / screen_size.y ) render_set_view_space(screen_extent) - ui := & screen_ui - state.ui_context = & screen_ui - - text_enqueued : b32 = false - shape_enqueued : b32 = false - when UI_Render_Method == .Layers { render_list := array_to_slice( ui.render_list ) render_ui_via_box_list( render_list ) } when UI_Render_Method == .Depth_First { - render_ui_via_box_tree( ui.root ) + render_ui_via_box_tree( ui.root, screen_extent, ve_ctx, ve_render ) } - - state.ui_context = nil } -render_text_layer :: proc() +render_text_layer :: proc( screen_extent : Vec2, ve_ctx : ^ve.Context, render : VE_RenderData ) { profile("VEFontCache: render text layer") + using render Bindings :: gfx.Bindings Range :: gfx.Range ShaderStage :: gfx.Shader_Stage - state := get_state(); using state - font_provider := & state.font_provider_data - using font_provider - // TODO(Ed): All this functionality for being able to segregate rendering of the drawlist incrementally should be lifted to the library itself (VEFontCache) - ve.optimize_draw_list( & ve_font_cache.draw_list, calls_layer_offset ) - draw_list := ve.get_draw_list( & ve_font_cache ) - - draw_list_vert_slice := array_to_slice(draw_list.vertices) - draw_list_index_slice := array_to_slice(draw_list.indices) - draw_list_calls_slice := array_to_slice(draw_list.calls) - - vbuf_layer_slice := draw_list_vert_slice [ vbuf_layer_offset : ] - ibuf_layer_slice := draw_list_index_slice[ ibuf_layer_offset : ] - calls_layer_slice := draw_list_calls_slice[ calls_layer_offset : ] + vbuf_layer_slice, ibuf_layer_slice, calls_layer_slice := ve.get_draw_list_layer( ve_ctx ) vbuf_ve_range := Range{ raw_data(vbuf_layer_slice), cast(u64) len(vbuf_layer_slice) * size_of(ve.Vertex) } ibuf_ve_range := Range{ raw_data(ibuf_layer_slice), cast(u64) len(ibuf_layer_slice) * size_of(u32) } @@ -344,9 +304,7 @@ render_text_layer :: proc() gfx.append_buffer( draw_list_vbuf, vbuf_ve_range ) gfx.append_buffer( draw_list_ibuf, ibuf_ve_range ) - vbuf_layer_offset = cast(u64) len(draw_list_vert_slice) - ibuf_layer_offset = cast(u64) len(draw_list_index_slice) - calls_layer_offset = cast(u64) len(draw_list_calls_slice) + ve.flush_draw_list_layer( ve_ctx ) for & draw_call in calls_layer_slice { @@ -365,8 +323,8 @@ render_text_layer :: proc() continue } - width := ve_font_cache.atlas.buffer_width - height := ve_font_cache.atlas.buffer_height + width := ve_ctx.atlas.buffer_width + height := ve_ctx.atlas.buffer_height pass := glyph_pass if draw_call.clear_before_draw { @@ -401,8 +359,8 @@ render_text_layer :: proc() continue } - width := ve_font_cache.atlas.width - height := ve_font_cache.atlas.height + width := ve_ctx.atlas.width + height := ve_ctx.atlas.height pass := atlas_pass if draw_call.clear_before_draw { @@ -443,13 +401,13 @@ render_text_layer :: proc() } profile("VEFontCache: draw call: target") - width := u32(app_window.extent.x * 2) - height := u32(app_window.extent.y * 2) pass := screen_pass pass.swapchain = sokol_glue.swapchain() gfx.begin_pass( pass ) + // width := u32(screen_extent.x * 2) + // height := u32(screen_extent.y * 2) // sokol_gfx.apply_viewport( 0, 0, width, height, origin_top_left = true ) // sokol_gfx.apply_scissor_rect( 0, 0, width, height, origin_top_left = true ) @@ -494,7 +452,7 @@ render_text_layer :: proc() } } -render_ui_via_box_tree :: proc( root : ^UI_Box, cam : ^Camera = nil ) +render_ui_via_box_tree :: proc( root : ^UI_Box, screen_extent : Vec2, ve_ctx : ^ve.Context, ve_render : VE_RenderData, cam : ^Camera = nil ) { debug := get_state().debug default_font := get_state().default_font @@ -510,7 +468,7 @@ render_ui_via_box_tree :: proc( root : ^UI_Box, cam : ^Camera = nil ) { if box.ancestors != previous_layer { if shape_enqueued do render_flush_gp() - if text_enqueued do render_text_layer() + if text_enqueued do render_text_layer( screen_extent, ve_ctx, ve_render ) shape_enqueued = false text_enqueued = false } @@ -577,10 +535,10 @@ render_ui_via_box_tree :: proc( root : ^UI_Box, cam : ^Camera = nil ) } if shape_enqueued do render_flush_gp() - if text_enqueued do render_text_layer() + if text_enqueued do render_text_layer( screen_extent, ve_ctx, ve_render ) } -render_ui_via_box_list :: proc( render_list : []UI_RenderBoxInfo, cam : ^Camera = nil ) +render_ui_via_box_list :: proc( render_list : []UI_RenderBoxInfo, screen_extent : Vec2, ve_ctx : ^ve.Context, ve_render : VE_RenderData, cam : ^Camera = nil ) { debug := get_state().debug default_font := get_state().default_font @@ -595,7 +553,7 @@ render_ui_via_box_list :: proc( render_list : []UI_RenderBoxInfo, cam : ^Camera { profile("render ui layer") render_flush_gp() - if text_enqueued do render_text_layer() + if text_enqueued do render_text_layer( screen_extent, ve_ctx, ve_render ) continue } using entry @@ -640,7 +598,7 @@ render_ui_via_box_list :: proc( render_list : []UI_RenderBoxInfo, cam : ^Camera } if shape_enqueued do render_flush_gp() - if text_enqueued do render_text_layer() + if text_enqueued do render_text_layer( screen_extent, ve_ctx, ve_render ) } #region("Helpers") @@ -705,8 +663,8 @@ draw_text_string_pos_norm :: proc( content : string, id : FontID, size : f32, po ve_id, resolved_size := font_provider_resolve_draw_id( id, size ) color_norm := normalize_rgba8(color) - ve.set_colour( & font_provider_data.ve_font_cache, color_norm ) - ve.draw_text( & font_provider_data.ve_font_cache, ve_id, content, pos, Vec2{1 / width, 1 / height} * scale ) + ve.set_colour( & font_provider_ctx.ve_ctx, color_norm ) + ve.draw_text( & font_provider_ctx.ve_ctx, ve_id, content, pos, Vec2{1 / width, 1 / height} * scale ) return } @@ -742,7 +700,7 @@ draw_text_string_pos_extent_zoomed :: proc( content : string, id : FontID, size zoom_adjust_size := size * cam.zoom // Over-sample font-size for any render under a camera - over_sample : f32 = zoom_adjust_size < 12 ? 1.0 : f32(state.config.font_size_canvas_scalar) + over_sample : f32 = zoom_adjust_size <= 8 ? 1.0 : f32(state.config.font_size_canvas_scalar) zoom_adjust_size *= over_sample ve_id, resolved_size := font_provider_resolve_draw_id( id, zoom_adjust_size ) @@ -761,8 +719,8 @@ draw_text_string_pos_extent_zoomed :: proc( content : string, id : FontID, size text_scale /= over_sample color_norm := normalize_rgba8(color) - ve.set_colour( & font_provider_data.ve_font_cache, color_norm ) - ve.draw_text( & font_provider_data.ve_font_cache, ve_id, content, normalized_pos, text_scale ) + ve.set_colour( & font_provider_ctx.ve_ctx, color_norm ) + ve.draw_text( & font_provider_ctx.ve_ctx, ve_id, content, normalized_pos, text_scale ) } // TODO(Ed): Eventually the workspace will need a viewport for drawing text diff --git a/code/sectr/engine/update.odin b/code/sectr/engine/update.odin index 64be990..fd93f43 100644 --- a/code/sectr/engine/update.odin +++ b/code/sectr/engine/update.odin @@ -43,10 +43,6 @@ poll_debug_actions :: proc( actions : ^ DebugActions, input : ^ InputState ) load_project = keyboard.left_control.ended_down && pressed( keyboard.O ) save_project = keyboard.left_control.ended_down && pressed( keyboard.S ) - base_replay_bind := keyboard.right_alt.ended_down && pressed( keyboard.L) - record_replay = base_replay_bind && keyboard.right_shift.ended_down - play_replay = base_replay_bind && ! keyboard.right_shift.ended_down - show_debug_text = keyboard.right_alt.ended_down && pressed(keyboard.T) show_mouse_pos = keyboard.right_alt.ended_down && pressed(keyboard.M) @@ -164,11 +160,11 @@ update :: proc( delta_time : f64 ) -> b32 workspace.zoom_target = cam.zoom } - config.cam_max_zoom = 10 - config.cam_min_zoom = 0.05 - config.cam_zoom_sensitivity_digital = 0.05 - config.cam_zoom_sensitivity_smooth = 2.0 - config.cam_zoom_mode = .Smooth + // config.cam_max_zoom = 10 + // config.cam_min_zoom = 0.05 + // config.cam_zoom_sensitivity_digital = 0.05 + // config.cam_zoom_sensitivity_smooth = 2.0 + // config.cam_zoom_mode = .Smooth switch config.cam_zoom_mode { case .Smooth: diff --git a/code/sectr/font/provider.odin b/code/sectr/font/provider.odin index 30353b2..ec417cb 100644 --- a/code/sectr/font/provider.odin +++ b/code/sectr/font/provider.odin @@ -4,11 +4,9 @@ import "core:math" import "core:os" import ve "codebase:font/VEFontCache" import sokol_gfx "thirdparty:sokol/gfx" -import sokol_glue "thirdparty:sokol/glue" - Font_Provider_Use_Freetype :: false -Font_Largest_Px_Size :: 172 +Font_Largest_Px_Size :: 154 Font_Size_Interval :: 2 Font_Default :: FontID { 0, "" } @@ -26,503 +24,41 @@ FontDef :: struct { path_file : string, default_size : i32, size_table : [Font_Largest_Px_Size / Font_Size_Interval] ve.FontID, - // ve_id : ve.FontID, } -FontProviderData :: struct +FontProviderContext :: struct { - ve_font_cache : ve.Context, - font_cache : HMapChained(FontDef), + ve_ctx : ve.Context, + font_cache : HMapChained(FontDef), - draw_list_vbuf : sokol_gfx.Buffer, - draw_list_ibuf : sokol_gfx.Buffer, - - vbuf_layer_offset : u64, - ibuf_layer_offset : u64, - calls_layer_offset : u64, - - glyph_shader : sokol_gfx.Shader, - atlas_shader : sokol_gfx.Shader, - screen_shader : sokol_gfx.Shader, - - // 2k x 512, R8 - glyph_rt_color : sokol_gfx.Image, - glyph_rt_depth : sokol_gfx.Image, - // glyph_rt_resolve : sokol_gfx.Image, - glyph_rt_sampler : sokol_gfx.Sampler, - - // 4k x 2k, R8 - atlas_rt_color : sokol_gfx.Image, - atlas_rt_depth : sokol_gfx.Image, - // atlas_rt_resolve : sokol_gfx.Image, - atlas_rt_sampler : sokol_gfx.Sampler, - - glyph_pipeline : sokol_gfx.Pipeline, - atlas_pipeline : sokol_gfx.Pipeline, - screen_pipeline : sokol_gfx.Pipeline, - - glyph_pass : sokol_gfx.Pass, - atlas_pass : sokol_gfx.Pass, - screen_pass : sokol_gfx.Pass, + using render : VE_RenderData, } -font_provider_startup :: proc() +font_provider_startup :: proc( ctx : ^FontProviderContext ) { profile(#procedure) - state := get_state() - - provider_data := & state.font_provider_data; using provider_data + using ctx error : AllocatorError font_cache, error = make( HMapChained(FontDef), hmap_closest_prime(1 * Kilo), persistent_allocator(), dbg_name = "font_cache" ) verify( error == AllocatorError.None, "Failed to allocate font_cache" ) - ve.init( & provider_data.ve_font_cache, .STB_TrueType, allocator = persistent_slab_allocator() ) + ve.startup( & ve_ctx, .STB_TrueType, allocator = persistent_slab_allocator() ) log("VEFontCached initialized") - - ve.configure_snap( & provider_data.ve_font_cache, u32(state.app_window.extent.x * 2.0), u32(state.app_window.extent.y * 2.0) ) - - // provider_data.ve_font_cache.debug_print = true - // provider_data.ve_font_cache.debug_print_verbose = true - - // TODO(Ed): Setup sokol hookup for VEFontCache - { - AttachmentDesc :: sokol_gfx.Attachment_Desc - 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 - ImageDesc :: sokol_gfx.Image_Desc - PassAction :: sokol_gfx.Pass_Action - Range :: sokol_gfx.Range - ResourceState :: sokol_gfx.Resource_State - 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 provider_data - backend := sokol_gfx.query_backend() - app_env := sokol_glue.environment() - - glyph_shader = sokol_gfx.make_shader(ve_render_glyph_shader_desc(backend) ) - atlas_shader = sokol_gfx.make_shader(ve_blit_atlas_shader_desc(backend) ) - screen_shader = sokol_gfx.make_shader(ve_draw_text_shader_desc(backend) ) - - draw_list_vbuf = sokol_gfx.make_buffer( BufferDesciption { - size = size_of([4]f32) * Kilo * 1024, - usage = BufferUsage.STREAM, - type = BufferType.VERTEXBUFFER, - }) - verify( sokol_gfx.query_buffer_state( draw_list_vbuf) < ResourceState.FAILED, "Failed to make draw_list_vbuf" ) - - draw_list_ibuf = sokol_gfx.make_buffer( BufferDesciption { - size = size_of(u32) * Kilo * 512, - usage = BufferUsage.STREAM, - type = BufferType.INDEXBUFFER, - }) - verify( sokol_gfx.query_buffer_state( draw_list_ibuf) < ResourceState.FAILED, "Failed to make draw_list_iubuf" ) - - Image_Filter := Filter.LINEAR - - // glyph_pipeline - { - vs_layout : VertexLayoutState - { - using vs_layout - attrs[ATTR_ve_render_glyph_vs_v_position] = VertexAttributeState { - format = VertexFormat.FLOAT2, - offset = 0, - buffer_index = 0, - } - attrs[ATTR_ve_render_glyph_vs_v_texture] = VertexAttributeState { - format = VertexFormat.FLOAT2, - offset = size_of(Vec2), - buffer_index = 0, - } - buffers[0] = VertexBufferLayoutState { - stride = size_of([4]f32), - step_func = VertexStep.PER_VERTEX - } - } - - color_target := ColorTargetState { - pixel_format = .R8, - write_mask = .RGBA, - blend = BlendState { - enabled = true, - src_factor_rgb = .ONE_MINUS_DST_COLOR, - dst_factor_rgb = .ONE_MINUS_SRC_COLOR, - op_rgb = BlendOp.ADD, - src_factor_alpha = .ONE_MINUS_DST_ALPHA, - dst_factor_alpha = .ONE_MINUS_SRC_ALPHA, - op_alpha = BlendOp.ADD, - }, - } - - glyph_pipeline = sokol_gfx.make_pipeline({ - shader = glyph_shader, - layout = vs_layout, - index_type = VertexIndexType.UINT32, - colors = { - 0 = color_target, - }, - color_count = 1, - depth = { - pixel_format = .DEPTH, - compare = .ALWAYS, - write_enabled = false, - }, - cull_mode = .NONE, - sample_count = 1, - // label = - }) - verify( sokol_gfx.query_pipeline_state(glyph_pipeline) < ResourceState.FAILED, "Failed to make glyph_pipeline" ) - } - - // glyph_pass - { - glyph_rt_color = sokol_gfx.make_image( ImageDesc { - type = ._2D, - render_target = true, - width = i32(ve_font_cache.atlas.buffer_width), - height = i32(ve_font_cache.atlas.buffer_height), - num_slices = 1, - num_mipmaps = 1, - usage = .IMMUTABLE, - pixel_format = .R8, - sample_count = 1, - // TODO(Ed): Setup labels for debug tracing/logging - // label = - }) - verify( sokol_gfx.query_image_state(glyph_rt_color) < ResourceState.FAILED, "Failed to make glyph_pipeline" ) - - glyph_rt_depth = sokol_gfx.make_image( ImageDesc { - type = ._2D, - render_target = true, - width = i32(ve_font_cache.atlas.buffer_width), - height = i32(ve_font_cache.atlas.buffer_height), - num_slices = 1, - num_mipmaps = 1, - usage = .IMMUTABLE, - pixel_format = .DEPTH, - sample_count = 1, - }) - - glyph_rt_sampler = sokol_gfx.make_sampler( SamplerDescription { - min_filter = Image_Filter, - mag_filter = Image_Filter, - mipmap_filter = Filter.NONE, - wrap_u = .CLAMP_TO_EDGE, - wrap_v = .CLAMP_TO_EDGE, - min_lod = -1000.0, - max_lod = 1000.0, - border_color = BorderColor.OPAQUE_BLACK, - compare = .NEVER, - max_anisotropy = 1, - }) - verify( sokol_gfx.query_sampler_state( glyph_rt_sampler) < ResourceState.FAILED, "Failed to make atlas_rt_sampler" ) - - color_attach := AttachmentDesc { - image = glyph_rt_color, - } - - glyph_attachments := sokol_gfx.make_attachments({ - colors = { - 0 = color_attach, - }, - depth_stencil = { - image = glyph_rt_depth, - }, - }) - verify( sokol_gfx.query_attachments_state(glyph_attachments) < ResourceState.FAILED, "Failed to make glyph_attachments" ) - - glyph_action := PassAction { - colors = { - 0 = { - load_action = .LOAD, - store_action = .STORE, - clear_value = {0.00, 0.00, 0.00, 1.00}, - } - }, - depth = { - load_action = .DONTCARE, - store_action = .DONTCARE, - clear_value = 0.0, - }, - stencil = { - load_action = .DONTCARE, - store_action = .DONTCARE, - clear_value = 0, - } - } - - glyph_pass = sokol_gfx.Pass { - action = glyph_action, - attachments = glyph_attachments, - // label = - } - } - - // atlas_pipeline - { - vs_layout : VertexLayoutState - { - using vs_layout - attrs[ATTR_ve_blit_atlas_vs_v_position] = VertexAttributeState { - format = VertexFormat.FLOAT2, - offset = 0, - buffer_index = 0, - } - attrs[ATTR_ve_blit_atlas_vs_v_texture] = VertexAttributeState { - format = VertexFormat.FLOAT2, - offset = size_of(Vec2), - buffer_index = 0, - } - buffers[0] = VertexBufferLayoutState { - stride = size_of([4]f32), - step_func = VertexStep.PER_VERTEX - } - } - - color_target := ColorTargetState { - pixel_format = .R8, - write_mask = .RGBA, - blend = BlendState { - enabled = true, - src_factor_rgb = .SRC_ALPHA, - dst_factor_rgb = .ONE_MINUS_SRC_ALPHA, - op_rgb = BlendOp.ADD, - src_factor_alpha = .SRC_ALPHA, - dst_factor_alpha = .ONE_MINUS_SRC_ALPHA, - op_alpha = BlendOp.ADD, - }, - } - - atlas_pipeline = sokol_gfx.make_pipeline({ - shader = atlas_shader, - layout = vs_layout, - index_type = VertexIndexType.UINT32, - colors = { - 0 = color_target, - }, - color_count = 1, - depth = { - pixel_format = .DEPTH, - compare = .ALWAYS, - write_enabled = false, - }, - cull_mode = .NONE, - sample_count = 1, - }) - } - - // atlas_pass - { - atlas_rt_color = sokol_gfx.make_image( ImageDesc { - type = ._2D, - render_target = true, - width = i32(ve_font_cache.atlas.width), - height = i32(ve_font_cache.atlas.height), - num_slices = 1, - num_mipmaps = 1, - usage = .IMMUTABLE, - pixel_format = .R8, - sample_count = 1, - // TODO(Ed): Setup labels for debug tracing/logging - // label = - }) - verify( sokol_gfx.query_image_state(atlas_rt_color) < ResourceState.FAILED, "Failed to make atlas_rt_color") - - atlas_rt_depth = sokol_gfx.make_image( ImageDesc { - type = ._2D, - render_target = true, - width = i32(ve_font_cache.atlas.width), - height = i32(ve_font_cache.atlas.height), - num_slices = 1, - num_mipmaps = 1, - usage = .IMMUTABLE, - pixel_format = .DEPTH, - sample_count = 1, - }) - verify( sokol_gfx.query_image_state(atlas_rt_depth) < ResourceState.FAILED, "Failed to make atlas_rt_depth") - - atlas_rt_sampler = sokol_gfx.make_sampler( SamplerDescription { - min_filter = Image_Filter, - mag_filter = Image_Filter, - mipmap_filter = Filter.NONE, - wrap_u = .CLAMP_TO_EDGE, - wrap_v = .CLAMP_TO_EDGE, - min_lod = -1000.0, - max_lod = 1000.0, - border_color = BorderColor.OPAQUE_BLACK, - compare = .NEVER, - max_anisotropy = 1, - }) - verify( sokol_gfx.query_sampler_state( atlas_rt_sampler) < ResourceState.FAILED, "Failed to make atlas_rt_sampler" ) - - color_attach := AttachmentDesc { - image = atlas_rt_color, - // mip_level = 1, - } - - atlas_attachments := sokol_gfx.make_attachments({ - colors = { - 0 = color_attach, - }, - depth_stencil = { - image = atlas_rt_depth, - }, - }) - verify( sokol_gfx.query_attachments_state(atlas_attachments) < ResourceState.FAILED, "Failed to make atlas_attachments") - - atlas_action := PassAction { - colors = { - 0 = { - load_action = .LOAD, - store_action = .STORE, - clear_value = {0.00, 0.00, 0.00, 1.0}, - } - }, - depth = { - load_action = .DONTCARE, - store_action = .DONTCARE, - clear_value = 0.0, - }, - stencil = { - load_action = .DONTCARE, - store_action = .DONTCARE, - clear_value = 0, - } - } - - atlas_pass = sokol_gfx.Pass { - action = atlas_action, - attachments = atlas_attachments, - // label = - } - } - - // screen pipeline - { - vs_layout : VertexLayoutState - { - using vs_layout - attrs[ATTR_ve_draw_text_vs_v_position] = VertexAttributeState { - format = VertexFormat.FLOAT2, - offset = 0, - buffer_index = 0, - } - attrs[ATTR_ve_draw_text_vs_v_texture] = VertexAttributeState { - format = VertexFormat.FLOAT2, - offset = size_of(Vec2), - buffer_index = 0, - } - buffers[0] = VertexBufferLayoutState { - stride = size_of([4]f32), - step_func = VertexStep.PER_VERTEX - } - } - - color_target := ColorTargetState { - pixel_format = app_env.defaults.color_format, - write_mask = .RGBA, - blend = BlendState { - enabled = true, - src_factor_rgb = .SRC_ALPHA, - dst_factor_rgb = .ONE_MINUS_SRC_ALPHA, - op_rgb = BlendOp.ADD, - src_factor_alpha = .SRC_ALPHA, - dst_factor_alpha = .ONE_MINUS_SRC_ALPHA, - op_alpha = BlendOp.ADD, - }, - } - - screen_pipeline = sokol_gfx.make_pipeline({ - shader = screen_shader, - layout = vs_layout, - index_type = VertexIndexType.UINT32, - colors = { - 0 = color_target, - }, - color_count = 1, - sample_count = 1, - depth = { - pixel_format = app_env.defaults.depth_format, - compare = .ALWAYS, - write_enabled = false, - }, - cull_mode = .NONE, - }) - verify( sokol_gfx.query_pipeline_state(screen_pipeline) < ResourceState.FAILED, "Failed to make screen_pipeline" ) - } - - // screen_pass - { - screen_action := PassAction { - colors = { - 0 = { - load_action = .LOAD, - store_action = .STORE, - clear_value = {0.00, 0.00, 0.00, 0.0}, - }, - 1 = { - load_action = .LOAD, - store_action = .STORE, - clear_value = {0.00, 0.00, 0.00, 0.0}, - }, - 2 = { - load_action = .LOAD, - store_action = .STORE, - clear_value = {0.00, 0.00, 0.00, 0.0}, - } - }, - depth = { - load_action = .DONTCARE, - store_action = .DONTCARE, - clear_value = 0.0, - }, - stencil = { - load_action = .DONTCARE, - store_action = .DONTCARE, - clear_value = 0, - } - } - - screen_pass = sokol_gfx.Pass { - action = screen_action, - // label = - } - } - } + // provider_data.ve_ctx.debug_print = true + // provider_data.ve_ctx.debug_print_verbose = true + font_provider_setup_sokol_gfx_objects( & render, ve_ctx ) } -font_provider_reload :: proc() +font_provider_reload :: proc( ctx : ^FontProviderContext ) { - state := get_state() - provider_data := & state.font_provider_data - - hmap_chained_reload( provider_data.font_cache, persistent_allocator()) - - // ve.configure_snap( & provider_data.ve_font_cache, u32(state.app_window.extent.x * 2.0), u32(state.app_window.extent.y * 2.0) ) - ve.hot_reload( & provider_data.ve_font_cache, persistent_slab_allocator() ) + hmap_chained_reload( ctx.font_cache, persistent_allocator()) + ve.hot_reload( & ctx.ve_ctx, persistent_slab_allocator() ) } -font_provider_shutdown :: proc() +font_provider_shutdown :: proc( ctx : ^FontProviderContext ) { - state := get_state() - provider_data := state.font_provider_data; using provider_data - - ve.shutdown( & provider_data.ve_font_cache ) + ve.shutdown( & ctx.ve_ctx ) } font_load :: proc(path_file : string, @@ -530,12 +66,12 @@ font_load :: proc(path_file : string, desired_id : string = Font_Load_Gen_ID ) -> FontID { + provider_data := & get_state().font_provider_ctx; using provider_data + msg := str_fmt_tmp("Loading font: %v", path_file) profile(msg) log(msg) - provider_data := & get_state().font_provider_data; using provider_data - font_data, read_succeded : = os.read_entire_file( path_file, persistent_allocator() ) verify( b32(read_succeded), str_fmt("Failed to read font file for: %v", path_file) ) font_data_size := cast(i32) len(font_data) @@ -549,7 +85,7 @@ font_load :: proc(path_file : string, desired_id = file_name_from_path(path_file) } - font_cache_watch := provider_data.font_cache + font_cache_watch := font_cache key := cast(u64) crc32( transmute([]byte) desired_id ) def, set_error := hmap_chained_set(font_cache, key, FontDef{}) @@ -568,7 +104,7 @@ font_load :: proc(path_file : string, // logf("Loading at size %v", font_size) id := (font_size / Font_Size_Interval) + (font_size % Font_Size_Interval) ve_id := & def.size_table[id - 1] - ve_ret_id := ve.load_font( & provider_data.ve_font_cache, desired_id, font_data, f32(font_size) ) + ve_ret_id := ve.load_font( & ve_ctx, desired_id, font_data, f32(font_size) ) (ve_id^) = ve_ret_id } @@ -580,9 +116,9 @@ Font_Use_Default_Size :: f32(0.0) font_provider_resolve_draw_id :: proc( id : FontID, size := Font_Use_Default_Size ) -> (ve_id :ve.FontID, resolved_size : i32) { - state := get_state(); using state + provider_data := get_state().font_provider_ctx; using provider_data - def := hmap_chained_get( font_provider_data.font_cache, id.key ) + def := hmap_chained_get( font_cache, id.key ) size := size == 0.0 ? f32(def.default_size) : size even_size := math.round(size * (1.0 / f32(Font_Size_Interval))) * f32(Font_Size_Interval) resolved_size = clamp( i32( even_size), 12, Font_Largest_Px_Size ) @@ -594,11 +130,7 @@ font_provider_resolve_draw_id :: proc( id : FontID, size := Font_Use_Default_Siz measure_text_size :: proc( text : string, font : FontID, font_size := Font_Use_Default_Size, spacing : f32 ) -> Vec2 { - state := get_state(); using state - - // profile(#procedure) ve_id, size := font_provider_resolve_draw_id( font, font_size ) - - measured := ve.measure_text_size( & font_provider_data.ve_font_cache, ve_id, text ) + measured := ve.measure_text_size( & get_state().font_provider_ctx.ve_ctx, ve_id, text ) return measured } diff --git a/code/sectr/font/render_sokol.odin b/code/sectr/font/render_sokol.odin new file mode 100644 index 0000000..50bf3b8 --- /dev/null +++ b/code/sectr/font/render_sokol.odin @@ -0,0 +1,454 @@ +package sectr + +import ve "codebase:font/VEFontCache" +import sokol_gfx "thirdparty:sokol/gfx" +import sokol_glue "thirdparty:sokol/glue" + +VE_RenderData :: struct { + draw_list_vbuf : sokol_gfx.Buffer, + draw_list_ibuf : sokol_gfx.Buffer, + + glyph_shader : sokol_gfx.Shader, + atlas_shader : sokol_gfx.Shader, + screen_shader : sokol_gfx.Shader, + + // 2k x 512, R8 + glyph_rt_color : sokol_gfx.Image, + glyph_rt_depth : sokol_gfx.Image, + // glyph_rt_resolve : sokol_gfx.Image, + glyph_rt_sampler : sokol_gfx.Sampler, + + // 4k x 2k, R8 + atlas_rt_color : sokol_gfx.Image, + atlas_rt_depth : sokol_gfx.Image, + // atlas_rt_resolve : sokol_gfx.Image, + atlas_rt_sampler : sokol_gfx.Sampler, + + glyph_pipeline : sokol_gfx.Pipeline, + atlas_pipeline : sokol_gfx.Pipeline, + screen_pipeline : sokol_gfx.Pipeline, + + glyph_pass : sokol_gfx.Pass, + atlas_pass : sokol_gfx.Pass, + screen_pass : sokol_gfx.Pass, +} + +font_provider_setup_sokol_gfx_objects :: proc( ctx : ^VE_RenderData, ve_ctx : ve.Context ) +{ + using ctx + AttachmentDesc :: sokol_gfx.Attachment_Desc + 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 + ImageDesc :: sokol_gfx.Image_Desc + PassAction :: sokol_gfx.Pass_Action + Range :: sokol_gfx.Range + ResourceState :: sokol_gfx.Resource_State + 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 + + backend := sokol_gfx.query_backend() + app_env := sokol_glue.environment() + + glyph_shader = sokol_gfx.make_shader(ve_render_glyph_shader_desc(backend) ) + atlas_shader = sokol_gfx.make_shader(ve_blit_atlas_shader_desc(backend) ) + screen_shader = sokol_gfx.make_shader(ve_draw_text_shader_desc(backend) ) + + draw_list_vbuf = sokol_gfx.make_buffer( BufferDesciption { + size = size_of([4]f32) * 2 * Mega, + usage = BufferUsage.STREAM, + type = BufferType.VERTEXBUFFER, + }) + verify( sokol_gfx.query_buffer_state( draw_list_vbuf) < ResourceState.FAILED, "Failed to make draw_list_vbuf" ) + + draw_list_ibuf = sokol_gfx.make_buffer( BufferDesciption { + size = size_of(u32) * 1 * Mega, + usage = BufferUsage.STREAM, + type = BufferType.INDEXBUFFER, + }) + verify( sokol_gfx.query_buffer_state( draw_list_ibuf) < ResourceState.FAILED, "Failed to make draw_list_iubuf" ) + + Image_Filter := Filter.LINEAR + + // glyph_pipeline + { + vs_layout : VertexLayoutState + { + using vs_layout + attrs[ATTR_ve_render_glyph_vs_v_position] = VertexAttributeState { + format = VertexFormat.FLOAT2, + offset = 0, + buffer_index = 0, + } + attrs[ATTR_ve_render_glyph_vs_v_texture] = VertexAttributeState { + format = VertexFormat.FLOAT2, + offset = size_of(Vec2), + buffer_index = 0, + } + buffers[0] = VertexBufferLayoutState { + stride = size_of([4]f32), + step_func = VertexStep.PER_VERTEX + } + } + + color_target := ColorTargetState { + pixel_format = .R8, + write_mask = .RGBA, + blend = BlendState { + enabled = true, + src_factor_rgb = .ONE_MINUS_DST_COLOR, + dst_factor_rgb = .ONE_MINUS_SRC_COLOR, + op_rgb = BlendOp.ADD, + src_factor_alpha = .ONE_MINUS_DST_ALPHA, + dst_factor_alpha = .ONE_MINUS_SRC_ALPHA, + op_alpha = BlendOp.ADD, + }, + } + + glyph_pipeline = sokol_gfx.make_pipeline({ + shader = glyph_shader, + layout = vs_layout, + index_type = VertexIndexType.UINT32, + colors = { + 0 = color_target, + }, + color_count = 1, + depth = { + pixel_format = .DEPTH, + compare = .ALWAYS, + write_enabled = false, + }, + cull_mode = .NONE, + sample_count = 1, + // label = + }) + verify( sokol_gfx.query_pipeline_state(glyph_pipeline) < ResourceState.FAILED, "Failed to make glyph_pipeline" ) + } + + // glyph_pass + { + glyph_rt_color = sokol_gfx.make_image( ImageDesc { + type = ._2D, + render_target = true, + width = i32(ve_ctx.atlas.buffer_width), + height = i32(ve_ctx.atlas.buffer_height), + num_slices = 1, + num_mipmaps = 1, + usage = .IMMUTABLE, + pixel_format = .R8, + sample_count = 1, + // TODO(Ed): Setup labels for debug tracing/logging + // label = + }) + verify( sokol_gfx.query_image_state(glyph_rt_color) < ResourceState.FAILED, "Failed to make glyph_pipeline" ) + + glyph_rt_depth = sokol_gfx.make_image( ImageDesc { + type = ._2D, + render_target = true, + width = i32(ve_ctx.atlas.buffer_width), + height = i32(ve_ctx.atlas.buffer_height), + num_slices = 1, + num_mipmaps = 1, + usage = .IMMUTABLE, + pixel_format = .DEPTH, + sample_count = 1, + }) + + glyph_rt_sampler = sokol_gfx.make_sampler( SamplerDescription { + min_filter = Image_Filter, + mag_filter = Image_Filter, + mipmap_filter = Filter.NONE, + wrap_u = .CLAMP_TO_EDGE, + wrap_v = .CLAMP_TO_EDGE, + min_lod = -1000.0, + max_lod = 1000.0, + border_color = BorderColor.OPAQUE_BLACK, + compare = .NEVER, + max_anisotropy = 1, + }) + verify( sokol_gfx.query_sampler_state( glyph_rt_sampler) < ResourceState.FAILED, "Failed to make atlas_rt_sampler" ) + + color_attach := AttachmentDesc { + image = glyph_rt_color, + } + + glyph_attachments := sokol_gfx.make_attachments({ + colors = { + 0 = color_attach, + }, + depth_stencil = { + image = glyph_rt_depth, + }, + }) + verify( sokol_gfx.query_attachments_state(glyph_attachments) < ResourceState.FAILED, "Failed to make glyph_attachments" ) + + glyph_action := PassAction { + colors = { + 0 = { + load_action = .LOAD, + store_action = .STORE, + clear_value = {0.00, 0.00, 0.00, 1.00}, + } + }, + depth = { + load_action = .DONTCARE, + store_action = .DONTCARE, + clear_value = 0.0, + }, + stencil = { + load_action = .DONTCARE, + store_action = .DONTCARE, + clear_value = 0, + } + } + + glyph_pass = sokol_gfx.Pass { + action = glyph_action, + attachments = glyph_attachments, + // label = + } + } + + // atlas_pipeline + { + vs_layout : VertexLayoutState + { + using vs_layout + attrs[ATTR_ve_blit_atlas_vs_v_position] = VertexAttributeState { + format = VertexFormat.FLOAT2, + offset = 0, + buffer_index = 0, + } + attrs[ATTR_ve_blit_atlas_vs_v_texture] = VertexAttributeState { + format = VertexFormat.FLOAT2, + offset = size_of(Vec2), + buffer_index = 0, + } + buffers[0] = VertexBufferLayoutState { + stride = size_of([4]f32), + step_func = VertexStep.PER_VERTEX + } + } + + color_target := ColorTargetState { + pixel_format = .R8, + write_mask = .RGBA, + blend = BlendState { + enabled = true, + src_factor_rgb = .SRC_ALPHA, + dst_factor_rgb = .ONE_MINUS_SRC_ALPHA, + op_rgb = BlendOp.ADD, + src_factor_alpha = .SRC_ALPHA, + dst_factor_alpha = .ONE_MINUS_SRC_ALPHA, + op_alpha = BlendOp.ADD, + }, + } + + atlas_pipeline = sokol_gfx.make_pipeline({ + shader = atlas_shader, + layout = vs_layout, + index_type = VertexIndexType.UINT32, + colors = { + 0 = color_target, + }, + color_count = 1, + depth = { + pixel_format = .DEPTH, + compare = .ALWAYS, + write_enabled = false, + }, + cull_mode = .NONE, + sample_count = 1, + }) + } + + // atlas_pass + { + atlas_rt_color = sokol_gfx.make_image( ImageDesc { + type = ._2D, + render_target = true, + width = i32(ve_ctx.atlas.width), + height = i32(ve_ctx.atlas.height), + num_slices = 1, + num_mipmaps = 1, + usage = .IMMUTABLE, + pixel_format = .R8, + sample_count = 1, + // TODO(Ed): Setup labels for debug tracing/logging + // label = + }) + verify( sokol_gfx.query_image_state(atlas_rt_color) < ResourceState.FAILED, "Failed to make atlas_rt_color") + + atlas_rt_depth = sokol_gfx.make_image( ImageDesc { + type = ._2D, + render_target = true, + width = i32(ve_ctx.atlas.width), + height = i32(ve_ctx.atlas.height), + num_slices = 1, + num_mipmaps = 1, + usage = .IMMUTABLE, + pixel_format = .DEPTH, + sample_count = 1, + }) + verify( sokol_gfx.query_image_state(atlas_rt_depth) < ResourceState.FAILED, "Failed to make atlas_rt_depth") + + atlas_rt_sampler = sokol_gfx.make_sampler( SamplerDescription { + min_filter = Image_Filter, + mag_filter = Image_Filter, + mipmap_filter = Filter.NONE, + wrap_u = .CLAMP_TO_EDGE, + wrap_v = .CLAMP_TO_EDGE, + min_lod = -1000.0, + max_lod = 1000.0, + border_color = BorderColor.OPAQUE_BLACK, + compare = .NEVER, + max_anisotropy = 1, + }) + verify( sokol_gfx.query_sampler_state( atlas_rt_sampler) < ResourceState.FAILED, "Failed to make atlas_rt_sampler" ) + + color_attach := AttachmentDesc { + image = atlas_rt_color, + // mip_level = 1, + } + + atlas_attachments := sokol_gfx.make_attachments({ + colors = { + 0 = color_attach, + }, + depth_stencil = { + image = atlas_rt_depth, + }, + }) + verify( sokol_gfx.query_attachments_state(atlas_attachments) < ResourceState.FAILED, "Failed to make atlas_attachments") + + atlas_action := PassAction { + colors = { + 0 = { + load_action = .LOAD, + store_action = .STORE, + clear_value = {0.00, 0.00, 0.00, 1.0}, + } + }, + depth = { + load_action = .DONTCARE, + store_action = .DONTCARE, + clear_value = 0.0, + }, + stencil = { + load_action = .DONTCARE, + store_action = .DONTCARE, + clear_value = 0, + } + } + + atlas_pass = sokol_gfx.Pass { + action = atlas_action, + attachments = atlas_attachments, + // label = + } + } + + // screen pipeline + { + vs_layout : VertexLayoutState + { + using vs_layout + attrs[ATTR_ve_draw_text_vs_v_position] = VertexAttributeState { + format = VertexFormat.FLOAT2, + offset = 0, + buffer_index = 0, + } + attrs[ATTR_ve_draw_text_vs_v_texture] = VertexAttributeState { + format = VertexFormat.FLOAT2, + offset = size_of(Vec2), + buffer_index = 0, + } + buffers[0] = VertexBufferLayoutState { + stride = size_of([4]f32), + step_func = VertexStep.PER_VERTEX + } + } + + color_target := ColorTargetState { + pixel_format = app_env.defaults.color_format, + write_mask = .RGBA, + blend = BlendState { + enabled = true, + src_factor_rgb = .SRC_ALPHA, + dst_factor_rgb = .ONE_MINUS_SRC_ALPHA, + op_rgb = BlendOp.ADD, + src_factor_alpha = .SRC_ALPHA, + dst_factor_alpha = .ONE_MINUS_SRC_ALPHA, + op_alpha = BlendOp.ADD, + }, + } + + screen_pipeline = sokol_gfx.make_pipeline({ + shader = screen_shader, + layout = vs_layout, + index_type = VertexIndexType.UINT32, + colors = { + 0 = color_target, + }, + color_count = 1, + sample_count = 1, + depth = { + pixel_format = app_env.defaults.depth_format, + compare = .ALWAYS, + write_enabled = false, + }, + cull_mode = .NONE, + }) + verify( sokol_gfx.query_pipeline_state(screen_pipeline) < ResourceState.FAILED, "Failed to make screen_pipeline" ) + } + + // screen_pass + { + screen_action := PassAction { + colors = { + 0 = { + load_action = .LOAD, + store_action = .STORE, + clear_value = {0.00, 0.00, 0.00, 0.0}, + }, + 1 = { + load_action = .LOAD, + store_action = .STORE, + clear_value = {0.00, 0.00, 0.00, 0.0}, + }, + 2 = { + load_action = .LOAD, + store_action = .STORE, + clear_value = {0.00, 0.00, 0.00, 0.0}, + } + }, + depth = { + load_action = .DONTCARE, + store_action = .DONTCARE, + clear_value = 0.0, + }, + stencil = { + load_action = .DONTCARE, + store_action = .DONTCARE, + clear_value = 0, + } + } + + screen_pass = sokol_gfx.Pass { + action = screen_action, + // label = + } + } +} diff --git a/code/sectr/grime/context.odin b/code/sectr/grime/context.odin index c804e7b..e340c94 100644 --- a/code/sectr/grime/context.odin +++ b/code/sectr/grime/context.odin @@ -24,4 +24,5 @@ context_push :: proc( value : ^($Type) ) { context_pop :: proc( value : ^($Type) ) { pop( & context_ext().stack ) + } diff --git a/code/sectr/ui/core/base.odin b/code/sectr/ui/core/base.odin index ff1f7e6..fc1fe56 100644 --- a/code/sectr/ui/core/base.odin +++ b/code/sectr/ui/core/base.odin @@ -515,4 +515,4 @@ ui_view_bounds :: #force_inline proc "contextless" () -> (range : Range2) { // } } -ui_context :: #force_inline proc() -> ^UI_State { return get_state().ui_context } +ui_context :: #force_inline proc "contextless" () -> ^UI_State { return get_state().ui_context } diff --git a/code/sectr/ui/core/box.odin b/code/sectr/ui/core/box.odin index d9b56ad..0b71117 100644 --- a/code/sectr/ui/core/box.odin +++ b/code/sectr/ui/core/box.odin @@ -151,9 +151,12 @@ ui_box_tranverse_next_depth_based :: #force_inline proc "contextless" ( box : ^ } // Traveral pritorizes traversing a "anestry layer" -ui_box_traverse_next_layer_based :: proc "contextless" ( box : ^UI_Box, bypass_intersection_test := false ) -> (^UI_Box) +ui_box_traverse_next_layer_based :: proc "contextless" ( box : ^UI_Box, bypass_intersection_test := false, ctx : ^UI_State = nil ) -> (^UI_Box) { - using state := get_state() + ctx := ctx + if ctx == nil { + ctx = ui_context() + } parent := box.parent if parent != nil