mirror of
				https://github.com/NoelFB/blah.git
				synced 2025-11-04 01:41:34 +08:00 
			
		
		
		
	new input binding/mapping implementation
This commit is contained in:
		@ -9,7 +9,7 @@ add_library(blah
 | 
			
		||||
 | 
			
		||||
	src/core/app.cpp
 | 
			
		||||
	src/core/filesystem.cpp
 | 
			
		||||
	src/core/log.cpp
 | 
			
		||||
	src/core/common.cpp
 | 
			
		||||
	src/core/time.cpp
 | 
			
		||||
 | 
			
		||||
	src/graphics/blend.cpp
 | 
			
		||||
@ -21,9 +21,8 @@ add_library(blah
 | 
			
		||||
	src/graphics/texture.cpp
 | 
			
		||||
 | 
			
		||||
	src/input/input.cpp
 | 
			
		||||
	src/input/virtual_stick.cpp
 | 
			
		||||
	src/input/virtual_button.cpp
 | 
			
		||||
	src/input/virtual_axis.cpp
 | 
			
		||||
	src/input/binding.cpp
 | 
			
		||||
	src/input/binding_registry.cpp
 | 
			
		||||
	
 | 
			
		||||
	src/containers/str.cpp
 | 
			
		||||
	
 | 
			
		||||
@ -54,7 +53,6 @@ add_library(blah
 | 
			
		||||
	src/streams/memorystream.cpp
 | 
			
		||||
	src/streams/stream.cpp
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	src/internal/graphics_backend_gl.cpp
 | 
			
		||||
	src/internal/graphics_backend_d3d11.cpp
 | 
			
		||||
	src/internal/graphics_backend_dummy.cpp
 | 
			
		||||
 | 
			
		||||
@ -28,9 +28,8 @@
 | 
			
		||||
#include "blah/images/packer.h"
 | 
			
		||||
 | 
			
		||||
#include "blah/input/input.h"
 | 
			
		||||
#include "blah/input/virtual_stick.h"
 | 
			
		||||
#include "blah/input/virtual_button.h"
 | 
			
		||||
#include "blah/input/virtual_axis.h"
 | 
			
		||||
#include "blah/input/binding.h"
 | 
			
		||||
#include "blah/input/binding_registry.h"
 | 
			
		||||
 | 
			
		||||
#include "blah/math/calc.h"
 | 
			
		||||
#include "blah/math/circle.h"
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										261
									
								
								include/blah/input/binding.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										261
									
								
								include/blah/input/binding.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,261 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
#include <blah/input/input.h>
 | 
			
		||||
#include <blah/containers/stackvector.h>
 | 
			
		||||
#include <blah/math/point.h>
 | 
			
		||||
#include <blah/math/vec2.h>
 | 
			
		||||
 | 
			
		||||
namespace Blah
 | 
			
		||||
{
 | 
			
		||||
	// Represents a Controller Trigger or a single direction of a Controller Axis.
 | 
			
		||||
	// Used in the Binding implementation.
 | 
			
		||||
	struct BoundTrigger
 | 
			
		||||
	{
 | 
			
		||||
		// Controller Index we're bound to
 | 
			
		||||
		int controller = 0;
 | 
			
		||||
 | 
			
		||||
		// The Axis we're bound to
 | 
			
		||||
		Axis axis = Axis::None;
 | 
			
		||||
 | 
			
		||||
		// Minimum value of the axis
 | 
			
		||||
		float threshold = 0.01f;
 | 
			
		||||
 | 
			
		||||
		// requires a positive value
 | 
			
		||||
		// otherwise requires a negative value
 | 
			
		||||
		bool positive = true;
 | 
			
		||||
 | 
			
		||||
		BoundTrigger() = default;
 | 
			
		||||
		BoundTrigger(Axis axis);
 | 
			
		||||
		BoundTrigger(int controller, Axis axis, float threshold, bool positive);
 | 
			
		||||
 | 
			
		||||
		bool is_down(float axis_value) const;
 | 
			
		||||
 | 
			
		||||
		// helper functions for frequent use cases
 | 
			
		||||
		static BoundTrigger left_stick_left(int controller, float threshold);
 | 
			
		||||
		static BoundTrigger left_stick_right(int controller, float threshold);
 | 
			
		||||
		static BoundTrigger left_stick_up(int controller, float threshold);
 | 
			
		||||
		static BoundTrigger left_stick_down(int controller, float threshold);
 | 
			
		||||
		static BoundTrigger right_stick_left(int controller, float threshold);
 | 
			
		||||
		static BoundTrigger right_stick_right(int controller, float threshold);
 | 
			
		||||
		static BoundTrigger right_stick_up(int controller, float threshold);
 | 
			
		||||
		static BoundTrigger right_stick_down(int controller, float threshold);
 | 
			
		||||
		static BoundTrigger left_trigger(int controller, float threshold);
 | 
			
		||||
		static BoundTrigger right_trigger(int controller, float threshold);
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	struct BoundButton
 | 
			
		||||
	{
 | 
			
		||||
		// Controller Index we're bound to
 | 
			
		||||
		int controller = 0;
 | 
			
		||||
 | 
			
		||||
		// Button we're bound to
 | 
			
		||||
		Button button = Button::None;
 | 
			
		||||
 | 
			
		||||
		BoundButton() = default;
 | 
			
		||||
		BoundButton(Button button);
 | 
			
		||||
		BoundButton(int controller, Button button);
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	// Single input Binding
 | 
			
		||||
	class Binding
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
 | 
			
		||||
		// Input Buffer for press events
 | 
			
		||||
		float press_buffer = 0;
 | 
			
		||||
 | 
			
		||||
		// Input Buffer for release events
 | 
			
		||||
		float release_buffer = 0;
 | 
			
		||||
 | 
			
		||||
		// List of bound Keys
 | 
			
		||||
		StackVector<Key, 16> keys;
 | 
			
		||||
		
 | 
			
		||||
		// List of bound Buttons
 | 
			
		||||
		StackVector<BoundButton, 16> buttons;
 | 
			
		||||
 | 
			
		||||
		// List of bound Triggers / Axis
 | 
			
		||||
		StackVector<BoundTrigger, 16> triggers;
 | 
			
		||||
 | 
			
		||||
		// List of bound Mouse buttons
 | 
			
		||||
		StackVector<MouseButton, 16> mouse;
 | 
			
		||||
 | 
			
		||||
		// if the binding has been pressed
 | 
			
		||||
		bool pressed() const;
 | 
			
		||||
 | 
			
		||||
		// if the binding has been released
 | 
			
		||||
		bool released() const;
 | 
			
		||||
 | 
			
		||||
		// if the binding is currently held
 | 
			
		||||
		bool down() const;
 | 
			
		||||
 | 
			
		||||
		// returns the binding's value from 0-1
 | 
			
		||||
		float value() const;
 | 
			
		||||
 | 
			
		||||
		// returns the bindings signed value (0 or 1)
 | 
			
		||||
		int sign() const;
 | 
			
		||||
 | 
			
		||||
		// returns the timestamp of the last time the binding was pressed
 | 
			
		||||
		double timestamp() const;
 | 
			
		||||
 | 
			
		||||
		// updates the binding state
 | 
			
		||||
		void update();
 | 
			
		||||
 | 
			
		||||
		// consumes the current press, and pressed() will return false until the next press
 | 
			
		||||
		void consume_press();
 | 
			
		||||
 | 
			
		||||
		// consumes the current release, and released() will return false until the next release
 | 
			
		||||
		void consume_release();
 | 
			
		||||
 | 
			
		||||
		// adds a key to the binding
 | 
			
		||||
		void add(Key key);
 | 
			
		||||
 | 
			
		||||
		// adds a button to the binding
 | 
			
		||||
		void add(BoundButton button);
 | 
			
		||||
 | 
			
		||||
		// adds an trigger to the binding
 | 
			
		||||
		void add(BoundTrigger trigger);
 | 
			
		||||
 | 
			
		||||
		// adds a mouse button to the binding
 | 
			
		||||
		void add(MouseButton mouse);
 | 
			
		||||
 | 
			
		||||
		// adds an input to the binding
 | 
			
		||||
		template<typename T, typename T2, typename ... Args>
 | 
			
		||||
		void add(T first, T2 second, const Args&... args)
 | 
			
		||||
		{
 | 
			
		||||
			add(first);
 | 
			
		||||
			add(second, args...);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// assigns all the bindings to the specific controller
 | 
			
		||||
		void set_controller(int index);
 | 
			
		||||
 | 
			
		||||
		// removes all bindings
 | 
			
		||||
		void clear();
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		double m_last_timestamp = 0;
 | 
			
		||||
		double m_last_press_time = -1;
 | 
			
		||||
		double m_last_release_time = -1;
 | 
			
		||||
		float m_value = 0.0f;
 | 
			
		||||
		bool m_pressed = false;
 | 
			
		||||
		bool m_released = false;
 | 
			
		||||
		bool m_down = false;
 | 
			
		||||
		bool m_press_consumed = false;
 | 
			
		||||
		bool m_release_consumed = false;
 | 
			
		||||
 | 
			
		||||
		bool get_pressed() const;
 | 
			
		||||
		bool get_released() const;
 | 
			
		||||
		bool get_down() const;
 | 
			
		||||
		float get_value() const;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	// Represents a Bound Axis (ex. Left/Right movement, or a Trigger)
 | 
			
		||||
	class AxisBinding
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
 | 
			
		||||
		enum class Overlap
 | 
			
		||||
		{
 | 
			
		||||
			Newer,
 | 
			
		||||
			Older,
 | 
			
		||||
			Cancel
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		// Negative Value Binding
 | 
			
		||||
		Binding negative;
 | 
			
		||||
 | 
			
		||||
		// Positive Value Binding
 | 
			
		||||
		Binding positive;
 | 
			
		||||
 | 
			
		||||
		// How to handle overlaps (ex. Left and Right are both held)
 | 
			
		||||
		Overlap overlap = Overlap::Newer;
 | 
			
		||||
 | 
			
		||||
		// Current Value from -1 to 1
 | 
			
		||||
		float value() const;
 | 
			
		||||
 | 
			
		||||
		// Current value, either -1, 0, or 1
 | 
			
		||||
		int sign() const;
 | 
			
		||||
 | 
			
		||||
		// updates the Binding
 | 
			
		||||
		void update();
 | 
			
		||||
 | 
			
		||||
		// consumes the press buffer
 | 
			
		||||
		void consume_press();
 | 
			
		||||
 | 
			
		||||
		// consumes the release buffer
 | 
			
		||||
		void consume_release();
 | 
			
		||||
 | 
			
		||||
		// Adds a negative & positive binding pair
 | 
			
		||||
		template<typename NegativeT, typename PositiveT>
 | 
			
		||||
		void add(NegativeT negative, PositiveT positive)
 | 
			
		||||
		{
 | 
			
		||||
			this->negative.add(negative);
 | 
			
		||||
			this->positive.add(positive);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Adds a Stick binding
 | 
			
		||||
		void add_left_stick_x(int controller, float threshold);
 | 
			
		||||
		void add_left_stick_y(int controller, float threshold);
 | 
			
		||||
		void add_right_stick_x(int controller, float threshold);
 | 
			
		||||
		void add_right_stick_y(int controller, float threshold);
 | 
			
		||||
 | 
			
		||||
		// assigns all the bindings to the specific controller
 | 
			
		||||
		void set_controller(int index);
 | 
			
		||||
 | 
			
		||||
		// Clears all Bindings
 | 
			
		||||
		void clear();
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	class StickBinding
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
 | 
			
		||||
		// An optional threshold for circular thresholds
 | 
			
		||||
		float round_threshold = 0.0f;
 | 
			
		||||
 | 
			
		||||
		// X Axis Binding
 | 
			
		||||
		AxisBinding x;
 | 
			
		||||
 | 
			
		||||
		// Y Axis Binding
 | 
			
		||||
		AxisBinding y;
 | 
			
		||||
 | 
			
		||||
		// Current Value, -1 to 1
 | 
			
		||||
		Vec2 value() const;
 | 
			
		||||
 | 
			
		||||
		// Current value, either -1, 0, or 1
 | 
			
		||||
		Point sign() const;
 | 
			
		||||
 | 
			
		||||
		// Updates the Binding
 | 
			
		||||
		void update();
 | 
			
		||||
 | 
			
		||||
		// Consumes the Press Buffer
 | 
			
		||||
		void consume_press();
 | 
			
		||||
 | 
			
		||||
		// Consumes the Release Buffer
 | 
			
		||||
		void consume_release();
 | 
			
		||||
 | 
			
		||||
		// Adds directional bindings
 | 
			
		||||
		template<typename LeftT, typename RightT, typename UpT, typename DownT>
 | 
			
		||||
		void add(LeftT left, RightT right, UpT up, DownT down)
 | 
			
		||||
		{
 | 
			
		||||
			x.negative.add(left);
 | 
			
		||||
			x.positive.add(right);
 | 
			
		||||
			y.negative.add(up);
 | 
			
		||||
			y.positive.add(down);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Adds the dpad binding
 | 
			
		||||
		void add_dpad(int controller);
 | 
			
		||||
 | 
			
		||||
		// Adds the left stick binding
 | 
			
		||||
		void add_left_stick(int controller, float threshold);
 | 
			
		||||
 | 
			
		||||
		// Adds the right stick binding
 | 
			
		||||
		void add_right_stick(int controller, float threshold);
 | 
			
		||||
 | 
			
		||||
		// assigns all the bindings to the specific controller
 | 
			
		||||
		void set_controller(int index);
 | 
			
		||||
 | 
			
		||||
		// Clears all the bindings
 | 
			
		||||
		void clear();
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										37
									
								
								include/blah/input/binding_registry.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								include/blah/input/binding_registry.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,37 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
#include <blah/input/binding.h>
 | 
			
		||||
#include <blah/containers/vector.h>
 | 
			
		||||
#include <memory>
 | 
			
		||||
 | 
			
		||||
namespace Blah
 | 
			
		||||
{
 | 
			
		||||
	using BindingRef = std::shared_ptr<Binding>;
 | 
			
		||||
	using AxisBindingRef = std::shared_ptr<AxisBinding>;
 | 
			
		||||
	using StickBindingRef = std::shared_ptr<StickBinding>;
 | 
			
		||||
 | 
			
		||||
	// Optional registry to automatically update bindings.
 | 
			
		||||
	// You can register different types of bindings here and until they are
 | 
			
		||||
	// no longer used, they will be updated without having to explicitely call
 | 
			
		||||
	// their update methods
 | 
			
		||||
	class BindingRegistry
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
		// registers a new binding
 | 
			
		||||
		static BindingRef register_binding();
 | 
			
		||||
 | 
			
		||||
		// registers a new axis binding
 | 
			
		||||
		static AxisBindingRef register_axis();
 | 
			
		||||
 | 
			
		||||
		// registers a new stick binding
 | 
			
		||||
		static StickBindingRef register_stick();
 | 
			
		||||
 | 
			
		||||
		// updates all the bindings. This is called
 | 
			
		||||
		// automatically by the App loop.
 | 
			
		||||
		static void update();
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		static Vector<std::weak_ptr<Binding>> bindings;
 | 
			
		||||
		static Vector<std::weak_ptr<AxisBinding>> axes;
 | 
			
		||||
		static Vector<std::weak_ptr<StickBinding>> sticks;
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
@ -1,86 +0,0 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
#include <blah/input/input.h>
 | 
			
		||||
 | 
			
		||||
namespace Blah
 | 
			
		||||
{
 | 
			
		||||
	// A virtual controller axis, which can be used to map multiple
 | 
			
		||||
	// inputs to an axis. Note that you must call `update` every frame!
 | 
			
		||||
	class VirtualAxis
 | 
			
		||||
	{
 | 
			
		||||
	private:
 | 
			
		||||
		struct KeysNode
 | 
			
		||||
		{
 | 
			
		||||
			Key positive = Key::Unknown;
 | 
			
		||||
			Key negative = Key::Unknown;
 | 
			
		||||
 | 
			
		||||
			int value = 0;
 | 
			
		||||
 | 
			
		||||
			void init(Key negative, Key positive);
 | 
			
		||||
			void update();
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		struct ButtonsNode
 | 
			
		||||
		{
 | 
			
		||||
			int gamepad_id = 0;
 | 
			
		||||
			Button positive = Button::None;
 | 
			
		||||
			Button negative = Button::None;
 | 
			
		||||
 | 
			
		||||
			int value = 0;
 | 
			
		||||
 | 
			
		||||
			void init(int gamepad_id, Button negative, Button positive);
 | 
			
		||||
			void update();
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		struct AxisNode
 | 
			
		||||
		{
 | 
			
		||||
			int gamepad_id = 0;
 | 
			
		||||
			Axis axis = Axis::None;
 | 
			
		||||
			float deadzone = 0;
 | 
			
		||||
 | 
			
		||||
			float value = 0;
 | 
			
		||||
 | 
			
		||||
			void init(int gamepad_id, Axis axis, float deadzone);
 | 
			
		||||
			void update();
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		KeysNode m_keys[Input::max_virtual_nodes];
 | 
			
		||||
		ButtonsNode m_buttons[Input::max_virtual_nodes];
 | 
			
		||||
		AxisNode m_axes[Input::max_virtual_nodes];
 | 
			
		||||
		int m_keys_len = 0;
 | 
			
		||||
		int m_buttons_len = 0;
 | 
			
		||||
		int m_axes_len = 0;
 | 
			
		||||
 | 
			
		||||
		float m_press_buffer = 0;
 | 
			
		||||
		float m_release_buffer = 0;
 | 
			
		||||
		float m_repeat_delay = 0;
 | 
			
		||||
		float m_repeat_interval = 0;
 | 
			
		||||
 | 
			
		||||
		float m_value = 0;
 | 
			
		||||
		int m_value_i = 0;
 | 
			
		||||
		float m_last_value = 0;
 | 
			
		||||
		int m_last_value_i = 0;
 | 
			
		||||
		bool m_pressed = false;
 | 
			
		||||
		bool m_released = false;
 | 
			
		||||
		double m_last_press_time = -1;
 | 
			
		||||
		double m_last_release_time = -1;
 | 
			
		||||
		double m_repeat_press_time = -1;
 | 
			
		||||
 | 
			
		||||
	public:
 | 
			
		||||
		VirtualAxis& add_keys(Key negative, Key positive);
 | 
			
		||||
		VirtualAxis& add_buttons(int gamepad_id, Button negative, Button positive);
 | 
			
		||||
		VirtualAxis& add_axis(int gamepad_id, Axis axis, float deadzone);
 | 
			
		||||
		VirtualAxis& repeat(float m_repeat_delay, float m_repeat_interval);
 | 
			
		||||
		VirtualAxis& press_buffer(float duration);
 | 
			
		||||
		VirtualAxis& release_buffer(float duration);
 | 
			
		||||
 | 
			
		||||
		void update();
 | 
			
		||||
		float value() const { return m_value; }
 | 
			
		||||
		int value_i() const { return m_value_i; }
 | 
			
		||||
		float last_value() const { return m_last_value; }
 | 
			
		||||
		int last_value_i() const { return m_last_value_i; }
 | 
			
		||||
		bool pressed() const { return m_pressed; }
 | 
			
		||||
		bool released() const { return m_released; }
 | 
			
		||||
		void clear_press_buffer() { m_last_press_time = -1; m_pressed = false; }
 | 
			
		||||
		void clear_release_buffer() { m_last_release_time = -1; m_released = false; }
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
@ -1,83 +0,0 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
#include <blah/input/input.h>
 | 
			
		||||
 | 
			
		||||
namespace Blah
 | 
			
		||||
{
 | 
			
		||||
	class VirtualButton
 | 
			
		||||
	{
 | 
			
		||||
	private:
 | 
			
		||||
		struct KeyNode
 | 
			
		||||
		{
 | 
			
		||||
			Key key = Key::Unknown;
 | 
			
		||||
 | 
			
		||||
			bool down = false;
 | 
			
		||||
			bool pressed = false;
 | 
			
		||||
			bool released = false;
 | 
			
		||||
 | 
			
		||||
			void init(Key key);
 | 
			
		||||
			void update();
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		struct ButtonNode
 | 
			
		||||
		{
 | 
			
		||||
			int gamepad_id = 0;
 | 
			
		||||
			Button button = Button::None;
 | 
			
		||||
 | 
			
		||||
			bool down = false;
 | 
			
		||||
			bool pressed = false;
 | 
			
		||||
			bool released = false;
 | 
			
		||||
 | 
			
		||||
			void init(int gamepad_id, Button button);
 | 
			
		||||
			void update();
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		struct AxisNode
 | 
			
		||||
		{
 | 
			
		||||
			int gamepad_id = 0;
 | 
			
		||||
			Axis axis = Axis::None;
 | 
			
		||||
			float threshold = 0;
 | 
			
		||||
			bool greater_than = false;
 | 
			
		||||
 | 
			
		||||
			bool down = false;
 | 
			
		||||
			bool pressed = false;
 | 
			
		||||
			bool released = false;
 | 
			
		||||
 | 
			
		||||
			void init(int gamepad_id, Axis axis, float threshold, bool greater_than);
 | 
			
		||||
			void update();
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		KeyNode m_keys[Input::max_virtual_nodes];
 | 
			
		||||
		ButtonNode m_buttons[Input::max_virtual_nodes];
 | 
			
		||||
		AxisNode m_axes[Input::max_virtual_nodes];
 | 
			
		||||
		int m_keys_len = 0;
 | 
			
		||||
		int m_buttons_len = 0;
 | 
			
		||||
		int m_axes_len = 0;
 | 
			
		||||
 | 
			
		||||
		float m_press_buffer = 0;
 | 
			
		||||
		float m_release_buffer = 0;
 | 
			
		||||
		float m_repeat_delay = 0;
 | 
			
		||||
		float m_repeat_interval = 0;
 | 
			
		||||
 | 
			
		||||
		bool m_down = false;
 | 
			
		||||
		bool m_pressed = false;
 | 
			
		||||
		bool m_released = false;
 | 
			
		||||
		double m_last_press_time = -1;
 | 
			
		||||
		double m_last_release_time = -1;
 | 
			
		||||
		double m_repeat_press_time = -1;
 | 
			
		||||
 | 
			
		||||
	public:
 | 
			
		||||
		VirtualButton& add_key(Key key);
 | 
			
		||||
		VirtualButton& add_button(int gamepad_id, Button button);
 | 
			
		||||
		VirtualButton& add_axis(int gamepad_id, Axis axis, float threshold, bool greater_than);
 | 
			
		||||
		VirtualButton& repeat(float m_repeat_delay, float m_repeat_interval);
 | 
			
		||||
		VirtualButton& press_buffer(float duration);
 | 
			
		||||
		VirtualButton& release_buffer(float duration);
 | 
			
		||||
 | 
			
		||||
		void update();
 | 
			
		||||
		bool down() const { return m_down; }
 | 
			
		||||
		bool pressed() const { return m_pressed; }
 | 
			
		||||
		bool released() const { return m_released; }
 | 
			
		||||
		void clear_press_buffer() { m_last_press_time = -1; m_pressed = false; }
 | 
			
		||||
		void clear_release_buffer() { m_last_release_time = -1; m_released = false; }
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
@ -1,97 +0,0 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
#include <blah/input/input.h>
 | 
			
		||||
#include <blah/math/vec2.h>
 | 
			
		||||
#include <blah/math/point.h>
 | 
			
		||||
 | 
			
		||||
namespace Blah
 | 
			
		||||
{
 | 
			
		||||
	// A virtual controller stick, which can be used to map multiple
 | 
			
		||||
	// inputs to a stick. Note that you must call `update` every frame!
 | 
			
		||||
	class VirtualStick
 | 
			
		||||
	{
 | 
			
		||||
	private:
 | 
			
		||||
		struct KeysNode
 | 
			
		||||
		{
 | 
			
		||||
			Key left;
 | 
			
		||||
			Key right;
 | 
			
		||||
			Key up;
 | 
			
		||||
			Key down;
 | 
			
		||||
 | 
			
		||||
			Point value;
 | 
			
		||||
 | 
			
		||||
			void init(Key left, Key right, Key up, Key down);
 | 
			
		||||
			void update();
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		struct ButtonsNode
 | 
			
		||||
		{
 | 
			
		||||
			int gamepad_id;
 | 
			
		||||
			Button left;
 | 
			
		||||
			Button right;
 | 
			
		||||
			Button up;
 | 
			
		||||
			Button down;
 | 
			
		||||
 | 
			
		||||
			Point value;
 | 
			
		||||
 | 
			
		||||
			void init(int gamepad_id, Button left, Button right, Button up, Button down);
 | 
			
		||||
			void update();
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		struct AxesNode
 | 
			
		||||
		{
 | 
			
		||||
			int gamepad_id;
 | 
			
		||||
			Axis horizontal;
 | 
			
		||||
			Axis vertical;
 | 
			
		||||
			float deadzone;
 | 
			
		||||
 | 
			
		||||
			Vec2 value;
 | 
			
		||||
 | 
			
		||||
			void init(int gamepad_id, Axis horizontal, Axis vertical, float deadzone);
 | 
			
		||||
			void update();
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		KeysNode m_keys[Input::max_virtual_nodes];
 | 
			
		||||
		ButtonsNode m_buttons[Input::max_virtual_nodes];
 | 
			
		||||
		AxesNode m_axes[Input::max_virtual_nodes];
 | 
			
		||||
		int m_keys_len = 0;
 | 
			
		||||
		int m_buttons_len = 0;
 | 
			
		||||
		int m_axes_len = 0;
 | 
			
		||||
 | 
			
		||||
		float m_press_buffer = 0;
 | 
			
		||||
		float m_release_buffer = 0;
 | 
			
		||||
		float m_repeat_delay = 0;
 | 
			
		||||
		float m_repeat_interval = 0;
 | 
			
		||||
 | 
			
		||||
		Vec2 m_value = Vec2();
 | 
			
		||||
		Point m_value_i = Point();
 | 
			
		||||
		Vec2 m_last_value = Vec2();
 | 
			
		||||
		Point m_last_value_i = Point();
 | 
			
		||||
		bool m_pressed = false;
 | 
			
		||||
		bool m_released = false;
 | 
			
		||||
 | 
			
		||||
		float m_i_deadzone;
 | 
			
		||||
		double m_last_press_time = -1;
 | 
			
		||||
		double m_last_release_time = -1;
 | 
			
		||||
		double m_repeat_press_time = -1;
 | 
			
		||||
 | 
			
		||||
	public:
 | 
			
		||||
		VirtualStick();
 | 
			
		||||
		VirtualStick(float iDeadzone);
 | 
			
		||||
		VirtualStick& add_keys(Key left, Key right, Key up, Key down);
 | 
			
		||||
		VirtualStick& add_buttons(int gamepad_id, Button left, Button right, Button up, Button down);
 | 
			
		||||
		VirtualStick& add_axes(int gamepad_id, Axis horizontal, Axis vertical, float deadzone);
 | 
			
		||||
		VirtualStick& repeat(float m_repeat_delay, float m_repeat_interval);
 | 
			
		||||
		VirtualStick& press_buffer(float duration);
 | 
			
		||||
		VirtualStick& release_buffer(float duration);
 | 
			
		||||
 | 
			
		||||
		void update();
 | 
			
		||||
		const Vec2& value() const { return m_value; }
 | 
			
		||||
		const Point& value_i() const { return m_value_i; }
 | 
			
		||||
		const Vec2& last_value() const { return m_last_value; }
 | 
			
		||||
		const Point& last_value_i() const { return m_last_value_i; }
 | 
			
		||||
		bool pressed() const { return m_pressed; }
 | 
			
		||||
		bool released() const { return m_released; }
 | 
			
		||||
		void clear_press_buffer() { m_last_press_time = 0; }
 | 
			
		||||
		void clear_release_buffer() { m_last_release_time = 0; }
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										492
									
								
								src/input/binding.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										492
									
								
								src/input/binding.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,492 @@
 | 
			
		||||
#include <blah/input/binding.h>
 | 
			
		||||
#include <blah/math/calc.h>
 | 
			
		||||
#include <blah/core/time.h>
 | 
			
		||||
 | 
			
		||||
using namespace Blah;
 | 
			
		||||
 | 
			
		||||
BoundTrigger::BoundTrigger(Axis axis)
 | 
			
		||||
	: axis(axis)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BoundTrigger::BoundTrigger(int controller, Axis axis, float threshold, bool positive)
 | 
			
		||||
	: controller(controller), axis(axis), threshold(threshold), positive(positive)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool BoundTrigger::is_down(float axis_value) const
 | 
			
		||||
{
 | 
			
		||||
	if ((axis_value > 0 && positive) || (axis_value < 0 && !positive))
 | 
			
		||||
	{
 | 
			
		||||
		if (Calc::abs(axis_value) >= threshold)
 | 
			
		||||
			return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BoundTrigger BoundTrigger::left_stick_left(int controller, float threshold)
 | 
			
		||||
{
 | 
			
		||||
	return BoundTrigger(controller, Axis::LeftX, threshold, false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BoundTrigger BoundTrigger::left_stick_right(int controller, float threshold)
 | 
			
		||||
{
 | 
			
		||||
	return BoundTrigger(controller, Axis::LeftX, threshold, true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BoundTrigger BoundTrigger::left_stick_up(int controller, float threshold)
 | 
			
		||||
{
 | 
			
		||||
	return BoundTrigger(controller, Axis::LeftY, threshold, false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BoundTrigger BoundTrigger::left_stick_down(int controller, float threshold)
 | 
			
		||||
{
 | 
			
		||||
	return BoundTrigger(controller, Axis::LeftY, threshold, true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BoundTrigger BoundTrigger::right_stick_left(int controller, float threshold)
 | 
			
		||||
{
 | 
			
		||||
	return BoundTrigger(controller, Axis::RightX, threshold, false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BoundTrigger BoundTrigger::right_stick_right(int controller, float threshold)
 | 
			
		||||
{
 | 
			
		||||
	return BoundTrigger(controller, Axis::RightX, threshold, true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BoundTrigger BoundTrigger::right_stick_up(int controller, float threshold)
 | 
			
		||||
{
 | 
			
		||||
	return BoundTrigger(controller, Axis::RightY, threshold, false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BoundTrigger BoundTrigger::right_stick_down(int controller, float threshold)
 | 
			
		||||
{
 | 
			
		||||
	return BoundTrigger(controller, Axis::RightY, threshold, true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BoundTrigger BoundTrigger::left_trigger(int controller, float threshold)
 | 
			
		||||
{
 | 
			
		||||
	return BoundTrigger(controller, Axis::LeftTrigger, threshold, true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BoundTrigger BoundTrigger::right_trigger(int controller, float threshold)
 | 
			
		||||
{
 | 
			
		||||
	return BoundTrigger(controller, Axis::RightTrigger, threshold, true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BoundButton::BoundButton(Button button)
 | 
			
		||||
	: button(button) {}
 | 
			
		||||
 | 
			
		||||
BoundButton::BoundButton(int controller, Button button)
 | 
			
		||||
	: controller(controller), button(button) {}
 | 
			
		||||
 | 
			
		||||
bool Binding::pressed() const
 | 
			
		||||
{
 | 
			
		||||
	if (m_press_consumed)
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	if (m_last_press_time >= 0 && (Time::seconds - m_last_press_time) <= press_buffer)
 | 
			
		||||
		return true;
 | 
			
		||||
 | 
			
		||||
	return m_pressed;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Binding::released() const
 | 
			
		||||
{
 | 
			
		||||
	if (m_release_consumed)
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	if (m_last_release_time >= 0 && (Time::seconds - m_last_release_time) <= release_buffer)
 | 
			
		||||
		return true;
 | 
			
		||||
 | 
			
		||||
	return m_released;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Binding::down() const
 | 
			
		||||
{
 | 
			
		||||
	return m_down;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float Binding::value() const
 | 
			
		||||
{
 | 
			
		||||
	return m_value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int Binding::sign() const
 | 
			
		||||
{
 | 
			
		||||
	return (int)Calc::sign(m_value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
double Binding::timestamp() const
 | 
			
		||||
{
 | 
			
		||||
	return m_last_timestamp;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Binding::update()
 | 
			
		||||
{
 | 
			
		||||
	m_press_consumed = false;
 | 
			
		||||
	m_release_consumed = false;
 | 
			
		||||
 | 
			
		||||
	if (get_pressed())
 | 
			
		||||
	{
 | 
			
		||||
		m_last_timestamp = Time::seconds;
 | 
			
		||||
		m_last_press_time = Time::seconds;
 | 
			
		||||
		m_pressed = true;
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		m_pressed = false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (get_released())
 | 
			
		||||
	{
 | 
			
		||||
		m_last_release_time = Time::seconds;
 | 
			
		||||
		m_released = true;
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		m_released = false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	m_down = get_down();
 | 
			
		||||
	m_value = get_value();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Binding::consume_press()
 | 
			
		||||
{
 | 
			
		||||
	m_press_consumed = true;
 | 
			
		||||
	m_last_press_time = -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Binding::consume_release()
 | 
			
		||||
{
 | 
			
		||||
	m_release_consumed = true;
 | 
			
		||||
	m_last_release_time = -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Binding::add(Key key)
 | 
			
		||||
{
 | 
			
		||||
	keys.push_back(key);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Binding::add(BoundButton button)
 | 
			
		||||
{
 | 
			
		||||
	buttons.push_back(button);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Binding::add(BoundTrigger trigger)
 | 
			
		||||
{
 | 
			
		||||
	triggers.push_back(trigger);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Binding::add(MouseButton button)
 | 
			
		||||
{
 | 
			
		||||
	mouse.push_back(button);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Binding::set_controller(int index)
 | 
			
		||||
{
 | 
			
		||||
	for (auto& it : buttons)
 | 
			
		||||
		it.controller = index;
 | 
			
		||||
	for (auto& it : triggers)
 | 
			
		||||
		it.controller = index;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Binding::clear()
 | 
			
		||||
{
 | 
			
		||||
	keys.clear();
 | 
			
		||||
	buttons.clear();
 | 
			
		||||
	triggers.clear();
 | 
			
		||||
	mouse.clear();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Binding::get_pressed() const
 | 
			
		||||
{
 | 
			
		||||
	for (auto& it : keys)
 | 
			
		||||
		if (Input::pressed(it))
 | 
			
		||||
			return true;
 | 
			
		||||
 | 
			
		||||
	for (auto& it : mouse)
 | 
			
		||||
		if (Input::pressed(it))
 | 
			
		||||
			return true;
 | 
			
		||||
 | 
			
		||||
	for (auto& it : buttons)
 | 
			
		||||
		if (Input::pressed(it.controller, it.button))
 | 
			
		||||
			return true;
 | 
			
		||||
 | 
			
		||||
	for (auto& it : triggers)
 | 
			
		||||
	{
 | 
			
		||||
		if (it.controller < 0 || it.controller >= Input::max_controllers)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if ((int)it.axis < 0 || (int)it.axis >= Input::max_controller_axis)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (it.is_down(Input::state()->controllers[it.controller].axis[(int)it.axis]) &&
 | 
			
		||||
			!it.is_down(Input::last_state()->controllers[it.controller].axis[(int)it.axis]))
 | 
			
		||||
			return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Binding::get_released() const
 | 
			
		||||
{
 | 
			
		||||
	for (auto& it : keys)
 | 
			
		||||
		if (Input::released(it))
 | 
			
		||||
			return true;
 | 
			
		||||
 | 
			
		||||
	for (auto& it : mouse)
 | 
			
		||||
		if (Input::released(it))
 | 
			
		||||
			return true;
 | 
			
		||||
 | 
			
		||||
	for (auto& it : buttons)
 | 
			
		||||
		if (Input::released(it.controller, it.button))
 | 
			
		||||
			return true;
 | 
			
		||||
 | 
			
		||||
	for (auto& it : triggers)
 | 
			
		||||
	{
 | 
			
		||||
		if (it.controller < 0 || it.controller >= Input::max_controllers)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if ((int)it.axis < 0 || (int)it.axis >= Input::max_controller_axis)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (!it.is_down(Input::state()->controllers[it.controller].axis[(int)it.axis]) &&
 | 
			
		||||
			it.is_down(Input::last_state()->controllers[it.controller].axis[(int)it.axis]))
 | 
			
		||||
			return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Binding::get_down() const
 | 
			
		||||
{
 | 
			
		||||
	for (auto& it : keys)
 | 
			
		||||
		if (Input::down(it))
 | 
			
		||||
			return true;
 | 
			
		||||
 | 
			
		||||
	for (auto& it : mouse)
 | 
			
		||||
		if (Input::down(it))
 | 
			
		||||
			return true;
 | 
			
		||||
 | 
			
		||||
	for (auto& it : buttons)
 | 
			
		||||
		if (Input::down(it.controller, it.button))
 | 
			
		||||
			return true;
 | 
			
		||||
 | 
			
		||||
	for (auto& it : triggers)
 | 
			
		||||
	{
 | 
			
		||||
		if (it.controller < 0 || it.controller >= Input::max_controllers)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if ((int)it.axis < 0 || (int)it.axis >= Input::max_controller_axis)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (it.is_down(Input::state()->controllers[it.controller].axis[(int)it.axis]))
 | 
			
		||||
			return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float Binding::get_value() const
 | 
			
		||||
{
 | 
			
		||||
	for (auto& it : keys)
 | 
			
		||||
		if (Input::down(it))
 | 
			
		||||
			return 1.0f;
 | 
			
		||||
 | 
			
		||||
	for (auto& it : mouse)
 | 
			
		||||
		if (Input::down(it))
 | 
			
		||||
			return 1.0f;
 | 
			
		||||
 | 
			
		||||
	for (auto& it : buttons)
 | 
			
		||||
		if (Input::down(it.controller, it.button))
 | 
			
		||||
			return 1.0f;
 | 
			
		||||
 | 
			
		||||
	float highest = 0;
 | 
			
		||||
 | 
			
		||||
	for (auto& it : triggers)
 | 
			
		||||
	{
 | 
			
		||||
		if (it.controller < 0 || it.controller >= Input::max_controllers)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if ((int)it.axis < 0 || (int)it.axis >= Input::max_controller_axis)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		float raw_value = Input::state()->controllers[it.controller].axis[(int)it.axis];
 | 
			
		||||
 | 
			
		||||
		if (it.is_down(raw_value))
 | 
			
		||||
		{
 | 
			
		||||
			float mapped_value = Calc::clamped_map(Calc::abs(raw_value), it.threshold, 1.0f, 0.0f, 1.0f);
 | 
			
		||||
			if (mapped_value > highest)
 | 
			
		||||
				highest = mapped_value;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
		
 | 
			
		||||
	return highest;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float AxisBinding::value() const
 | 
			
		||||
{
 | 
			
		||||
	float neg = negative.value();
 | 
			
		||||
	float pos = positive.value();
 | 
			
		||||
	
 | 
			
		||||
	// neither are down
 | 
			
		||||
	if (neg <= 0 && pos <= 0)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	// negative-only is down
 | 
			
		||||
	if (neg > 0 && pos <= 0)
 | 
			
		||||
		return -neg;
 | 
			
		||||
 | 
			
		||||
	// positive-only is down
 | 
			
		||||
	if (pos > 0 && neg <= 0)
 | 
			
		||||
		return pos;
 | 
			
		||||
 | 
			
		||||
	// both are down:
 | 
			
		||||
 | 
			
		||||
	// overlap cancel out
 | 
			
		||||
	if (overlap == Overlap::Cancel)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	// overlap takes older
 | 
			
		||||
	if (overlap == Overlap::Older)
 | 
			
		||||
	{
 | 
			
		||||
		if (negative.timestamp() < positive.timestamp())
 | 
			
		||||
			return -neg;
 | 
			
		||||
		else
 | 
			
		||||
			return pos;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// overlap takes newer
 | 
			
		||||
	if (negative.timestamp() > positive.timestamp())
 | 
			
		||||
		return -neg;
 | 
			
		||||
	else
 | 
			
		||||
		return pos;		
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int AxisBinding::sign() const
 | 
			
		||||
{
 | 
			
		||||
	return (int)Calc::sign(value());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AxisBinding::update()
 | 
			
		||||
{
 | 
			
		||||
	negative.update();
 | 
			
		||||
	positive.update();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AxisBinding::consume_press()
 | 
			
		||||
{
 | 
			
		||||
	negative.consume_press();
 | 
			
		||||
	positive.consume_press();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AxisBinding::consume_release()
 | 
			
		||||
{
 | 
			
		||||
	negative.consume_release();
 | 
			
		||||
	positive.consume_release();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AxisBinding::add_left_stick_x(int controller, float threshold)
 | 
			
		||||
{
 | 
			
		||||
	negative.add(BoundTrigger::left_stick_left(controller, threshold));
 | 
			
		||||
	positive.add(BoundTrigger::left_stick_right(controller, threshold));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AxisBinding::add_left_stick_y(int controller, float threshold)
 | 
			
		||||
{
 | 
			
		||||
	negative.add(BoundTrigger::left_stick_up(controller, threshold));
 | 
			
		||||
	positive.add(BoundTrigger::left_stick_down(controller, threshold));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AxisBinding::add_right_stick_x(int controller, float threshold)
 | 
			
		||||
{
 | 
			
		||||
	negative.add(BoundTrigger::right_stick_left(controller, threshold));
 | 
			
		||||
	positive.add(BoundTrigger::right_stick_right(controller, threshold));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AxisBinding::add_right_stick_y(int controller, float threshold)
 | 
			
		||||
{
 | 
			
		||||
	negative.add(BoundTrigger::right_stick_up(controller, threshold));
 | 
			
		||||
	positive.add(BoundTrigger::right_stick_down(controller, threshold));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AxisBinding::set_controller(int index)
 | 
			
		||||
{
 | 
			
		||||
	negative.set_controller(index);
 | 
			
		||||
	positive.set_controller(index);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AxisBinding::clear()
 | 
			
		||||
{
 | 
			
		||||
	negative.clear();
 | 
			
		||||
	positive.clear();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Vec2 StickBinding::value() const
 | 
			
		||||
{
 | 
			
		||||
	Vec2 result = Vec2(x.value(), y.value());
 | 
			
		||||
	if (round_threshold > 0 && result.length() < round_threshold)
 | 
			
		||||
		return Vec2::zero;
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Point StickBinding::sign() const
 | 
			
		||||
{
 | 
			
		||||
	Vec2 result = value();
 | 
			
		||||
	return Point((int)Calc::sign(result.x), (int)Calc::sign(result.y));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StickBinding::update()
 | 
			
		||||
{
 | 
			
		||||
	x.update();
 | 
			
		||||
	y.update();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StickBinding::consume_press()
 | 
			
		||||
{
 | 
			
		||||
	x.consume_press();
 | 
			
		||||
	y.consume_press();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StickBinding::consume_release()
 | 
			
		||||
{
 | 
			
		||||
	x.consume_release();
 | 
			
		||||
	y.consume_release();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StickBinding::add_dpad(int controller)
 | 
			
		||||
{
 | 
			
		||||
	x.negative.add(BoundButton(controller, Button::Left));
 | 
			
		||||
	x.positive.add(BoundButton(controller, Button::Right));
 | 
			
		||||
	y.negative.add(BoundButton(controller, Button::Up));
 | 
			
		||||
	y.positive.add(BoundButton(controller, Button::Down));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StickBinding::add_left_stick(int controller, float threshold)
 | 
			
		||||
{
 | 
			
		||||
	x.add_left_stick_x(controller, threshold);
 | 
			
		||||
	y.add_left_stick_y(controller, threshold);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StickBinding::add_right_stick(int controller, float threshold)
 | 
			
		||||
{
 | 
			
		||||
	x.add_right_stick_x(controller, threshold);
 | 
			
		||||
	y.add_right_stick_y(controller, threshold);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StickBinding::set_controller(int index)
 | 
			
		||||
{
 | 
			
		||||
	x.set_controller(index);
 | 
			
		||||
	y.set_controller(index);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StickBinding::clear()
 | 
			
		||||
{
 | 
			
		||||
	x.clear();
 | 
			
		||||
	y.clear();
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										70
									
								
								src/input/binding_registry.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								src/input/binding_registry.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,70 @@
 | 
			
		||||
#include <blah/input/binding_registry.h>
 | 
			
		||||
 | 
			
		||||
using namespace Blah;
 | 
			
		||||
 | 
			
		||||
Vector<std::weak_ptr<Binding>> BindingRegistry::bindings;
 | 
			
		||||
Vector<std::weak_ptr<AxisBinding>> BindingRegistry::axes;
 | 
			
		||||
Vector<std::weak_ptr<StickBinding>> BindingRegistry::sticks;
 | 
			
		||||
 | 
			
		||||
BindingRef BindingRegistry::register_binding()
 | 
			
		||||
{
 | 
			
		||||
	auto binding = std::make_shared<Binding>();
 | 
			
		||||
	bindings.push_back(std::weak_ptr<Binding>(binding));
 | 
			
		||||
	return binding;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AxisBindingRef BindingRegistry::register_axis()
 | 
			
		||||
{
 | 
			
		||||
	auto binding = std::make_shared<AxisBinding>();
 | 
			
		||||
	axes.push_back(std::weak_ptr<AxisBinding>(binding));
 | 
			
		||||
	return binding;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
StickBindingRef BindingRegistry::register_stick()
 | 
			
		||||
{
 | 
			
		||||
	auto binding = std::make_shared<StickBinding>();
 | 
			
		||||
	sticks.push_back(std::weak_ptr<StickBinding>(binding));
 | 
			
		||||
	return binding;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BindingRegistry::update()
 | 
			
		||||
{
 | 
			
		||||
	for (int i = 0; i < bindings.size(); i++)
 | 
			
		||||
	{
 | 
			
		||||
		if (bindings[i].use_count() <= 0)
 | 
			
		||||
		{
 | 
			
		||||
			bindings.erase(i);
 | 
			
		||||
			i--;
 | 
			
		||||
		}
 | 
			
		||||
		else if (auto binding = bindings[i].lock())
 | 
			
		||||
		{
 | 
			
		||||
			binding->update();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (int i = 0; i < axes.size(); i++)
 | 
			
		||||
	{
 | 
			
		||||
		if (axes[i].use_count() <= 0)
 | 
			
		||||
		{
 | 
			
		||||
			axes.erase(i);
 | 
			
		||||
			i--;
 | 
			
		||||
		}
 | 
			
		||||
		else if (auto binding = axes[i].lock())
 | 
			
		||||
		{
 | 
			
		||||
			binding->update();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (int i = 0; i < sticks.size(); i++)
 | 
			
		||||
	{
 | 
			
		||||
		if (sticks[i].use_count() <= 0)
 | 
			
		||||
		{
 | 
			
		||||
			sticks.erase(i);
 | 
			
		||||
			i--;
 | 
			
		||||
		}
 | 
			
		||||
		else if (auto binding = sticks[i].lock())
 | 
			
		||||
		{
 | 
			
		||||
			binding->update();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -1,4 +1,5 @@
 | 
			
		||||
#include <blah/input/input.h>
 | 
			
		||||
#include <blah/input/binding_registry.h>
 | 
			
		||||
#include <blah/core/app.h>
 | 
			
		||||
#include <blah/core/time.h>
 | 
			
		||||
#include <blah/core/common.h>
 | 
			
		||||
@ -66,6 +67,9 @@ void InputBackend::frame()
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// update bindings
 | 
			
		||||
	BindingRegistry::update();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void InputBackend::on_mouse_move(float x, float y)
 | 
			
		||||
 | 
			
		||||
@ -1,166 +0,0 @@
 | 
			
		||||
#include <blah/input/virtual_axis.h>
 | 
			
		||||
#include <blah/core/time.h>
 | 
			
		||||
#include <blah/core/common.h>
 | 
			
		||||
 | 
			
		||||
using namespace Blah;
 | 
			
		||||
 | 
			
		||||
VirtualAxis& VirtualAxis::add_keys(Key negative, Key positive)
 | 
			
		||||
{
 | 
			
		||||
	if (m_axes_len >= Input::max_virtual_nodes)
 | 
			
		||||
		BLAH_ERROR("VirtualAxis Keys out of bounds!");
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		m_keys[m_keys_len].init(negative, positive);
 | 
			
		||||
		m_keys_len++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VirtualAxis& VirtualAxis::add_buttons(int gamepad_id, Button negative, Button positive)
 | 
			
		||||
{
 | 
			
		||||
	if (m_axes_len >= Input::max_virtual_nodes)
 | 
			
		||||
		BLAH_ERROR("VirtualAxis Buttons out of bounds!");
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		m_buttons[m_buttons_len].init(gamepad_id, negative, positive);
 | 
			
		||||
		m_buttons_len++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VirtualAxis& VirtualAxis::add_axis(int gamepad_id, Axis axis, float deadzone)
 | 
			
		||||
{
 | 
			
		||||
	if (m_axes_len >= Input::max_virtual_nodes)
 | 
			
		||||
		BLAH_ERROR("VirtualAxis Axes out of bounds!");
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		m_axes[m_axes_len].init(gamepad_id, axis, deadzone);
 | 
			
		||||
		m_axes_len++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VirtualAxis& VirtualAxis::repeat(float m_repeat_delay, float m_repeat_interval)
 | 
			
		||||
{
 | 
			
		||||
	this->m_repeat_delay = m_repeat_delay;
 | 
			
		||||
	this->m_repeat_interval = m_repeat_interval;
 | 
			
		||||
	return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VirtualAxis& VirtualAxis::press_buffer(float duration)
 | 
			
		||||
{
 | 
			
		||||
	this->m_press_buffer = duration;
 | 
			
		||||
	return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VirtualAxis& VirtualAxis::release_buffer(float duration)
 | 
			
		||||
{
 | 
			
		||||
	this->m_release_buffer = duration;
 | 
			
		||||
	return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VirtualAxis::update()
 | 
			
		||||
{
 | 
			
		||||
	m_last_value = m_value;
 | 
			
		||||
	m_value = 0;
 | 
			
		||||
 | 
			
		||||
	for (int i = 0; i < m_keys_len; i++)
 | 
			
		||||
	{
 | 
			
		||||
		m_keys[i].update();
 | 
			
		||||
		if (m_value == 0)
 | 
			
		||||
			m_value = (float)m_keys[i].value;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (int i = 0; i < m_buttons_len; i++)
 | 
			
		||||
	{
 | 
			
		||||
		m_buttons[i].update();
 | 
			
		||||
		if (m_value == 0)
 | 
			
		||||
			m_value = (float)m_buttons[i].value;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (int i = 0; i < m_axes_len; i++)
 | 
			
		||||
	{
 | 
			
		||||
		m_axes[i].update();
 | 
			
		||||
		if (m_value == 0)
 | 
			
		||||
			m_value = m_axes[i].value;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	//Valuei
 | 
			
		||||
	m_last_value_i = m_value_i;
 | 
			
		||||
	if (m_value > 0)
 | 
			
		||||
		m_value_i = 1;
 | 
			
		||||
	else if (m_value < 0)
 | 
			
		||||
		m_value_i = -1;
 | 
			
		||||
	else
 | 
			
		||||
		m_value_i = 0;
 | 
			
		||||
 | 
			
		||||
	//pressed?
 | 
			
		||||
	m_pressed = false;
 | 
			
		||||
	if (m_value_i != 0 && m_last_value_i != m_value_i)
 | 
			
		||||
	{
 | 
			
		||||
		m_pressed = true;
 | 
			
		||||
		m_last_press_time = m_repeat_press_time = Time::seconds;
 | 
			
		||||
	}
 | 
			
		||||
	else if (m_value_i == m_last_value_i && m_value_i != 0)
 | 
			
		||||
	{
 | 
			
		||||
		if (Time::seconds - m_last_press_time <= m_press_buffer)
 | 
			
		||||
			m_pressed = true;
 | 
			
		||||
		else if (m_repeat_interval > 0 && Time::seconds >= m_repeat_press_time + m_repeat_delay)
 | 
			
		||||
		{
 | 
			
		||||
			int prev = (int)((Time::previous_seconds - m_repeat_press_time - m_repeat_delay) / m_repeat_interval);
 | 
			
		||||
			int cur = (int)((Time::seconds - m_repeat_press_time - m_repeat_delay) / m_repeat_interval);
 | 
			
		||||
			m_pressed = prev < cur;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	//released?
 | 
			
		||||
	if (m_last_value_i != 0 && m_value_i != m_last_value_i)
 | 
			
		||||
	{
 | 
			
		||||
		m_released = true;
 | 
			
		||||
		m_last_release_time = Time::seconds;
 | 
			
		||||
	}
 | 
			
		||||
	else if (Time::seconds - m_last_release_time <= m_release_buffer)
 | 
			
		||||
		m_released = true;
 | 
			
		||||
	else
 | 
			
		||||
		m_released = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VirtualAxis::KeysNode::init(Key negative, Key positive)
 | 
			
		||||
{
 | 
			
		||||
	this->negative = negative;
 | 
			
		||||
	this->positive = positive;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VirtualAxis::KeysNode::update()
 | 
			
		||||
{
 | 
			
		||||
	value = Input::axis_check(value, negative, positive);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VirtualAxis::ButtonsNode::init(int gamepad_id, Button negative, Button positive)
 | 
			
		||||
{
 | 
			
		||||
	this->gamepad_id = gamepad_id;
 | 
			
		||||
	this->negative = negative;
 | 
			
		||||
	this->positive = positive;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VirtualAxis::ButtonsNode::update()
 | 
			
		||||
{
 | 
			
		||||
	value = Input::axis_check(value, gamepad_id, negative, positive);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VirtualAxis::AxisNode::init(int gamepad_id, Axis axis, float deadzone)
 | 
			
		||||
{
 | 
			
		||||
	this->gamepad_id = gamepad_id;
 | 
			
		||||
	this->axis = axis;
 | 
			
		||||
	this->deadzone = deadzone;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VirtualAxis::AxisNode::update()
 | 
			
		||||
{
 | 
			
		||||
	value = Input::axis_check(gamepad_id, axis);
 | 
			
		||||
	if (value < deadzone && value > -deadzone)
 | 
			
		||||
		value = 0;
 | 
			
		||||
}
 | 
			
		||||
@ -1,174 +0,0 @@
 | 
			
		||||
#include <blah/input/virtual_button.h>
 | 
			
		||||
#include <blah/core/time.h>
 | 
			
		||||
#include <blah/core/common.h>
 | 
			
		||||
 | 
			
		||||
using namespace Blah;
 | 
			
		||||
 | 
			
		||||
VirtualButton& VirtualButton::add_key(Key key)
 | 
			
		||||
{
 | 
			
		||||
	if (m_keys_len >= Input::max_virtual_nodes)
 | 
			
		||||
		BLAH_ERROR("VirtualButton Keys out of bounds!");
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		m_keys[m_keys_len].init(key);
 | 
			
		||||
		m_keys_len++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VirtualButton& VirtualButton::add_button(int gamepad_id, Button button)
 | 
			
		||||
{
 | 
			
		||||
	if (m_buttons_len >= Input::max_virtual_nodes)
 | 
			
		||||
		BLAH_ERROR("VirtualButton Buttons out of bounds!");
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		m_buttons[m_buttons_len].init(gamepad_id, button);
 | 
			
		||||
		m_buttons_len++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VirtualButton& VirtualButton::add_axis(int gamepad_id, Axis axis, float threshold, bool greater_than)
 | 
			
		||||
{
 | 
			
		||||
	if (m_axes_len >= Input::max_virtual_nodes)
 | 
			
		||||
		BLAH_ERROR("VirtualButton Axes out of bounds!");
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		m_axes[m_axes_len].init(gamepad_id, axis, threshold, greater_than);
 | 
			
		||||
		m_axes_len++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VirtualButton& VirtualButton::repeat(float m_repeat_delay, float m_repeat_interval)
 | 
			
		||||
{
 | 
			
		||||
	this->m_repeat_delay = m_repeat_delay;
 | 
			
		||||
	this->m_repeat_interval = m_repeat_interval;
 | 
			
		||||
	return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VirtualButton& VirtualButton::press_buffer(float duration)
 | 
			
		||||
{
 | 
			
		||||
	this->m_press_buffer = duration;
 | 
			
		||||
	return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VirtualButton& VirtualButton::release_buffer(float duration)
 | 
			
		||||
{
 | 
			
		||||
	this->m_release_buffer = duration;
 | 
			
		||||
	return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VirtualButton::update()
 | 
			
		||||
{
 | 
			
		||||
	m_down = false;
 | 
			
		||||
	m_pressed = false;
 | 
			
		||||
	m_released = false;
 | 
			
		||||
 | 
			
		||||
	// Keys
 | 
			
		||||
	for (int i = 0; i < m_keys_len; i++)
 | 
			
		||||
	{
 | 
			
		||||
		m_keys[i].update();
 | 
			
		||||
 | 
			
		||||
		m_down = m_down || m_keys[i].down;
 | 
			
		||||
		m_pressed = m_pressed || m_keys[i].pressed;
 | 
			
		||||
		m_released = m_released || m_keys[i].released;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Buttons
 | 
			
		||||
	for (int i = 0; i < m_buttons_len; i++)
 | 
			
		||||
	{
 | 
			
		||||
		m_buttons[i].update();
 | 
			
		||||
 | 
			
		||||
		m_down = m_down || m_buttons[i].down;
 | 
			
		||||
		m_pressed = m_pressed || m_buttons[i].pressed;
 | 
			
		||||
		m_released = m_released || m_buttons[i].released;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Axes
 | 
			
		||||
	for (int i = 0; i < m_axes_len; i++)
 | 
			
		||||
	{
 | 
			
		||||
		m_axes[i].update();
 | 
			
		||||
 | 
			
		||||
		m_down = m_down || m_axes[i].down;
 | 
			
		||||
		m_pressed = m_pressed || m_axes[i].pressed;
 | 
			
		||||
		m_released = m_released || m_axes[i].released;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// pressed?
 | 
			
		||||
	if (m_pressed)
 | 
			
		||||
	{
 | 
			
		||||
		m_repeat_press_time = m_last_press_time = Time::seconds;
 | 
			
		||||
	}
 | 
			
		||||
	else if (Time::seconds - m_last_press_time <= m_press_buffer)
 | 
			
		||||
	{
 | 
			
		||||
		m_pressed = true;
 | 
			
		||||
	}
 | 
			
		||||
	else if (m_down && m_repeat_interval > 0 && Time::seconds >= m_repeat_press_time + m_repeat_delay)
 | 
			
		||||
	{
 | 
			
		||||
		int prev = (int)((Time::previous_seconds - m_repeat_press_time - m_repeat_delay) / m_repeat_interval);
 | 
			
		||||
		int cur = (int)((Time::seconds - m_repeat_press_time - m_repeat_delay) / m_repeat_interval);
 | 
			
		||||
		m_pressed = prev < cur;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// released?
 | 
			
		||||
	if (m_released)
 | 
			
		||||
		m_last_release_time = Time::seconds;
 | 
			
		||||
	else
 | 
			
		||||
		m_released = Time::seconds - m_last_release_time <= m_release_buffer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VirtualButton::KeyNode::init(Key key)
 | 
			
		||||
{
 | 
			
		||||
	this->key = key;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VirtualButton::KeyNode::update()
 | 
			
		||||
{
 | 
			
		||||
	down = Input::down(key);
 | 
			
		||||
	pressed = Input::pressed(key);
 | 
			
		||||
	released = Input::released(key);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VirtualButton::ButtonNode::init(int gamepad_id, Button button)
 | 
			
		||||
{
 | 
			
		||||
	this->gamepad_id = gamepad_id;
 | 
			
		||||
	this->button = button;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VirtualButton::ButtonNode::update()
 | 
			
		||||
{
 | 
			
		||||
	down = Input::down(gamepad_id, button);
 | 
			
		||||
	pressed = Input::pressed(gamepad_id, button);
 | 
			
		||||
	released = Input::released(gamepad_id, button);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VirtualButton::AxisNode::init(int gamepad_id, Axis axis, float threshold, bool greater_than)
 | 
			
		||||
{
 | 
			
		||||
	this->gamepad_id = gamepad_id;
 | 
			
		||||
	this->axis = axis;
 | 
			
		||||
	this->threshold = threshold;
 | 
			
		||||
	this->greater_than = greater_than;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VirtualButton::AxisNode::update()
 | 
			
		||||
{
 | 
			
		||||
	float curr = Input::state()->controllers[gamepad_id].axis[(int)axis];
 | 
			
		||||
	float prev = Input::last_state()->controllers[gamepad_id].axis[(int)axis];
 | 
			
		||||
 | 
			
		||||
	if (greater_than)
 | 
			
		||||
	{
 | 
			
		||||
		down = curr >= threshold;
 | 
			
		||||
		pressed = down && prev < threshold;
 | 
			
		||||
		released = !down && prev >= threshold;
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		down = curr <= threshold;
 | 
			
		||||
		pressed = down && prev > threshold;
 | 
			
		||||
		released = !down && prev <= threshold;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -1,191 +0,0 @@
 | 
			
		||||
#include <blah/input/virtual_stick.h>
 | 
			
		||||
#include <blah/core/time.h>
 | 
			
		||||
#include <blah/core/common.h>
 | 
			
		||||
 | 
			
		||||
using namespace Blah;
 | 
			
		||||
 | 
			
		||||
VirtualStick::VirtualStick()
 | 
			
		||||
{
 | 
			
		||||
	this->m_i_deadzone = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VirtualStick::VirtualStick(float iDeadzone)
 | 
			
		||||
{
 | 
			
		||||
	this->m_i_deadzone = iDeadzone;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VirtualStick& VirtualStick::add_keys(Key left, Key right, Key up, Key down)
 | 
			
		||||
{
 | 
			
		||||
	if (m_keys_len >= Input::max_virtual_nodes)
 | 
			
		||||
		BLAH_ERROR("VirtualStick Keys out of bounds!");
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		m_keys[m_keys_len].init(left, right, up, down);
 | 
			
		||||
		m_keys_len++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VirtualStick& VirtualStick::add_buttons(int gamepad_id, Button left, Button right, Button up, Button down)
 | 
			
		||||
{
 | 
			
		||||
	if (m_buttons_len >= Input::max_virtual_nodes)
 | 
			
		||||
		BLAH_ERROR("VirtualStick Buttons out of bounds!");
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		m_buttons[m_buttons_len].init(gamepad_id, left, right, up, down);
 | 
			
		||||
		m_buttons_len++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VirtualStick& VirtualStick::add_axes(int gamepad_id, Axis horizontal, Axis vertical, float deadzone)
 | 
			
		||||
{
 | 
			
		||||
	if (m_axes_len >= Input::max_virtual_nodes)
 | 
			
		||||
		BLAH_ERROR("VirtualStick Axes out of bounds!");
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		m_axes[m_axes_len].init(gamepad_id, horizontal, vertical, deadzone);
 | 
			
		||||
		m_axes_len++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VirtualStick& VirtualStick::repeat(float repeat_delay, float repeat_interval)
 | 
			
		||||
{
 | 
			
		||||
	this->m_repeat_delay = repeat_delay;
 | 
			
		||||
	this->m_repeat_interval = repeat_interval;
 | 
			
		||||
	return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VirtualStick& VirtualStick::press_buffer(float duration)
 | 
			
		||||
{
 | 
			
		||||
	m_press_buffer = duration;
 | 
			
		||||
	return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VirtualStick& VirtualStick::release_buffer(float duration)
 | 
			
		||||
{
 | 
			
		||||
	m_release_buffer = duration;
 | 
			
		||||
	return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VirtualStick::update()
 | 
			
		||||
{
 | 
			
		||||
	m_last_value = m_value;
 | 
			
		||||
	m_value = Vec2::zero;
 | 
			
		||||
 | 
			
		||||
	for (int i = 0; i < m_keys_len; i++)
 | 
			
		||||
	{
 | 
			
		||||
		m_keys[i].update();
 | 
			
		||||
		if (m_value == Vec2::zero)
 | 
			
		||||
			m_value = m_keys[i].value;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (int i = 0; i < m_buttons_len; i++)
 | 
			
		||||
	{
 | 
			
		||||
		m_buttons[i].update();
 | 
			
		||||
		if (m_value == Vec2::zero)
 | 
			
		||||
			m_value = m_buttons[i].value;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (int i = 0; i < m_axes_len; i++)
 | 
			
		||||
	{
 | 
			
		||||
		m_axes[i].update();
 | 
			
		||||
		if (m_value == Vec2::zero)
 | 
			
		||||
			m_value = m_axes[i].value;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	//Valuei
 | 
			
		||||
	m_last_value_i = m_value_i;
 | 
			
		||||
	if (m_value.x > m_i_deadzone)
 | 
			
		||||
		m_value_i.x = 1;
 | 
			
		||||
	else if (m_value.x < -m_i_deadzone)
 | 
			
		||||
		m_value_i.x = -1;
 | 
			
		||||
	else
 | 
			
		||||
		m_value_i.x = 0;
 | 
			
		||||
	if (m_value.y > m_i_deadzone)
 | 
			
		||||
		m_value_i.y = 1;
 | 
			
		||||
	else if (m_value.y < -m_i_deadzone)
 | 
			
		||||
		m_value_i.y = -1;
 | 
			
		||||
	else
 | 
			
		||||
		m_value_i.y = 0;
 | 
			
		||||
 | 
			
		||||
	//pressed?
 | 
			
		||||
	m_pressed = false;
 | 
			
		||||
	if (m_value_i != Point::zero && m_last_value_i != m_value_i)
 | 
			
		||||
	{
 | 
			
		||||
		m_pressed = true;
 | 
			
		||||
		m_last_press_time = m_repeat_press_time = Time::seconds;
 | 
			
		||||
	}
 | 
			
		||||
	else if (m_value_i == m_last_value_i && m_value_i != Point::zero)
 | 
			
		||||
	{
 | 
			
		||||
		if (Time::seconds - m_last_press_time <= m_press_buffer)
 | 
			
		||||
			m_pressed = true;
 | 
			
		||||
		else if (m_repeat_interval > 0 && Time::seconds >= m_repeat_press_time + m_repeat_delay)
 | 
			
		||||
		{
 | 
			
		||||
			int prev = (int)((Time::previous_seconds - m_repeat_press_time - m_repeat_delay) / m_repeat_interval);
 | 
			
		||||
			int cur = (int)((Time::seconds - m_repeat_press_time - m_repeat_delay) / m_repeat_interval);
 | 
			
		||||
			m_pressed = prev < cur;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	//released?
 | 
			
		||||
	if (m_last_value_i != Point::zero && m_value_i != m_last_value_i)
 | 
			
		||||
	{
 | 
			
		||||
		m_released = true;
 | 
			
		||||
		m_last_release_time = Time::seconds;
 | 
			
		||||
	}
 | 
			
		||||
	else if (Time::seconds - m_last_release_time <= m_release_buffer)
 | 
			
		||||
		m_released = true;
 | 
			
		||||
	else
 | 
			
		||||
		m_released = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VirtualStick::KeysNode::init(Key left, Key right, Key up, Key down)
 | 
			
		||||
{
 | 
			
		||||
	this->left = left;
 | 
			
		||||
	this->right = right;
 | 
			
		||||
	this->up = up;
 | 
			
		||||
	this->down = down;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VirtualStick::KeysNode::update()
 | 
			
		||||
{
 | 
			
		||||
	value.x = Input::axis_check(value.x, left, right);
 | 
			
		||||
	value.y = Input::axis_check(value.y, up, down);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VirtualStick::ButtonsNode::init(int gamepad_id, Button left, Button right, Button up, Button down)
 | 
			
		||||
{
 | 
			
		||||
	this->gamepad_id = gamepad_id;
 | 
			
		||||
	this->left = left;
 | 
			
		||||
	this->right = right;
 | 
			
		||||
	this->up = up;
 | 
			
		||||
	this->down = down;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VirtualStick::ButtonsNode::update()
 | 
			
		||||
{
 | 
			
		||||
	value.x = Input::axis_check(value.x, gamepad_id, left, right);
 | 
			
		||||
	value.y = Input::axis_check(value.y, gamepad_id, up, down);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VirtualStick::AxesNode::init(int gamepad_id, Axis horizontal, Axis vertical, float deadzone)
 | 
			
		||||
{
 | 
			
		||||
	this->gamepad_id = gamepad_id;
 | 
			
		||||
	this->horizontal = horizontal;
 | 
			
		||||
	this->vertical = vertical;
 | 
			
		||||
	this->deadzone = deadzone;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VirtualStick::AxesNode::update()
 | 
			
		||||
{
 | 
			
		||||
	value.x = Input::axis_check(gamepad_id, horizontal);
 | 
			
		||||
	value.y = Input::axis_check(gamepad_id, vertical);
 | 
			
		||||
 | 
			
		||||
	if (value.length() < deadzone)
 | 
			
		||||
		value = Vec2::zero;
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user