#load "sdl_input.jai"; LEFT_STICK_DEADZONE :: 0.239; RIGHT_STICK_DEADZONE :: 0.265; Key_Flags :: enum_flags u8 { NONE :: 0; DOWN :: 1; START :: 2; END :: 4; EATEN :: 8; } Key_Code :: enum { INVALID :: 0; A; B; C; D; E; F; G; H; I; J; K; L; M; N; O; P; Q; R; S; T; U; V; W; X; Y; Z; ZERO; ONE; TWO; THREE; FOUR; FIVE; SIX; SEVEN; EIGHT; NINE; F1; F2; F3; F4; F5; F6; F7; F8; F9; F10; F11; F12; SPACE; BACKSPACE; RETURN; TAB; SHIFT; CTRL; ALT; DELETE; TILDE; ESCAPE; LEFT; RIGHT; UP; DOWN; MOUSE_LEFT; MOUSE_RIGHT; KEYS_MAX; } Gamepad_Button :: enum { SPECIAL_BOTTOM; SPECIAL_TOP; SPECIAL_LEFT; SPECIAL_RIGHT; LEFT_STICK_LEFT; LEFT_STICK_RIGHT; LEFT_STICK_UP; LEFT_STICK_DOWN; LEFT_STICK_BUTTON; RIGHT_STICK_BUTTON; DPAD_LEFT; DPAD_RIGHT; DPAD_UP; DPAD_DOWN; LEFT_BUMPER; RIGHT_BUMPER; LEFT_TRIGGER; RIGHT_TRIGGER; GAMEPAD_MAX; } Gamepad :: struct { id : s32; left_stick_x : float; left_stick_y : float; right_stick_x : float; right_stick_y : float; buttons : [Gamepad_Button.GAMEPAD_MAX] Key_Flags; } MAX_GAMEPADS :: 4; MAX_MAPPINGS :: 4; Action_Mapping :: struct { gamepad_buttons: [MAX_MAPPINGS] Gamepad_Button; keys: [MAX_MAPPINGS] Key_Code; gamepad_mapping_count: s32; key_mapping_count: s32; } Last_Touched_State :: enum { KEYBOARD_AND_MOUSE; GAMEPAD; } Input_State :: struct { exit : bool; action_mappings: [..] Action_Mapping; keys: [Key_Code.KEYS_MAX] Key_Flags; mouse : struct { x : float; y : float; delta_x : float; delta_y : float; first: bool = true; wheel: float; } normalized_viewport_mouse_position: Vector2; viewport_mouse_position: Vector2; gamepads: [MAX_GAMEPADS] Gamepad; num_gamepads: s32; has_char : bool; current_char: s8; last_touched: Last_Touched_State; } init_input :: () { engine.input = .{}; engine.input.has_char = false; init_sdl_input(); } update_key_state :: (key: Key_Code, down: bool) { using engine.input; flags := keys[key]; if down { if !(flags & Key_Flags.DOWN) { flags = Key_Flags.DOWN | Key_Flags.START; } } else { flags = Key_Flags.END; } keys[key] = flags; engine.input.last_touched = .KEYBOARD_AND_MOUSE; } update_gamepad_state :: (gamepad: *Gamepad, button: Gamepad_Button, down: bool) { flags := gamepad.buttons[button]; if down { if !(flags & Key_Flags.DOWN) { flags = Key_Flags.DOWN | Key_Flags.START; engine.input.last_touched = .GAMEPAD; } } else if flags & Key_Flags.DOWN { flags = Key_Flags.END; } gamepad.buttons[button] = flags; } update_input :: () { engine.input.mouse.delta_x = 0.0; engine.input.mouse.delta_y = 0.0; engine.input.mouse.wheel = 0.0; engine.input.has_char = false; remove_all_temp_key_flags(*engine.input); update_sdl_input(); update_gamepad_input(); #if !EDITOR { engine.input.viewport_mouse_position.x = engine.input.mouse.x; engine.input.viewport_mouse_position.y = engine.input.mouse.y; engine.input.normalized_viewport_mouse_position = engine.input.viewport_mouse_position / Vector2.{xx engine.renderer.render_target_width, xx engine.renderer.render_target_height}; } } remove_all_temp_key_flags :: (using input_state: *Input_State) { for 0..Key_Code.KEYS_MAX - 1 { keys[it] &= ~Key_Flags.START; keys[it] &= ~Key_Flags.END; keys[it] &= ~Key_Flags.EATEN; } for g: 0..num_gamepads-1 { for 0..Gamepad_Button.GAMEPAD_MAX-1 { gamepads[g].buttons[it] &= ~Key_Flags.START; gamepads[g].buttons[it] &= ~Key_Flags.END; } } } eat_all_input :: (using input_state: *Input_State) { for 0..Key_Code.KEYS_MAX - 1 { eat_key(cast(Key_Code)it); } } eat_mouse_input :: (using input_state: *Input_State) { eat_key(.MOUSE_LEFT); eat_key(.MOUSE_RIGHT); } eat_key :: (key: Key_Code) { engine.input.keys[key] |= Key_Flags.EATEN; } action_down :: (action: Action) -> bool { mapping := engine.input.action_mappings[action]; for 0..mapping.key_mapping_count-1 { if key_down(mapping.keys[it]) { return true; } } for 0..mapping.gamepad_mapping_count-1 { if gamepad_down(0, mapping.gamepad_buttons[it]) { return true; } } return false; } action_pressed :: (action: Action) -> bool { mapping := engine.input.action_mappings[action]; for 0..mapping.key_mapping_count-1 { if key_pressed(mapping.keys[it]) { return true; } } for 0..mapping.gamepad_mapping_count-1 { if gamepad_pressed(0, mapping.gamepad_buttons[it]) { return true; } } return false; } action_up :: (action: Action) -> bool { mapping := engine.input.action_mappings[action]; for 0..mapping.key_mapping_count-1 { if key_up(mapping.keys[it]) { return true; } } for 0..mapping.gamepad_mapping_count-1 { if gamepad_up(0, mapping.gamepad_buttons[it]) { return true; } } return false; } get_mouse_delta_x :: inline () -> float { return engine.input.mouse.delta_x; } get_mouse_delta_y :: inline () -> float { return engine.input.mouse.delta_y; } get_mouse_delta :: () -> float, float { return get_mouse_delta_x(), get_mouse_delta_y(); } get_mouse_wheel_input :: () -> float { return engine.input.mouse.wheel; } get_horizontal_axis :: () -> float { if #complete engine.input.last_touched == { case .KEYBOARD_AND_MOUSE; if key_pressed(.A) || key_pressed(.LEFT) return -1.0; else if key_pressed(.D) || key_pressed(.RIGHT) return 1.0; else return 0.0; case .GAMEPAD; if gamepad_pressed(0, .DPAD_LEFT) return -1.0; else if gamepad_pressed(0, .DPAD_RIGHT) return 1.0; return engine.input.gamepads[0].left_stick_x; } } get_vertical_axis :: () -> float { if #complete engine.input.last_touched == { case .KEYBOARD_AND_MOUSE; if key_pressed(.S) || key_pressed(.DOWN) return -1.0; else if key_pressed(.W) || key_pressed(.UP) return 1.0; else return 0.0; case .GAMEPAD; if gamepad_pressed(0, .DPAD_DOWN) return -1.0; else if gamepad_pressed(0, .DPAD_UP) return 1.0; return -engine.input.gamepads[0].left_stick_y; } } get_right_horizontal_axis :: () -> float { if #complete engine.input.last_touched == { case .KEYBOARD_AND_MOUSE; return engine.input.mouse.delta_x; case .GAMEPAD; return engine.input.gamepads[0].right_stick_x; } } get_right_vertical_axis :: () -> float { if #complete engine.input.last_touched == { case .KEYBOARD_AND_MOUSE; return engine.input.mouse.delta_y; case .GAMEPAD; return -engine.input.gamepads[0].right_stick_y; } } key_down :: (key: Key_Code) -> bool { flags := engine.input.keys[key]; return flags & .START && !(flags & .EATEN); } key_pressed :: (key: Key_Code) -> bool { flags := engine.input.keys[key]; return flags & .DOWN && !(flags & .EATEN); } key_up :: (key: Key_Code) -> bool { flags := engine.input.keys[key]; return flags & .END && !(flags & .EATEN); } gamepad_down :: (index: s32, button: Gamepad_Button) -> bool { return cast(bool)(engine.input.gamepads[index].buttons[button] & .START); } gamepad_pressed :: (index: s32, button: Gamepad_Button) -> bool { return cast(bool)(engine.input.gamepads[index].buttons[button] & .DOWN); } gamepad_up :: (index: s32, button: Gamepad_Button) -> bool { return cast(bool)(engine.input.gamepads[index].buttons[button] & .END); }