Base input pass updated for sokol possibly done (untested)

Still need to figure out input event consumption, I don't want to do it with the event ring.

I would like to setup input binding layers and then have the push/pop input contextes with a set of bindings.
If the bindings are detected it should "consume" that binding from further use for the buffered time period.

This will be really important with how heavily model this app will be.I
This commit is contained in:
Edward R. Gonzalez 2024-06-18 01:33:50 -04:00
parent 3b395f3356
commit b698f5166b
14 changed files with 487 additions and 151 deletions

View File

@ -0,0 +1,18 @@
package grime
import "base:runtime"
reload_array :: proc( self : [dynamic]$Type, allocator : Allocator ) {
raw := transmute(runtime.Raw_Dynamic_Array) self
raw.allocator = allocator
}
reload_queue :: proc( self : Queue($Type), allocator : Allocator ) {
raw_array := transmute(runtime.Raw_Dynamic_Array) self.data
raw_array.allocator = allocator
}
reload_map :: proc( self : map [$KeyType] $EntryType, allocator : Allocator ) {
raw := transmute(runtime.Raw_Map) self
raw.allocator = allocator
}

View File

@ -29,6 +29,9 @@ import "base:runtime"
import c "core:c/libc"
mem_fmt :: c.memset
import "core:container/queue"
Queue :: queue.Queue
import "core:dynlib"
import "core:hash"
@ -143,11 +146,17 @@ is_power_of_two :: proc {
is_power_of_two_uintptr,
}
iterator :: proc {
iterator_queue,
}
make :: proc {
array_init,
hmap_chained_init,
hmap_zpl_init,
make_queue,
// Usual
make_slice,
make_dynamic_array,
@ -157,10 +166,24 @@ make :: proc {
make_multi_pointer,
}
next :: proc {
next_queue_iterator,
}
push :: proc {
stack_push,
}
space_left :: proc {
queue.space,
}
reload :: proc {
reload_array,
reload_queue,
reload_map,
}
to_runes :: proc {
string_to_runes,
}

61
code/grime/queue.odin Normal file
View File

@ -0,0 +1,61 @@
package grime
import "core:container/queue"
make_queue :: proc( $QueueType : typeid/Queue($Type), capacity := queue.DEFAULT_CAPACITY, allocator := context.allocator ) -> (result : Queue(Type), error : AllocatorError)
{
queue.init( & result, capacity, allocator )
return
}
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 : ])
return
}
QueueIterator :: struct( $Type : typeid ) {
data : []Type,
length : uint,
offset : uint,
index : uint,
}
iterator_queue :: proc( queue : $QueueType / Queue($Type) ) -> QueueIterator(Type)
{
iter := QueueIterator(Type) {
data = queue.data[:],
length = queue.len,
offset = queue.offset,
index = 0,
}
return iter
}
next_queue_iterator :: proc( iter : ^QueueIterator($Type) ) -> ^Type
{
using iter
front_id := (length + offset ) % len(data)
elem_id := (length + offset - index) % len(data)
if elem_id == front_id do return nil
elem := & data[ elem_id ]
index += 1
return elem
}

View File

@ -181,7 +181,7 @@ load_sectr_api :: proc( version_id : i32 ) -> (loaded_module : sectr.ModuleAPI)
startup := cast( type_of( sectr.startup )) os_lib_get_proc( lib, "startup" )
shutdown := cast( type_of( sectr.sectr_shutdown )) os_lib_get_proc( lib, "sectr_shutdown" )
reload := cast( type_of( sectr.reload )) os_lib_get_proc( lib, "reload" )
reload := cast( type_of( sectr.hot_reload )) os_lib_get_proc( lib, "hot_reload" )
tick := cast( type_of( sectr.tick )) os_lib_get_proc( lib, "tick" )
clean_frame := cast( type_of( sectr.clean_frame )) os_lib_get_proc( lib, "clean_frame" )

View File

