Wizard Engine
2D cross-platform game engine built around SDL2
 
Loading...
Searching...
No Matches
input.cpp
1/*
2 Wizard Engine
3 Copyright (C) 2023-2024 Zana Domán
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21
22// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
23#define __WIZARD_ENGINE_INTERNAL__
24
33
34SDL_Keycode wze::input::_key = SDLK_UNKNOWN;
35std::array<bool, wze::KEY_COUNT> wze::input::_keys = {};
36std::unordered_map<std::string, std::vector<wze::key>> wze::input::_keymaps;
37float wze::input::_cursor_absolute_x = 0;
38float wze::input::_cursor_absolute_y = 0;
39float wze::input::_cursor_relative_x = 0;
40float wze::input::_cursor_relative_y = 0;
41float wze::input::_mouse_sensitivity = 1;
42std::unordered_map<size_t, wze::finger> wze::input::_fingers;
43std::optional<wze::gesture> wze::input::_gesture;
44std::unique_ptr<SDL_Sensor, std::function<void(SDL_Sensor*)>>
45 wze::input::_accelerometer;
46std::array<float, 3> wze::input::_accelerometer_xyz = {};
47
48void wze::input::update_key() {
49 std::vector<SDL_Event>::const_reverse_iterator iterator;
50
51 _key = SDLK_UNKNOWN;
52 for (iterator = engine::events().rbegin();
53 iterator != engine::events().rend(); ++iterator) {
54 if (iterator->type == SDL_KEYDOWN) {
55 _key = iterator->key.keysym.sym;
56 break;
57 }
58 }
59}
60
61void wze::input::update_keys() {
62 uint8_t const* keyboard_keys;
63 uint32_t mouse_keys;
64 std::vector<SDL_Event>::const_reverse_iterator iterator;
65
66 static_assert((size_t)KEY_COUNT <= (size_t)SDL_NUM_SCANCODES);
67 keyboard_keys = SDL_GetKeyboardState(nullptr);
68 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
69 std::copy(keyboard_keys, keyboard_keys + KEY_COUNT, _keys.data());
70
71 mouse_keys = SDL_GetMouseState(nullptr, nullptr);
72 _keys.at(KEY_MOUSE_LEFT) = (bool)(mouse_keys & SDL_BUTTON_LMASK);
73 _keys.at(KEY_MOUSE_MIDDLE) = (bool)(mouse_keys & SDL_BUTTON_MMASK);
74 _keys.at(KEY_MOUSE_RIGHT) = (bool)(mouse_keys & SDL_BUTTON_RMASK);
75 _keys.at(KEY_MOUSE_X1) = (bool)(mouse_keys & SDL_BUTTON_X1MASK);
76 _keys.at(KEY_MOUSE_X2) = (bool)(mouse_keys & SDL_BUTTON_X2MASK);
77
78 _keys.at(KEY_MOUSE_WHEEL_DOWN) = false;
79 _keys.at(KEY_MOUSE_WHEEL_UP) = false;
80 for (iterator = engine::events().rbegin();
81 iterator != engine::events().rend(); ++iterator) {
82 if (iterator->type == SDL_MOUSEWHEEL) {
83 if (iterator->wheel.y < 0) {
84 _keys.at(KEY_MOUSE_WHEEL_DOWN) = true;
85 } else if (0 < iterator->wheel.y) {
86 _keys.at(KEY_MOUSE_WHEEL_UP) = true;
87 }
88 break;
89 }
90 }
91}
92
93void wze::input::update_cursor() {
94 std::vector<SDL_Event>::const_reverse_iterator iterator;
95 int32_t x;
96 int32_t y;
97
98 for (iterator = engine::events().rbegin();
99 iterator != engine::events().rend(); ++iterator) {
100 if (iterator->type == SDL_MOUSEMOTION) {
101 _cursor_absolute_x =
102 (float)std::clamp(iterator->motion.x, 0, window::width() - 1);
103 _cursor_absolute_y =
104 (float)std::clamp(iterator->motion.y, 0, window::height() - 1);
105 std::tie(_cursor_absolute_x, _cursor_absolute_y) =
106 renderer::detransform(cursor_absolute_x(), cursor_absolute_y());
107 break;
108 }
109 }
110
111 SDL_GetRelativeMouseState(&x, &y);
112 _cursor_relative_x = (float)x * mouse_sensitivity();
113 _cursor_relative_y = (float)y * mouse_sensitivity();
114}
115
116void wze::input::update_fingers() {
117 std::vector<SDL_Event>::const_iterator iterator;
118
119 std::for_each(_fingers.begin(), _fingers.end(),
120 [](std::pair<size_t const, finger>& finger) -> void {
121 finger.second.relative_x = 0;
122 finger.second.relative_y = 0;
123 });
124
125 for (iterator = engine::events().begin();
126 iterator != engine::events().end(); ++iterator) {
127 // NOLINTNEXTLINE(bugprone-switch-missing-default-case)
128 switch (iterator->type) {
129 case SDL_FINGERUP:
130 _fingers.erase(iterator->tfinger.fingerId);
131 break;
132 case SDL_FINGERDOWN:
133 case SDL_FINGERMOTION:
134 finger& finger = _fingers[iterator->tfinger.fingerId];
135 std::tie(finger.absolute_x, finger.absolute_y) =
136 renderer::detransform(
137 iterator->tfinger.x * (float)window::width(),
138 iterator->tfinger.y * (float)window::height());
139 finger.relative_x += iterator->tfinger.dx * (float)window::width();
140 finger.relative_y += iterator->tfinger.dy * (float)window::height();
141 }
142 }
143}
144
145void wze::input::update_gesture() {
146 std::vector<SDL_Event>::const_iterator iterator;
147
148 _gesture = std::nullopt;
149 for (iterator = engine::events().begin();
150 iterator != engine::events().end(); ++iterator) {
151 if (iterator->type == SDL_MULTIGESTURE) {
152 if (!_gesture) {
153 _gesture = wze::gesture();
154 }
155 std::apply(
156 [&](float x, float y) -> void {
157 _gesture->x = x;
158 _gesture->y = y;
159 _gesture->length += iterator->mgesture.dDist;
160 _gesture->angle += iterator->mgesture.dTheta;
161 },
162 renderer::detransform(
163 iterator->mgesture.x * (float)window::width(),
164 iterator->mgesture.y * (float)window::height()));
165 }
166 }
167}
168
169void wze::input::update_accelerometer() {
170 if (!_accelerometer) {
171 return;
172 }
173 if ((bool)SDL_SensorGetData(_accelerometer.get(), _accelerometer_xyz.data(),
174 _accelerometer_xyz.size())) {
175 throw exception(SDL_GetError());
176 }
177 std::for_each(_accelerometer_xyz.begin(), _accelerometer_xyz.end(),
178 [](float& axis) -> void {
179 axis *= math::pi() / SDL_STANDARD_GRAVITY;
180 });
181}
182
183bool wze::input::text_input() {
184 return (bool)SDL_IsTextInputActive();
185}
186
187void wze::input::set_text_input(bool text_input) {
188 if (text_input) {
189 SDL_StartTextInput();
190 } else {
191 SDL_StopTextInput();
192 }
193}
194
195uint32_t wze::input::key() {
196 return _key;
197}
198
199std::unordered_map<std::string, std::vector<wze::key>>& wze::input::keymaps() {
200 return _keymaps;
201}
202
203float wze::input::cursor_absolute_x() {
204 return _cursor_absolute_x;
205}
206
207float wze::input::cursor_absolute_y() {
208 return _cursor_absolute_y;
209}
210
211float wze::input::cursor_relative_x() {
212 return _cursor_relative_x;
213}
214
215float wze::input::cursor_relative_y() {
216 return _cursor_relative_y;
217}
218
219float wze::input::mouse_sensitivity() {
220 return _mouse_sensitivity;
221}
222
223void wze::input::set_mouse_sensitivity(float mouse_sensitivity) {
224 _mouse_sensitivity = mouse_sensitivity;
225}
226
227bool wze::input::cursor_visible() {
228 return (bool)SDL_GetRelativeMouseMode();
229}
230
231void wze::input::set_cursor_visible(bool cursor_visible) {
232 if ((bool)SDL_SetRelativeMouseMode((SDL_bool)!cursor_visible)) {
233 throw exception(SDL_GetError());
234 }
235}
236
237void wze::input::set_cursor_appearance(
238 std::unique_ptr<cursor, std::function<void(cursor*)>> cursor_appearance) {
239 SDL_SetCursor(cursor_appearance.release());
240}
241
242std::unordered_map<size_t, wze::finger> const& wze::input::fingers() {
243 return _fingers;
244}
245
246std::optional<wze::gesture> const& wze::input::gesture() {
247 return _gesture;
248}
249
250float wze::input::accelerometer_x() {
251 return _accelerometer_xyz.at(1);
252}
253
254float wze::input::accelerometer_y() {
255 return _accelerometer_xyz.at(0);
256}
257
258float wze::input::accelerometer_z() {
259 return _accelerometer_xyz.at(2);
260}
261
262void wze::input::initialize() {
263 int32_t sensor_count;
264 int32_t sensor;
265
266 sensor_count = SDL_NumSensors();
267 for (sensor = 0; sensor != sensor_count; ++sensor) {
268 if (SDL_SensorGetDeviceType(sensor) == SDL_SENSOR_ACCEL) {
269 _accelerometer = {SDL_SensorOpen(sensor), SDL_SensorClose};
270 if (!_accelerometer) {
271 throw exception(SDL_GetError());
272 }
273 }
274 }
275}
276
277void wze::input::update() {
278 update_key();
279 update_keys();
280 update_cursor();
281 update_fingers();
282 update_gesture();
283 update_accelerometer();
284}
285
286bool wze::input::key(enum key key) {
287 return _keys.at(key);
288}
289
290bool wze::input::key(std::string const& name) {
291 std::vector<enum key>& keys = keymaps().at(name);
292 return std::any_of(keys.begin(), keys.end(), [](enum key key) -> bool {
293 return input::key(key);
294 });
295}
296
297std::pair<float, float> wze::input::cursor_spatial(float z) {
298 return camera::unproject(cursor_absolute_x(), cursor_absolute_y(), z);
299}
Subsystem to handle transformations and spatial projections.
Master singleton of the Wizard Engine.
Generic exception.
Touchscreen finger data.
Math modul.
key
Keys.
Definition enums.hpp:72
Subsystem to handle graphics.
Timer modul.
Subsystem to handle game window.