From 5d6f996d3ce0a007472b920e7b1e3ec2a032e26a Mon Sep 17 00:00:00 2001 From: Ed_ Date: Wed, 19 Jun 2024 18:09:11 -0400 Subject: [PATCH] Finished fixing input back to prev-sokol feature parity --- code/grime/queue.odin | 45 ++++++++------ code/sectr/colors.odin | 10 +-- code/sectr/engine/client_api.odin | 18 +++--- .../engine/client_api_sokol_callbacks.odin | 21 ++++++- code/sectr/engine/render.odin | 57 +++++++++--------- code/sectr/engine/update.odin | 9 ++- code/sectr/font/provider_VEFontCache.odin | 11 ++-- code/sectr/grime/mappings.odin | 4 ++ code/sectr/input/events.odin | 41 +++++++++---- code/sectr/input/input.odin | 33 ++++++---- docs/input sys design.pur | Bin 0 -> 79937 bytes 11 files changed, 155 insertions(+), 94 deletions(-) create mode 100644 docs/input sys design.pur diff --git a/code/grime/queue.odin b/code/grime/queue.odin index 6cd18eb..737dde3 100644 --- a/code/grime/queue.odin +++ b/code/grime/queue.odin @@ -19,24 +19,29 @@ make_queue :: proc( $QueueType : typeid/Queue($Type), capacity := queue.DEFAULT_ push_back_slice_queue :: proc( self : ^$QueueType / Queue($Type), slice : []Type ) -> ( error : AllocatorError ) { - num := cast(uint) len(slice) - - if uint( space_left( self^ )) < num { - error = queue._grow( self, self.len + num ) - if error != .None do return - } - - size := uint(len(self.data)) - insert_from := (self.offset + self.len) % size - insert_to := num - - if insert_from + insert_to > size { - insert_to = size - insert_from - } - - copy( self.data[ insert_from : ], slice[ : insert_to ]) - copy( self.data[ : insert_from ], slice[ insert_to : ]) + queue.push_back_elems( self, ..slice ) return + + // num := cast(uint) len(slice) + + // if uint( space_left( self^ )) < num { + // error = queue._grow( self, self.len + num ) + // if error != .None do return + // } + + // size := uint(len(self.data)) + // insert_from := (self.offset + self.len) % size + // insert_to := num + + // if insert_from + insert_to > size { + // insert_to = size - insert_from + // } + + // copy( self.data[ insert_from : ], slice[ : insert_to ]) + // copy( self.data[ : insert_from ], slice[ insert_to : ]) + + // self.len += num + // return } QueueIterator :: struct( $Type : typeid ) { @@ -60,8 +65,10 @@ iterator_queue :: proc( queue : $QueueType / Queue($Type) ) -> QueueIterator(Typ next_queue_iterator :: proc( iter : ^QueueIterator($Type) ) -> ^Type { using iter - front_id := (length + offset ) % len(data) - elem_id := (length + offset - index) % len(data) + data_size := cast(uint) len(data) + + front_id := (length + offset ) % data_size + elem_id := (length + offset - index -1 ) % data_size if elem_id == front_id do return nil elem := & data[ elem_id ] diff --git a/code/sectr/colors.odin b/code/sectr/colors.odin index 07a0907..a45953a 100644 --- a/code/sectr/colors.odin +++ b/code/sectr/colors.odin @@ -4,11 +4,13 @@ RGBA8 :: struct { r, g, b, a : u8 } RGBAN :: [4]f32 normalize_rgba8 :: #force_inline proc( color : RGBA8 ) -> RGBAN { + quotient : f32 = 1.0 / 255 + result := RGBAN { - 1.0 / f32(color.r), - 1.0 / f32(color.g), - 1.0 / f32(color.b), - 1.0 / f32(color.a), + f32(color.r) * quotient, + f32(color.g) * quotient, + f32(color.b) * quotient, + f32(color.a) * quotient, } return result } diff --git a/code/sectr/engine/client_api.odin b/code/sectr/engine/client_api.odin index c529df2..dd71511 100644 --- a/code/sectr/engine/client_api.odin +++ b/code/sectr/engine/client_api.odin @@ -112,13 +112,13 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem using input_events error : AllocatorError - events, error = make( Queue(InputEvent), 4 * Kilo, persistent_slab_allocator() ) + events, error = make( Queue(InputEvent), 4 * Kilo, persistent_allocator(), fixed_cap = true ) ensure(error == AllocatorError.None, "Failed to allocate input.events array") - key_events, error = make( Queue(InputKeyEvent), Kilo, persistent_slab_allocator() ) + key_events, error = make( Queue(InputKeyEvent), Kilo, persistent_allocator(), fixed_cap = true ) ensure(error == AllocatorError.None, "Failed to allocate key_events array") - mouse_events, error = make( Queue(InputMouseEvent), 2 * Kilo, persistent_slab_allocator() ) + mouse_events, error = make( Queue(InputMouseEvent), 2 * Kilo, persistent_allocator(), fixed_cap = true ) ensure(error == AllocatorError.None, "Failed to allocate mouse_events array") codes_pressed, error = make( Array(rune), Kilo, persistent_slab_allocator() ) @@ -132,8 +132,8 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem // TODO(Ed): Make this actually load from an ini { using config - resolution_width = 1600 - resolution_height = 900 + resolution_width = 1000 + resolution_height = 600 refresh_rate = 0 cam_min_zoom = 0.10 @@ -418,10 +418,10 @@ hot_reload :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_ // input_reload() { using input_events - reload( & events, persistent_slab_allocator()) - reload( & key_events, persistent_slab_allocator()) - reload( & mouse_events, persistent_slab_allocator()) - codes_pressed.backing = persistent_slab_allocator() + reload( & events, runtime.nil_allocator()) + reload( & key_events, runtime.nil_allocator()) + reload( & mouse_events, runtime.nil_allocator()) + codes_pressed.backing = persistent_slab_allocator() staged_input_events.backing = persistent_slab_allocator() } diff --git a/code/sectr/engine/client_api_sokol_callbacks.odin b/code/sectr/engine/client_api_sokol_callbacks.odin index 3334bb9..d522cb8 100644 --- a/code/sectr/engine/client_api_sokol_callbacks.odin +++ b/code/sectr/engine/client_api_sokol_callbacks.odin @@ -119,55 +119,74 @@ sokol_app_event_callback :: proc "c" (sokol_event : ^sokol_app.Event) logf("%v", sokol_event) case .KEY_DOWN: + if sokol_event.key_repeat do return + type = .Key_Pressed key = to_key_from_sokol( sokol_event.key_code ) modifiers = to_modifiers_code_from_sokol( sokol_event.modifiers ) sokol_app.consume_event() + append_staged_input_events( event ) + // logf("Key pressed(sokol): %v", key) + // logf("frame (sokol): %v", frame_id ) case .KEY_UP: + if sokol_event.key_repeat do return + type = .Key_Released key = to_key_from_sokol( sokol_event.key_code ) modifiers = to_modifiers_code_from_sokol( sokol_event.modifiers ) sokol_app.consume_event() + append_staged_input_events( event ) + // logf("Key released(sokol): %v", key) + // logf("frame (sokol): %v", frame_id ) case .CHAR: + if sokol_event.key_repeat do return + type = .Unicode codepoint = transmute(rune) sokol_event.char_code modifiers = to_modifiers_code_from_sokol( sokol_event.modifiers ) sokol_app.consume_event() + append_staged_input_events( event ) case .MOUSE_DOWN: type = .Mouse_Pressed mouse.btn = to_mouse_btn_from_sokol( sokol_event.mouse_button ) modifiers = to_modifiers_code_from_sokol( sokol_event.modifiers ) sokol_app.consume_event() + append_staged_input_events( event ) case .MOUSE_UP: type = .Mouse_Released mouse.btn = to_mouse_btn_from_sokol( sokol_event.mouse_button ) modifiers = to_modifiers_code_from_sokol( sokol_event.modifiers ) sokol_app.consume_event() + append_staged_input_events( event ) case .MOUSE_SCROLL: type = .Mouse_Scroll mouse.scroll = { sokol_event.scroll_x, sokol_event.scroll_y } modifiers = to_modifiers_code_from_sokol( sokol_event.modifiers ) sokol_app.consume_event() + append_staged_input_events( event ) case .MOUSE_MOVE: type = .Mouse_Move modifiers = to_modifiers_code_from_sokol( sokol_event.modifiers ) sokol_app.consume_event() + append_staged_input_events( event ) case .MOUSE_ENTER: type = .Mouse_Enter modifiers = to_modifiers_code_from_sokol( sokol_event.modifiers ) sokol_app.consume_event() + append_staged_input_events( event ) case .MOUSE_LEAVE: type = .Mouse_Leave modifiers = to_modifiers_code_from_sokol( sokol_event.modifiers ) sokol_app.consume_event() + append_staged_input_events( event ) // TODO(Ed): Add support case .TOUCHES_BEGAN: @@ -211,8 +230,6 @@ sokol_app_event_callback :: proc "c" (sokol_event : ^sokol_app.Event) monitor_refresh_hz := sokol_app.refresh_rate() sokol_app.consume_event() } - - append_staged_input_events( event ) } #endregion("Sokol App") diff --git a/code/sectr/engine/render.odin b/code/sectr/engine/render.odin index 7e20c28..7cc2d76 100644 --- a/code/sectr/engine/render.odin +++ b/code/sectr/engine/render.odin @@ -113,7 +113,7 @@ render_mode_screenspace :: proc() screen_corners := screen_get_corners() position := screen_corners.top_right - position.x -= app_window.extent.x + position.x -= app_window.extent.x * 0.5 position.y -= debug.draw_debug_text_y content := str_fmt_buffer( draw_text_scratch[:], format, ..args ) @@ -122,37 +122,36 @@ render_mode_screenspace :: proc() debug.draw_debug_text_y += 14 } - // "Draw text" using immediate mode api - { - font_provider := & state.font_provider_data - using font_provider - - @static index : i32 - text_test_str := str_fmt("frametime : %0.6f\nframetime(sokol): %0.2f\nframe id : %d\nsokol_frame: %d", frametime_delta_ms, sokol_app.frame_delta() * S_To_MS, frame, sokol_app.frame_count() ) - // log(text_test_str) - // text_test_str := str_fmt("HELLO VE FONT CACHE!") - // text_test_str := str_fmt("C") - - // font_provider := & state.font_provider_data - // fdef := hmap_chained_get( font_cache, default_font.key ) - - width := app_window.extent.x * 2 - height := app_window.extent.y * 2 - - 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.draw_text( & ve_font_cache, font_provider_resolve_draw_id(default_font), text_test_str, {0.0, 0.975}, Vec2{1 / width, 1 / height} ) - } - debug.debug_text_vis = true if debug.debug_text_vis { - fps_msg := str_fmt( "FPS: %f", fps_avg) - fps_msg_width := cast(f32) u32(measure_text_size( fps_msg, default_font, 12.0, 0.0 ).x) + 0.5 + fps_msg := str_fmt( "FPS: %0.2f", fps_avg) + fps_msg_width := measure_text_size( fps_msg, default_font, 12.0, 0.0 ).x fps_msg_pos := screen_get_corners().top_right - { fps_msg_width, 0 } - { 5, 5 } - debug_draw_text( fps_msg, fps_msg_pos, 12.0, color = Color_White ) - // debug_draw_text( fps_msg, {}, 12.0, color = Color_White ) + debug_draw_text( fps_msg, fps_msg_pos, 38.0, color = Color_Red ) + + // debug_text( "Screen Width : %v", rl.GetScreenWidth () ) + // debug_text( "Screen Height: %v", rl.GetScreenHeight() ) + // debug_text( "frametime_target_ms : %f ms", frametime_target_ms ) + debug_text( "frametime : %f ms", frametime_delta_ms ) + // debug_text( "frametime_last_elapsed_ms : %f ms", frametime_elapsed_ms ) + if replay.mode == ReplayMode.Record { + debug_text( "Recording Input") + } + if replay.mode == ReplayMode.Playback { + debug_text( "Replaying Input") + } + // debug_text("Zoom Target: %v", project.workspace.zoom_target) + + if debug.mouse_vis { + debug_text("Mouse scroll: %v", input.mouse.scroll ) + debug_text("Mouse Delta : %v", input.mouse.delta ) + debug_text("Mouse Position (Render) : %v", input.mouse.raw_pos ) + debug_text("Mouse Position (Screen) : %v", input.mouse.pos ) + debug_text("Mouse Position (Workspace View): %v", screen_to_ws_view_pos(input.mouse.pos) ) + // rl.DrawCircleV( input.mouse.raw_pos, 10, Color_White_A125 ) + // rl.DrawCircleV( screen_to_render_pos(input.mouse.pos), 2, Color_BG ) + } render_text_layer() } @@ -300,7 +299,7 @@ render_text_layer :: proc() fs_target_uniform := Ve_Draw_Text_Fs_Params { down_sample = 0, - colour = {1.0, 1.0, 1.0, 1}, + colour = draw_call.colour, } if draw_call.pass == .Target_Uncached { diff --git a/code/sectr/engine/update.odin b/code/sectr/engine/update.odin index 06f3fe6..0ad4248 100644 --- a/code/sectr/engine/update.odin +++ b/code/sectr/engine/update.odin @@ -78,12 +78,17 @@ update :: proc( delta_time : f64 ) -> b32 project.workspace.cam.view = transmute(Vec2) window.extent } - state.input, state.input_prev = swap( state.input, state.input_prev ) + // state.input, state.input_prev = swap( state.input, state.input_prev ) + { + temp := state.input_prev + state.input_prev = state.input + state.input = temp + } pull_staged_input_events( state.input, & state.input_events, state.staged_input_events ) poll_input_events( state.input, state.input_prev, state.input_events ) debug_actions : DebugActions = {} - // poll_debug_actions( & debug_actions, state.input ) + poll_debug_actions( & debug_actions, state.input ) // Saving & Loading { diff --git a/code/sectr/font/provider_VEFontCache.odin b/code/sectr/font/provider_VEFontCache.odin index 6405dd1..dbee9ea 100644 --- a/code/sectr/font/provider_VEFontCache.odin +++ b/code/sectr/font/provider_VEFontCache.odin @@ -552,6 +552,7 @@ font_load :: proc(path_file : string, for font_size : i32 = Font_Size_Interval; font_size <= Font_Largest_Px_Size; font_size += Font_Size_Interval { + 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_id^ = ve.load_font( & provider_data.ve_font_cache, desired_id, font_data, 14.0 ) @@ -567,12 +568,12 @@ font_provider_resolve_draw_id :: proc( id : FontID, size := Font_Use_Default_Siz { state := get_state(); using state - even_size := math.round(size * (1.0 / f32(Font_Size_Interval))) * f32(Font_Size_Interval) - size := clamp( i32( even_size), 4, Font_Largest_Px_Size ) - def := hmap_chained_get( font_provider_data.font_cache, id.key ) - size = size if size != i32(Font_Use_Default_Size) else def.default_size + def := hmap_chained_get( font_provider_data.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), 2, Font_Largest_Px_Size ) - id := (size / Font_Size_Interval) + (size % Font_Size_Interval) + id := (resolved_size / Font_Size_Interval) + (resolved_size % Font_Size_Interval) ve_id := def.size_table[ id - 1 ] width := app_window.extent.x * 2 diff --git a/code/sectr/grime/mappings.odin b/code/sectr/grime/mappings.odin index fe37289..8aa86d3 100644 --- a/code/sectr/grime/mappings.odin +++ b/code/sectr/grime/mappings.odin @@ -399,6 +399,10 @@ next :: proc { next_queue_iterator, } +peek_back :: proc { + queue.peek_back, +} + peek_front :: proc { queue.peek_front, } diff --git a/code/sectr/input/events.odin b/code/sectr/input/events.odin index 4a8fc87..6643a81 100644 --- a/code/sectr/input/events.odin +++ b/code/sectr/input/events.odin @@ -88,6 +88,9 @@ pull_staged_input_events :: proc( input : ^InputState, input_events : ^InputEve key = event.key, modifiers = event.modifiers }) + // logf("Key pressed(event pushed): %v", event.key) + // logf("last key event frame: %v", peek_back(& key_events).frame_id) + // logf("last event frame: %v", peek_back(& events).frame_id) case .Key_Released: push( & key_events, InputKeyEvent { @@ -96,6 +99,9 @@ pull_staged_input_events :: proc( input : ^InputState, input_events : ^InputEve key = event.key, modifiers = event.modifiers }) + // logf("Key released(event rpushed): %v", event.key) + // logf("last key event frame: %v", peek_back(& key_events).frame_id) + // logf("last event frame: %v", peek_back(& events).frame_id) case .Unicode: append( & codes_pressed, event.codepoint ) @@ -175,22 +181,39 @@ poll_input_events :: proc( input, prev_input : ^InputState, input_events : Input input.keyboard = {} input.mouse = {} + // logf("m's value is: %v (prev)", prev_input.keyboard.keys[KeyCode.M] ) + + for prev_key, id in prev_input.keyboard.keys { + input.keyboard.keys[id].ended_down = prev_key.ended_down + } + + for prev_btn, id in prev_input.mouse.btns { + input.mouse.btns[id].ended_down = prev_btn.ended_down + } + input_events := input_events using input_events - @static prev_frame : u64 = u64_max + @static prev_frame : u64 = 0 - last_frame := peek_front( & events).frame_id + last_frame : u64 = 0 + if events.len > 0 { + last_frame = peek_back( & events).frame_id + } // No new events, don't update - if prev_frame != 0 && last_frame == prev_frame do return + if last_frame == prev_frame do return Iterate_Key_Events: { iter_obj := iterator( key_events ); iter := & iter_obj for event := next( iter ); event != nil; event = next( iter ) { - if last_frame == event.frame_id do return + if last_frame > event.frame_id { + break + } + // logf("last_frame (iter): %v", last_frame) + // logf("frame (iter): %v", event.frame_id ) key := & input.keyboard.keys[event.key] prev_key := prev_input.keyboard.keys[event.key] @@ -206,9 +229,6 @@ poll_input_events :: proc( input, prev_input : ^InputState, input_events : Input key.half_transitions += 1 key.ended_down = false } - - frame_transition := first_transition && prev_key.ended_down != key.ended_down ? i32(1) : i32(0) - key.half_transitions += frame_transition } } @@ -217,7 +237,9 @@ poll_input_events :: proc( input, prev_input : ^InputState, input_events : Input iter_obj := iterator( mouse_events ); iter := & iter_obj for event := next( iter ); event != nil; event = next( iter ) { - if last_frame == event.frame_id do return + if last_frame > event.frame_id { + break + } process_digital_btn :: proc( btn : ^DigitalBtn, prev_btn : DigitalBtn, ended_down : b32 ) { @@ -225,9 +247,6 @@ poll_input_events :: proc( input, prev_input : ^InputState, input_events : Input btn.half_transitions += 1 btn.ended_down = ended_down - - frame_transition := first_transition && prev_btn.ended_down != btn.ended_down ? i32(1) : i32(0) - btn.half_transitions += frame_transition } #partial switch event.type { diff --git a/code/sectr/input/input.odin b/code/sectr/input/input.odin index 605e6eb..35058e1 100644 --- a/code/sectr/input/input.odin +++ b/code/sectr/input/input.odin @@ -39,26 +39,30 @@ MouseBtn :: enum u32 { KeyboardState :: struct #raw_union { keys : [KeyCode.count] DigitalBtn, using individual : struct { - - ignored : DigitalBtn, + null : DigitalBtn, // 0x00 + ignored : DigitalBtn, // 0x01 // GFLW / Sokol menu, world_1, world_2 : DigitalBtn, + // 0x02 - 0x04 __0x05_0x07_Unassigned__ : [ 3 * size_of( DigitalBtn)] u8, tab, backspace : DigitalBtn, + // 0x08 - 0x09 right, left, up, down : DigitalBtn, + // 0x0A - 0x0D - enter : DigitalBtn, + enter : DigitalBtn, // 0x0E __0x0F_Unassigned__ : [ 1 * size_of( DigitalBtn)] u8, caps_lock, scroll_lock, num_lock : DigitalBtn, + // 0x10 - 0x12 left_alt, left_shift, @@ -66,6 +70,7 @@ KeyboardState :: struct #raw_union { right_alt, right_shift, right_control : DigitalBtn, + // 0x13 - 0x18 print_screen, pause, @@ -75,6 +80,7 @@ KeyboardState :: struct #raw_union { page_up, page_down, space : DigitalBtn, + // 0x19 - 0x20 exlamation, quote_dbl, @@ -91,17 +97,18 @@ KeyboardState :: struct #raw_union { minus, period, slash : DigitalBtn, + // 0x21 - 0x2F - nrow_0, - nrow_1, - nrow_2, - nrow_3, - nrow_4, - nrow_5, - nrow_6, - nrow_7, - nrow_8, - nrow_9, + nrow_0, // 0x30 + nrow_1, // 0x31 + nrow_2, // 0x32 + nrow_3, // 0x33 + nrow_4, // 0x34 + nrow_5, // 0x35 + nrow_6, // 0x36 + nrow_7, // 0x37 + nrow_8, // 0x38 + nrow_9, // 0x39 __0x3A_Unassigned__ : [ 1 * size_of(DigitalBtn)] u8, diff --git a/docs/input sys design.pur b/docs/input sys design.pur new file mode 100644 index 0000000000000000000000000000000000000000..a5498b5fdd321d6b547f772428b1c7b27951912b GIT binary patch literal 79937 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 P_z3V3;3M!qjKKc`kQocm literal 0 HcmV?d00001