@ -252,8 +252,8 @@ ui_screen_settings_menu :: proc( captures : rawptr = nil ) -> ( should_raise : b
}
if input_box.active {
array_append( & value_str, input.codes_pressed )
array_clear( input.codes_pressed )
append( & value_str, input_events.codes_pressed )
clear( input_events.codes_pressed )
}
else if input_box.was_active
{
@ -264,8 +264,8 @@ ui_screen_settings_menu :: proc( captures : rawptr = nil ) -> ( should_raise : b
}
else
{
array_clear( value_str)
array_append( & value_str, to_runes(str_fmt("%v", config.engine_refresh_hz)))
clear( value_str)
append( & value_str, to_runes(str_fmt("%v", config.engine_refresh_hz)))
}
ui_parent(input_box)

View File

@ -210,6 +210,8 @@ State :: struct {
input_prev : ^InputState,
input : ^InputState,
input_events : InputEvents,
// Note(Ed): Do not modify directly, use its interface in app/event.odin
staged_input_events : Array(InputEvent),
// TODO(Ed): Add a multi-threaded guard for accessing or mutating staged_input_events.

View File

@ -30,7 +30,7 @@ ModuleAPI :: struct {
startup : type_of( startup ),
shutdown : type_of( sectr_shutdown ),
reload : type_of( reload ),
reload : type_of( hot_reload ),
tick : type_of( tick ),
clean_frame : type_of( clean_frame ),
}
@ -107,24 +107,23 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem
{
input = & input_data[1]
input_prev = & input_data[0]
for & input in input_data {
using input
error : AllocatorError
events, error = make( Array(InputEvent), Kilo, persistent_slab_allocator() )
ensure(error == AllocatorError.None, "Failed to allocate input.events array")
using input_events
key_events, error = make( Array(InputKeyEvent), Kilo, persistent_slab_allocator() )
ensure(error == AllocatorError.None, "Failed to allocate key_events array")
error : AllocatorError
events, error = make( Queue(InputEvent), 4 * Kilo, persistent_allocator() )
ensure(error == AllocatorError.None, "Failed to allocate input.events array")
mouse_events, error = make( Array(InputMouseEvent), Kilo, persistent_slab_allocator() )
ensure(error == AllocatorError.None, "Failed to allocate mouse_events array")
key_events, error = make( Queue(InputKeyEvent), Kilo, persistent_allocator() )
ensure(error == AllocatorError.None, "Failed to allocate key_events array")
codes_pressed, error = make( Array(rune), Kilo, persistent_slab_allocator() )
ensure(error == AllocatorError.None, "Failed to allocate codes_pressed array")
}
mouse_events, error = make( Queue(InputMouseEvent), 2 * Kilo, persistent_allocator() )
ensure(error == AllocatorError.None, "Failed to allocate mouse_events array")
input_staged_events, error := make( Array(InputEvent), Kilo, persistent_slab_allocator() )
codes_pressed, error = make( Array(rune), Kilo, persistent_allocator() )
ensure(error == AllocatorError.None, "Failed to allocate codes_pressed array")
staged_input_events, error = make( Array(InputEvent), 8 * Kilo, persistent_allocator() )
ensure(error == AllocatorError.None, "Failed to allocate input_staged_events array")
}
@ -396,7 +395,7 @@ sectr_shutdown :: proc()
}
@export
reload :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem, files_buffer_mem : ^VArena, host_logger : ^ Logger )
hot_reload :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem, files_buffer_mem : ^VArena, host_logger : ^ Logger )
{
spall.SCOPED_EVENT( & prof.ctx, & prof.buffer, #procedure )
set_profiler_module_context( prof )
@ -484,7 +483,6 @@ tick :: proc( host_delta_time_ms : f64, host_delta_ns : Duration ) -> b32
return ! should_close
}
// Lifted out of tick so that sokol_app_frame_callback can do it as well.
tick_work_frame :: #force_inline proc( host_delta_time_ms : f64 ) -> b32
{
@ -542,6 +540,7 @@ tick_work_frame :: #force_inline proc( host_delta_time_ms : f64 ) -> b32
// Lifted out of tick so that sokol_app_frame_callback can do it as well.
tick_frametime :: #force_inline proc( client_tick : ^time.Tick, host_delta_time_ms : f64, host_delta_ns : Duration )
{
profile(#procedure)
state := get_state(); using state
context.allocator = frame_slab_allocator()
context.temp_allocator = transient_allocator()
@ -598,7 +597,7 @@ tick_frametime :: #force_inline proc( client_tick : ^time.Tick, host_delta_time_
@export
clean_frame :: proc()
{
// profile( #procedure)
profile( #procedure)
state := get_state(); using state
context.logger = to_odin_logger( & Memory_App.logger )

View File

@ -15,10 +15,12 @@ sokol_app_init_callback :: proc "c" () {
// This is being filled in but we're directly controlling the lifetime of sokol_app's execution.
// So this will only get called during window pan or resize events (on Win32 at least)
sokol_app_frame_callback :: proc "c" () {
sokol_app_frame_callback :: proc "c" ()
{
context = get_state().sokol_context
state := get_state()
profile(#procedure)
state := get_state()
should_close : b32
sokol_width := sokol_app.widthf()
@ -38,10 +40,12 @@ sokol_app_frame_callback :: proc "c" () {
sokol_delta_ms := sokol_app.frame_delta()
sokol_delta_ns := transmute(Duration) sokol_delta_ms * MS_To_NS
profile_begin("Client Tick")
client_tick := time.tick_now()
should_close |= tick_work_frame( sokol_delta_ms )
tick_frametime( & client_tick, sokol_delta_ms, sokol_delta_ns )
profile_end()
tick_frametime( & client_tick, sokol_delta_ms, sokol_delta_ns )
window.resized = false
}
@ -118,43 +122,52 @@ sokol_app_event_callback :: proc "c" (sokol_event : ^sokol_app.Event)
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()
case .KEY_UP:
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()
case .CHAR:
type = .Unicode
codepoint = transmute(rune) sokol_event.char_code
modifiers = to_modifiers_code_from_sokol( sokol_event.modifiers )
sokol_app.consume_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()
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()
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()
case .MOUSE_MOVE:
type = .Mouse_Move
modifiers = to_modifiers_code_from_sokol( sokol_event.modifiers )
sokol_app.consume_event()
case .MOUSE_ENTER:
type = .Mouse_Enter
modifiers = to_modifiers_code_from_sokol( sokol_event.modifiers )
sokol_app.consume_event()
case .MOUSE_LEAVE:
type = .Mouse_Leave
modifiers = to_modifiers_code_from_sokol( sokol_event.modifiers )
sokol_app.consume_event()
// TODO(Ed): Add support
case .TOUCHES_BEGAN:
@ -163,30 +176,43 @@ sokol_app_event_callback :: proc "c" (sokol_event : ^sokol_app.Event)
case .TOUCHES_CANCELLED:
case .RESIZED:
sokol_app.consume_event()
case .ICONIFIED:
sokol_app.consume_event()
case .RESTORED:
sokol_app.consume_event()
case .FOCUSED:
sokol_app.consume_event()
case .UNFOCUSED:
sokol_app.consume_event()
case .SUSPENDED:
sokol_app.consume_event()
case .RESUMED:
sokol_app.consume_event()
case .QUIT_REQUESTED:
sokol_app.consume_event()
case .CLIPBOARD_PASTED:
sokol_app.consume_event()
case .FILES_DROPPED:
sokol_app.consume_event()
case .DISPLAY_CHANGED:
logf("sokol_app - event: Display changed")
logf("refresh rate: %v", sokol_app.refresh_rate())
monitor_refresh_hz := sokol_app.refresh_rate()
sokol_app.consume_event()
}
append_staged_input_events( event )
}
#endregion("Sokol App")

View File

@ -79,7 +79,8 @@ update :: proc( delta_time : f64 ) -> b32
}
state.input, state.input_prev = swap( state.input, state.input_prev )
pull_staged_input_events( state.input, & state.staged_input_events )
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 )
@ -165,7 +166,7 @@ update :: proc( delta_time : f64 ) -> b32
switch config.cam_zoom_mode
{
case .Smooth:
zoom_delta := input.mouse.vertical_wheel * config.cam_zoom_sensitivity_smooth
zoom_delta := input.mouse.scroll.y * config.cam_zoom_sensitivity_smooth
workspace.zoom_target *= 1 + zoom_delta * f32(delta_time)
workspace.zoom_target = clamp(workspace.zoom_target, config.cam_min_zoom, config.cam_max_zoom)
@ -174,7 +175,7 @@ update :: proc( delta_time : f64 ) -> b32
cam.zoom += (workspace.zoom_target - cam.zoom) * lerp_factor * f32(delta_time)
cam.zoom = clamp(cam.zoom, config.cam_min_zoom, config.cam_max_zoom) // Ensure cam.zoom stays within bounds
case .Digital:
zoom_delta := input.mouse.vertical_wheel * config.cam_zoom_sensitivity_digital
zoom_delta := input.mouse.scroll.y * config.cam_zoom_sensitivity_digital
workspace.zoom_target = clamp(workspace.zoom_target + zoom_delta, config.cam_min_zoom, config.cam_max_zoom)
cam.zoom = workspace.zoom_target
}

View File

@ -30,6 +30,9 @@ import "base:runtime"
import c "core:c/libc"
import "core:container/queue"
Queue :: queue.Queue
// import "core:dynlib"
import "core:hash"
@ -49,6 +52,9 @@ import fmt_io "core:fmt"
import "core:math"
import "core:math/bits"
u64_max :: bits.U64_MAX
import "core:mem"
align_forward_int :: mem.align_forward_int
align_forward_uint :: mem.align_forward_uint
@ -158,6 +164,7 @@ import "codebase:grime"
array_to_slice :: grime.array_to_slice
array_init :: grime.array_init
array_append :: grime.array_append
array_append_array :: grime.array_append_array
array_append_at :: grime.array_append_at
array_clear :: grime.array_clear
array_free :: grime.array_free
@ -181,6 +188,10 @@ import "codebase:grime"
hmap_zpl_reload :: grime.hmap_zpl_reload
hmap_zpl_set :: grime.hmap_zpl_set
make_queue :: grime.make_queue
next_queue_iterator :: grime.next_queue_iterator
Pool :: grime.Pool
Slab :: grime.Slab
@ -308,6 +319,10 @@ bivec3 :: proc {
vec3_to_bivec3,
}
clear :: proc{
grime.array_clear,
}
cm_to_pixels :: proc {
f32_cm_to_pixels,
vec2_cm_to_pixels,
@ -352,10 +367,15 @@ is_power_of_two :: proc {
is_power_of_two_uintptr,
}
iterator :: proc {
grime.iterator_queue,
}
make :: proc {
array_init,
hmap_chained_init,
hmap_zpl_init,
make_queue,
// Usual
make_slice,
@ -375,6 +395,14 @@ mov_avg_exp :: proc {
mov_avg_exp_f64,
}
next :: proc {
next_queue_iterator,
}
peek_front :: proc {
queue.peek_front,
}
pixels_to_cm :: proc {
f32_pixels_to_cm,
vec2_pixels_to_cm,
@ -412,6 +440,9 @@ pressed :: proc {
}
push :: proc {
queue.push_back,
grime.push_back_slice_queue,
stack_push,
stack_allocator_push,
@ -435,6 +466,29 @@ released :: proc {
btn_released,
}
reload :: proc {
grime.reload_array,
grime.reload_queue,
grime.reload_map,
}
space_left :: proc {
queue.space,
}
scope :: proc {
ui_layout_scope_via_layout,
ui_layout_scope_via_combo,
ui_style_scope_via_style,
ui_style_scope_via_combo,
ui_theme_scope_via_layout_style,
ui_theme_scope_via_combos,
ui_theme_scope_via_proc,
ui_theme_scope_via_theme,
}
sqrt :: proc{
math.sqrt_f16,
math.sqrt_f16le,
@ -451,19 +505,6 @@ inverse_sqrt :: proc {
inverse_sqrt_f32,
}
scope :: proc {
ui_layout_scope_via_layout,
ui_layout_scope_via_combo,
ui_style_scope_via_style,
ui_style_scope_via_combo,
ui_theme_scope_via_layout_style,
ui_theme_scope_via_combos,
ui_theme_scope_via_proc,
ui_theme_scope_via_theme,
}
sub :: proc {
sub_point3,
sub_range2,

View File

@ -1,63 +0,0 @@
package sectr
InputEventType :: enum u32 {
Key_Pressed,
Key_Released,
Mouse_Pressed,
Mouse_Released,
Mouse_Scroll,
Mouse_Move,
Mouse_Enter,
Mouse_Leave,
Unicode,
}
InputEvent :: struct
{
frame_id : u64,
type : InputEventType,
key : KeyCode,
modifiers : ModifierCodeFlags,
mouse : struct {
btn : MouseBtn,
pos : Vec2,
delta : Vec2,
scroll : Vec2,
},
codepoint : rune,
// num_touches : u32,
// touches : Touchpoint,
_sokol_frame_id : u64,
}
InputKeyEvent :: struct {
frame_id : u64,
type : InputEventType,
key : KeyCode,
modifiers : ModifierCodeFlags,
}
InputMouseEvent :: struct {
frame_id : u64,
type : InputEventType,
key : KeyCode,
modifiers : ModifierCodeFlags,
}
// Note(Ed): There is a staged_input_events : Array(InputEvent), in the state.odin's State struct
append_staged_input_events :: #force_inline proc() {
// TODO(Ed) : Add guards for multi-threading
state := get_state()
array_append( & state.staged_input_events, event )
}
pull_staged_input_events :: proc( input : ^InputState, staged_events : ^Array(InputEvent) )
{
// TODO(Ed) : Add guards for multi-threading
}

View File

@ -0,0 +1,259 @@
package sectr
InputEventType :: enum u32 {
Key_Pressed,
Key_Released,
Mouse_Pressed,
Mouse_Released,
Mouse_Scroll,
Mouse_Move,
Mouse_Enter,
Mouse_Leave,
Unicode,
}
InputEvent :: struct
{
frame_id : u64,
type : InputEventType,
key : KeyCode,
modifiers : ModifierCodeFlags,
mouse : struct {
btn : MouseBtn,
pos : Vec2,
delta : Vec2,
scroll : Vec2,
},
codepoint : rune,
// num_touches : u32,
// touches : Touchpoint,
_sokol_frame_id : u64,
}
// TODO(Ed): May just use input event exclusively in the future and have pointers for key and mouse event filters
// I'm on the fence about this as I don't want to force
InputKeyEvent :: struct {
frame_id : u64,
type : InputEventType,
key : KeyCode,
modifiers : ModifierCodeFlags,
}
InputMouseEvent :: struct {
frame_id : u64,
type : InputEventType,
btn : MouseBtn,
pos : Vec2,
delta : Vec2,
scroll : Vec2,
modifiers : ModifierCodeFlags,
}
InputEvents :: struct {
events : Queue(InputEvent),
key_events : Queue(InputKeyEvent),
mouse_events : Queue(InputMouseEvent),
codes_pressed : Array(rune),
}
// Note(Ed): There is a staged_input_events : Array(InputEvent), in the state.odin's State struct
append_staged_input_events :: #force_inline proc( event : InputEvent ) {
// TODO(Ed) : Add guards for multi-threading
state := get_state()
append( & state.staged_input_events, event )
}
pull_staged_input_events :: proc( input : ^InputState, input_events : ^InputEvents, staged_events : Array(InputEvent) )
{
// TODO(Ed) : Add guards for multi-threading
staged_events_slice := array_to_slice(staged_events)
push( & input_events.events, staged_events_slice )
using input_events
for event in staged_events_slice
{
switch event.type {
case .Key_Pressed:
push( & key_events, InputKeyEvent {
frame_id = event.frame_id,
type = event.type,
key = event.key,
modifiers = event.modifiers
})
case .Key_Released:
push( & key_events, InputKeyEvent {
frame_id = event.frame_id,
type = event.type,
key = event.key,
modifiers = event.modifiers
})
case .Unicode:
append( & codes_pressed, event.codepoint )
case .Mouse_Pressed:
push( & mouse_events, InputMouseEvent {
frame_id = event.frame_id,
type = event.type,
btn = event.mouse.btn,
pos = event.mouse.pos,
delta = event.mouse.delta,
scroll = event.mouse.scroll,
modifiers = event.modifiers,
})
case .Mouse_Released:
push( & mouse_events, InputMouseEvent {
frame_id = event.frame_id,
type = event.type,
btn = event.mouse.btn,
pos = event.mouse.pos,
delta = event.mouse.delta,
scroll = event.mouse.scroll,
modifiers = event.modifiers,
})
case .Mouse_Scroll:
push( & mouse_events, InputMouseEvent {
frame_id = event.frame_id,
type = event.type,
btn = event.mouse.btn,
pos = event.mouse.pos,
delta = event.mouse.delta,
scroll = event.mouse.scroll,
modifiers = event.modifiers,
})
case .Mouse_Move:
push( & mouse_events, InputMouseEvent {
frame_id = event.frame_id,
type = event.type,
btn = event.mouse.btn,
pos = event.mouse.pos,
delta = event.mouse.delta,
scroll = event.mouse.scroll,
modifiers = event.modifiers,
})
case .Mouse_Enter:
push( & mouse_events, InputMouseEvent {
frame_id = event.frame_id,
type = event.type,
btn = event.mouse.btn,
pos = event.mouse.pos,
delta = event.mouse.delta,
scroll = event.mouse.scroll,
modifiers = event.modifiers,
})
case .Mouse_Leave:
push( & mouse_events, InputMouseEvent {
frame_id = event.frame_id,
type = event.type,
btn = event.mouse.btn,
pos = event.mouse.pos,
delta = event.mouse.delta,
scroll = event.mouse.scroll,
modifiers = event.modifiers,
})
}
}
clear( staged_events )
}
poll_input_events :: proc( input, prev_input : ^InputState, input_events : InputEvents )
{
input.keyboard = {}
input.mouse = {}
input_events := input_events
using input_events
@static prev_frame : u64 = u64_max
last_frame := peek_front( & events).frame_id
// No new events, don't update
if prev_frame != 0 && 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
key := & input.keyboard.keys[event.key]
prev_key := prev_input.keyboard.keys[event.key]
first_transition := key.half_transitions == 0
#partial switch event.type {
case .Key_Pressed:
key.half_transitions += 1
key.ended_down = true
case .Key_Released:
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
}
}
Iterate_Mouse_Events:
{
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
process_digital_btn :: proc( btn : ^DigitalBtn, prev_btn : DigitalBtn, ended_down : b32 )
{
first_transition := btn.half_transitions == 0
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 {
case .Mouse_Pressed:
btn := & input.mouse.btns[event.btn]
prev_btn := prev_input.mouse.btns[event.btn]
process_digital_btn( btn, prev_btn, true )
case .Mouse_Released:
btn := & input.mouse.btns[event.btn]
prev_btn := prev_input.mouse.btns[event.btn]
process_digital_btn( btn, prev_btn, false )
case .Mouse_Scroll:
input.mouse.scroll += event.scroll.x
case .Mouse_Move:
case .Mouse_Enter:
case .Mouse_Leave:
// Handled elsewhere
}
input.mouse.pos = event.pos
input.mouse.delta = event.delta
}
}
prev_frame = last_frame
}

View File

@ -10,7 +10,7 @@ AnalogStick :: struct {
DigitalBtn :: struct {
half_transitions : i32,
ended_down : b32
ended_down : b32,
}
btn_pressed :: proc( btn : DigitalBtn ) -> b32 {
@ -167,11 +167,11 @@ MouseState :: struct {
btns : [16] DigitalBtn,
using individual : struct {
left, middle, right : DigitalBtn,
side, forward, back, extra : DigitalBtn
side, forward, back, extra : DigitalBtn,
}
},
raw_pos, pos, delta : Vec2,
vertical_wheel, horizontal_wheel : AnalogAxis
raw_pos, pos, delta : Vec2,
scroll : [2]AnalogAxis,
}
mouse_world_delta :: #force_inline proc "contextless" () -> Vec2 {
@ -183,10 +183,4 @@ mouse_world_delta :: #force_inline proc "contextless" () -> Vec2 {
InputState :: struct {
keyboard : KeyboardState,
mouse : MouseState,
events : Array(InputEvent),
key_events : Array(InputKeyEvent),
mouse_events : Array(InputMouseEvent),
codes_pressed : Array(rune),
}

View File

@ -7,43 +7,18 @@ import sokol_app "thirdparty:sokol/app"
to_modifiers_code_from_sokol :: proc( sokol_modifiers : u32 ) -> ( modifiers : ModifierCodeFlags )
{
if sokol_modifiers & sokol_app.MODIFIER_SHIFT != 0 {
modifiers |= { .Shift }
}
if sokol_modifiers & sokol_app.MODIFIER_CTRL != 0 {
modifiers |= { .Control }
}
if sokol_modifiers & sokol_app.MODIFIER_ALT != 0 {
modifiers |= { .Alt }
}
if sokol_modifiers & sokol_app.MODIFIER_LMB != 0 {
modifiers |= { .Left_Mouse }
}
if sokol_modifiers & sokol_app.MODIFIER_RMB != 0 {
modifiers |= { .Right_Mouse }
}
if sokol_modifiers & sokol_app.MODIFIER_MMB != 0 {
modifiers |= { .Middle_Mouse }
}
if sokol_modifiers & sokol_app.MODIFIER_LSHIFT != 0 {
modifiers |= { .Left_Shift }
}
if sokol_modifiers & sokol_app.MODIFIER_RSHIFT != 0 {
modifiers |= { .Right_Shift }
}
if sokol_modifiers & sokol_app.MODIFIER_LCTRL != 0 {
modifiers |= { .Left_Control }
}
if sokol_modifiers & sokol_app.MODIFIER_RCTRL != 0 {
modifiers |= { .Right_Control }
}
if sokol_modifiers & sokol_app.MODIFIER_LALT != 0 {
modifiers |= { .Left_Alt }
}
if sokol_modifiers & sokol_app.MODIFIER_RALT != 0 {
modifiers |= { .Right_Alt }
}
if sokol_modifiers & sokol_app.MODIFIER_SHIFT != 0 do modifiers |= { .Shift }
if sokol_modifiers & sokol_app.MODIFIER_CTRL != 0 do modifiers |= { .Control }
if sokol_modifiers & sokol_app.MODIFIER_ALT != 0 do modifiers |= { .Alt }
if sokol_modifiers & sokol_app.MODIFIER_LMB != 0 do modifiers |= { .Left_Mouse }
if sokol_modifiers & sokol_app.MODIFIER_RMB != 0 do modifiers |= { .Right_Mouse }
if sokol_modifiers & sokol_app.MODIFIER_MMB != 0 do modifiers |= { .Middle_Mouse }
if sokol_modifiers & sokol_app.MODIFIER_LSHIFT != 0 do modifiers |= { .Left_Shift }
if sokol_modifiers & sokol_app.MODIFIER_RSHIFT != 0 do modifiers |= { .Right_Shift }
if sokol_modifiers & sokol_app.MODIFIER_LCTRL != 0 do modifiers |= { .Left_Control }
if sokol_modifiers & sokol_app.MODIFIER_RCTRL != 0 do modifiers |= { .Right_Control }
if sokol_modifiers & sokol_app.MODIFIER_LALT != 0 do modifiers |= { .Left_Alt }
if sokol_modifiers & sokol_app.MODIFIER_RALT != 0 do modifiers |= { .Right_Alt }
return
}