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:
parent
3b395f3356
commit
b698f5166b
18
code/grime/hot_reload.odin
Normal file
18
code/grime/hot_reload.odin
Normal 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
|
||||
}
|
@ -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
61
code/grime/queue.odin
Normal 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
|
||||
}
|
@ -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" )
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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 )
|
||||
|
||||
|
@ -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")
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
||||
|
||||
}
|
259
code/sectr/input/events.odin
Normal file
259
code/sectr/input/events.odin
Normal 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
|
||||
}
|
@ -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),
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user