The Battle for Wesnoth  1.13.11+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
joystick.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2011 - 2018 by Fabian Mueller
3  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #include "joystick.hpp"
16 #include "preferences/general.hpp"
17 #include "log.hpp"
18 #include "sdl/surface.hpp"
19 #include "utils/math.hpp"
20 #include <boost/math/constants/constants.hpp>
21 using namespace boost::math::constants;
22 
23 static lg::log_domain log_joystick("joystick");
24 #define ERR_JOY LOG_STREAM(err, log_joystick)
25 #define LOG_JOY LOG_STREAM(info, log_joystick)
26 #define DBG_JOY LOG_STREAM(debug, log_joystick)
27 
29  : joysticks_()
30  , joystick_area_(0)
31  , counter_(0)
32 {
33  init();
34 }
35 
37  close();
38 }
39 
40 
41 static bool attached(
42  const std::vector<SDL_Joystick*>& joysticks
43  , const size_t index)
44 {
45  return SDL_JoystickGetAttached(joysticks[index]) == SDL_TRUE;
46 }
47 
48 static const char* name(
49  const std::vector<SDL_Joystick*>& joysticks
50  , const size_t index)
51 {
52  return SDL_JoystickName(joysticks[index]);
53 }
54 
55 
57  if(SDL_WasInit(SDL_INIT_JOYSTICK) == 0)
58  return true;
59 
60  int joysticks = joysticks_.size();
61  bool all_closed = true;
62 
63  for (int i = 0; i<joysticks; i++) {
64  if (attached(joysticks_, i)) {
65  SDL_JoystickClose(joysticks_[i]);
66  LOG_JOY << "Closed Joystick" << i;
67  LOG_JOY << "Name: " << name(joysticks_, i);
68  } else {
69  ERR_JOY << "Joystick" << i << " closing failed.";
70  all_closed = false;
71  }
72  }
73 
74  joysticks_.clear();
75  return all_closed;
76 }
77 
79 
80  close();
81 
83  LOG_JOY << "Joystick support is disabled.";
84  return false;
85  }
86 
87  LOG_JOY << "Initializing joysticks...\n";
88  if(SDL_WasInit(SDL_INIT_JOYSTICK) == 0)
89  if(SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1)
90  return false;
91 
92  joysticks_.clear();
93 
94  int joysticks = SDL_NumJoysticks();
95  if (joysticks == 0) return false;
96 
97  SDL_JoystickEventState(SDL_ENABLE);
98 
99  bool joystick_found = false;
100  for (int i = 0; i<joysticks; i++) {
101  joysticks_.resize(i+1);
102  joysticks_[i] = SDL_JoystickOpen(i);
103 
104  if (joysticks_[i] && attached(joysticks_, i)) {
105 
106  joystick_found = true;
107 
108  LOG_JOY << "Opened Joystick" << i;
109  LOG_JOY << "Name: " << name(joysticks_, i);
110  LOG_JOY << "Number of Axes: " << SDL_JoystickNumAxes(joysticks_[i]);
111  LOG_JOY << "Number of Buttons: " << SDL_JoystickNumButtons(joysticks_[i]);
112  LOG_JOY << "Number of Balls: " << SDL_JoystickNumBalls(joysticks_[i]);
113  LOG_JOY << "Number of Hats: ", SDL_JoystickNumHats(joysticks_[i]);
114  } else {
115  ERR_JOY << "Couldn't open Joystick" << i;
116  }
117  }
118  return joystick_found;
119 }
120 
121 std::pair<double, double> joystick_manager::get_mouse_axis_pair() {
122 
123  const int mouse_joystick_x = preferences::joystick_num_mouse_xaxis();
124  const int mouse_xaxis = preferences::joystick_mouse_xaxis_num();
125 
126  const int mouse_joystick_y = preferences::joystick_num_mouse_yaxis();
127  const int mouse_yaxis = preferences::joystick_mouse_yaxis_num();
128 
129  std::pair<int, int> values;
130  double thrust;
131  {
132  values = get_axis_pair(mouse_joystick_x, mouse_xaxis, mouse_joystick_y, mouse_yaxis);
133  thrust = get_thrusta_axis();
134  }
135 
136  const int radius = round_double(sqrt(pow(values.first, 2.0f) + pow(values.second, 2.0f)));
137  const int deadzone = preferences::joystick_mouse_deadzone();
138  const double multiplier = 1.0 + thrust;
139 
140  if (deadzone > radius)
141  return std::make_pair(0.0, 0.0);
142 
143  // TODO do some math to normalize over the value - deadzone.
144  //const double relation = std::abs( (double)values.first / (double)values.second );
145  //const int range_x = values.first - round_double(relation * deadzone);
146  //const int range_y = values.second - ((1.0 - relation) * deadzone);
147  //double x_value = ((double)(values.first - deadzone) / (double)(32768 - deadzone)) *
148 
149  return std::make_pair(
150  ((static_cast<double>(values.first)) / 32768.0) * multiplier
151  , ((static_cast<double>(values.second)) / 32768.0) * multiplier );
152 
153 }
154 
155 std::pair<double, double> joystick_manager::get_scroll_axis_pair() {
156 
157  if (!preferences::joystick_support_enabled()) return std::make_pair(0.0, 0.0);
158 
159  const int scroll_joystick_x = preferences::joystick_num_scroll_xaxis();
160  const int scroll_axis = preferences::joystick_scroll_xaxis_num();
161 
162  const int scroll_joystick_y = preferences::joystick_num_scroll_yaxis();
163  const int scroll_yaxis = preferences::joystick_scroll_yaxis_num();
164 
165  std::pair<int, int> values;
166  double thrust;
167  {
168  values = get_axis_pair(scroll_joystick_x, scroll_axis, scroll_joystick_y, scroll_yaxis);
169  thrust = get_thrusta_axis();
170  }
171 
172  const int radius = round_double(sqrt(pow(values.first, 2.0f) + pow(values.second, 2.0f)));
173  const int deadzone = preferences::joystick_scroll_deadzone();
174  const double multiplier = 1.0 + thrust;
175 
176  if (deadzone > radius)
177  return std::make_pair(0.0, 0.0);
178 
179  return std::make_pair(
180  ((static_cast<double>(values.first)) / 32768.0) * multiplier
181  , ((static_cast<double>(values.second)) / 32768.0) * multiplier );
182 }
183 
185  if (!preferences::joystick_support_enabled()) return 0.0;
186 
187  const int thrust_joystick_x = preferences::joystick_num_thrusta_axis();
188  const int thrust_axis_x = preferences::joystick_thrusta_axis_num();
189  const int thrust_deadzone = preferences::joystick_thrusta_deadzone();
190 
191  const int value = get_axis(thrust_joystick_x, thrust_axis_x) + 32768;
192  if (value < thrust_deadzone) return 0.0;
193  return static_cast<double>(value) / 65536.0;
194 }
195 
197  if (!preferences::joystick_support_enabled()) return 0.0;
198 
199  const int thrustb_joystick = preferences::joystick_num_thrustb_axis();
200  const int thrustb_axis = preferences::joystick_thrustb_axis_num();
201  const int thrustb_deadzone = preferences::joystick_thrustb_deadzone();
202 
203  const int value = get_axis(thrustb_joystick, thrustb_axis) + 32768;
204  if (value < thrustb_deadzone) return 0.0;
205  return static_cast<double>(value) / 65536.0;
206 }
207 
209  const int cursor_joystick_xaxis = preferences::joystick_num_cursor_xaxis();
210  const int cursor_xaxis = preferences::joystick_cursor_xaxis_num();
211 
212  const int cursor_joystick_yaxis = preferences::joystick_num_cursor_yaxis();
213  const int cursor_yaxis = preferences::joystick_cursor_yaxis_num();
214 
215  return get_polar_coordinates(cursor_joystick_xaxis, cursor_xaxis, cursor_joystick_yaxis, cursor_yaxis);
216 }
217 
218 std::pair<double, double> joystick_manager::get_polar_coordinates(int joystick_xaxis, int xaxis, int joystick_yaxis, int yaxis) {
219 
220  const std::pair<int, int> values = get_axis_pair(joystick_xaxis, xaxis, joystick_yaxis, yaxis);
221  const double radius = (sqrt(pow(values.first, 2.0f) + pow(values.second, 2.0f))) / 32768.0;
222  const double angle = (atan2(
223  static_cast<double>(values.second)
224  , static_cast<double>(values.first))) * 180.0 / pi<double>();
225 
226  return std::make_pair(radius, angle);
227 }
228 
229 std::pair<int, int> joystick_manager::get_axis_pair(int joystick_xaxis, int xaxis, int joystick_yaxis, int yaxis) {
230 
231  if(!SDL_WasInit(SDL_INIT_JOYSTICK))
232  return std::make_pair(0, 0);
233 
234  int x_axis = 0, y_axis = 0;
235  bool get_xaxis = false, get_yaxis = false;
236 
237  if(attached(joysticks_, joystick_xaxis))
238  if(SDL_JoystickNumAxes(joysticks_[joystick_xaxis]) > xaxis)
239  get_xaxis = true;
240 
241  if(attached(joysticks_, joystick_yaxis))
242  if(SDL_JoystickNumAxes(joysticks_[joystick_yaxis]) > yaxis)
243  get_yaxis = true;
244 
245  //TODO Does the block prevent the commands from being interrupted?
246  //We want the readings to be from a similar time slice.
247  {
248  if (get_xaxis) x_axis = SDL_JoystickGetAxis(joysticks_[joystick_xaxis], xaxis);
249  if (get_yaxis) y_axis = SDL_JoystickGetAxis(joysticks_[joystick_yaxis], yaxis);
250  }
251  return std::make_pair(x_axis, y_axis);
252 }
253 
254 int joystick_manager::get_axis(int joystick_axis, int axis) {
255  if(!SDL_WasInit(SDL_INIT_JOYSTICK))
256  return 0;
257 
258  if(attached(joysticks_, joystick_axis))
259  if(SDL_JoystickNumAxes(joysticks_[joystick_axis]) > axis)
260  return SDL_JoystickGetAxis(joysticks_[joystick_axis], axis);
261  return 0;
262 }
263 
264 
265 bool joystick_manager::update_highlighted_hex(map_location& highlighted_hex, const map_location& selected_hex) {
266 
267  const int cursor_joystick_xaxis = preferences::joystick_num_cursor_xaxis();
268  const int cursor_xaxis = preferences::joystick_cursor_xaxis_num();
269 
270  const int cursor_joystick_yaxis = preferences::joystick_num_cursor_yaxis();
271  const int cursor_yaxis = preferences::joystick_cursor_yaxis_num();
272 
273  const std::pair<int, int> values = get_axis_pair(cursor_joystick_xaxis, cursor_xaxis, cursor_joystick_yaxis, cursor_yaxis);
274 
275  const int x_axis = values.first;
276  const int y_axis = values.second;
277 
278  //const int radius = round_double(sqrt(pow(x_axis, 2.0f) + pow(y_axis, 2.0f)));
279 
280 // const int deadzone = preferences::joystick_cursor_deadzone();
281  //const int threshold2 = 10*threshold;
282  //const int max = 100000;
283 
284  //const bool greater_deadzone = radius > deadzone;
285  //const bool greater_threshold2 = radius > threshold2;
286 
287  highlighted_hex = selected_hex;
288  highlighted_hex.add(round_double(x_axis / 3200), round_double(y_axis / 3200));
289 
290  //if (!greater_threshold) {
291  // counter_ = 0;
292  // joystick_area_ = 0;
293  // return false;
294  //}
295 
296  return true;
297 }
298 
299 
301 
302  const int cursor_joystick_xaxis = preferences::joystick_num_cursor_xaxis();
303  const int cursor_xaxis = preferences::joystick_cursor_xaxis_num();
304 
305  const int cursor_joystick_yaxis = preferences::joystick_num_cursor_yaxis();
306  const int cursor_yaxis = preferences::joystick_cursor_yaxis_num();
307 
308  const std::pair<int, int> values = get_axis_pair(cursor_joystick_xaxis, cursor_xaxis, cursor_joystick_yaxis, cursor_yaxis);
309 
310  const int x_axis = values.first;
311  const int y_axis = values.second;
312 
313  const int radius = round_double(sqrt(pow(x_axis, 2.0f) + pow(y_axis, 2.0f)));
314 
315  const int deadzone = preferences::joystick_cursor_deadzone();
316  const int threshold = deadzone + preferences::joystick_cursor_threshold();
317  //TODO fendrin take max from preferences as well
318  const int max = 100000;
319 
320  const bool greater_deadzone = radius > deadzone;
321  const bool greater_threshold2 = radius > threshold;
322 
323  if (!greater_deadzone) {
324  counter_ = 0;
325  joystick_area_ = 0;
326  return false;
327  } else {
328  if (joystick_area_ == 0) {
329  highlighted_hex = get_next_hex(x_axis, y_axis, highlighted_hex);
330  }
331  if (!greater_threshold2) {
332  joystick_area_ = 1;
333  } else {
334  joystick_area_ = 2;
335  counter_ += radius;
336  if (counter_ > max) {
337  counter_ -= max;
338  highlighted_hex = get_next_hex(x_axis, y_axis, highlighted_hex);
339  return true;
340  } else return false;
341  }
342  }
343 
344  return true;
345 }
346 
348 {
349  map_location l = loc;
350 
351  switch(direction) {
352  case NORTH: return l.get_direction(map_location::NORTH);
353  case SOUTH: return l.get_direction(map_location::SOUTH);
358  case WEST: l.add(-1, 0); return l;
359  case EAST: l.add(1, 0); return l;
360  default:
361  assert(false);
362  return map_location();
363  }
364 }
365 
367 
368  const int cursor_joystick_xaxis = preferences::joystick_num_cursor_xaxis();
369  const int cursor_xaxis = preferences::joystick_cursor_xaxis_num();
370 
371  const int cursor_joystick_yaxis = preferences::joystick_num_cursor_yaxis();
372  const int cursor_yaxis = preferences::joystick_cursor_yaxis_num();
373 
374  const std::pair<int, int> values = get_axis_pair(cursor_joystick_xaxis, cursor_xaxis, cursor_joystick_yaxis, cursor_yaxis);
375 
376  const int x_axis = values.first;
377  const int y_axis = values.second;
378 
379  const double angle = (atan2(
380  static_cast<double>(y_axis)
381  , static_cast<double>(x_axis))) * 180.0 / pi<double>();
382 
383  return angle;
384 }
385 
386 
387 const map_location joystick_manager::get_next_hex(int x_axis, int y_axis, map_location loc) {
388 
390 
391  if (x_axis == 0) return (y_axis > 0) ? get_direction(loc, SOUTH) : get_direction(loc, NORTH);
392  if (y_axis == 0) return (x_axis > 0) ? get_direction(loc, EAST) : get_direction(loc, WEST);
393  const double angle = (atan2(
394  static_cast<double>(y_axis)
395  , static_cast<double>(x_axis))) * 180.0 / pi<double>();
396 
397  if (angle < -112.5 && angle > -157.5)
398  new_loc = get_direction(loc, NORTH_WEST);
399 
400  if (angle < -67.5 && angle > -112.5)
401  new_loc = get_direction(loc, NORTH);
402 
403  if (angle < -22.5 && angle > -67.5)
404  new_loc = get_direction(loc, NORTH_EAST);
405 
406  if (angle < 22.5 && angle > -22.5 )
407  new_loc = get_direction(loc, EAST);
408 
409  if (angle > 22.5 && angle < 67.5 )
410  new_loc = get_direction(loc, SOUTH_EAST);
411 
412  if (angle > 67.5 && angle < 113.5)
413  new_loc = get_direction(loc, SOUTH);
414 
415  if (angle > 113.5 && angle < 158.5)
416  new_loc = get_direction(loc, SOUTH_WEST);
417 
418  if (angle > 158.5 || angle < -157.5)
419  new_loc = get_direction(loc, WEST);
420 
421  return new_loc;
422 }
423 
int joystick_mouse_xaxis_num()
Definition: general.cpp:740
int joystick_thrustb_axis_num()
Definition: general.cpp:854
std::pair< int, int > get_axis_pair(int joystick_xaxis, int xaxis, int joystick_yaxis, int yaxis)
Definition: joystick.cpp:229
int joystick_mouse_yaxis_num()
Definition: general.cpp:752
static bool attached(const std::vector< SDL_Joystick * > &joysticks, const size_t index)
Definition: joystick.cpp:41
int joystick_num_mouse_xaxis()
Definition: general.cpp:734
size_t index(const utf8::string &str, const size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
Definition: unicode.cpp:71
int get_axis(int joystick_axis, int axis)
Definition: joystick.cpp:254
int joystick_thrusta_axis_num()
Definition: general.cpp:842
int joystick_num_cursor_yaxis()
Definition: general.cpp:824
bool update_highlighted_hex(map_location &highlighted_hex)
Used for absolute movement of the cursor.
Definition: joystick.cpp:300
int joystick_thrustb_deadzone()
Definition: general.cpp:776
int joystick_num_mouse_yaxis()
Definition: general.cpp:746
int joystick_num_thrustb_axis()
Definition: general.cpp:848
int joystick_num_scroll_xaxis()
Definition: general.cpp:788
int joystick_num_cursor_xaxis()
Definition: general.cpp:812
std::pair< double, double > get_scroll_axis_pair()
Definition: joystick.cpp:155
static lg::log_domain log_joystick("joystick")
int joystick_cursor_yaxis_num()
Definition: general.cpp:830
int joystick_thrusta_deadzone()
Definition: general.cpp:770
bool joystick_support_enabled()
Definition: general.cpp:723
#define LOG_JOY
Definition: joystick.cpp:25
void add(int x_diff, int y_diff)
Definition: location.hpp:123
int joystick_scroll_yaxis_num()
Definition: general.cpp:806
std::pair< double, double > get_polar_coordinates(int joystick_xaxis, int xaxis, int joystick_yaxis, int yaxis)
TODO fendrin.
Definition: joystick.cpp:218
int round_double(double d)
Definition: math.hpp:67
General math utility functions.
double get_thrusta_axis()
TODO fendrin.
Definition: joystick.cpp:184
static const map_location & null_location()
Definition: location.hpp:224
int joystick_scroll_xaxis_num()
Definition: general.cpp:794
double get_angle()
TODO fendrin.
Definition: joystick.cpp:366
Encapsulates the map of the game.
Definition: location.hpp:42
int joystick_num_thrusta_axis()
Definition: general.cpp:836
const map_location get_direction(const map_location &loc, joystick_manager::DIRECTION direction)
Definition: joystick.cpp:347
std::vector< SDL_Joystick * > joysticks_
Definition: joystick.hpp:95
double get_thrustb_axis()
TODO fendrin.
Definition: joystick.cpp:196
size_t i
Definition: function.cpp:933
int joystick_cursor_xaxis_num()
Definition: general.cpp:818
int joystick_cursor_threshold()
Definition: general.cpp:782
#define ERR_JOY
Definition: joystick.cpp:24
#define f
Standard logging facilities (interface).
int joystick_scroll_deadzone()
Definition: general.cpp:758
map_location get_direction(DIRECTION d, unsigned int n=1u) const
Definition: location.hpp:261
static const char * name(const std::vector< SDL_Joystick * > &joysticks, const size_t index)
Definition: joystick.cpp:48
int joystick_mouse_deadzone()
Definition: general.cpp:728
int joystick_cursor_deadzone()
Definition: general.cpp:764
const map_location get_next_hex(int x_axis, int y_axis, map_location old_hex)
Definition: joystick.cpp:387
int joystick_num_scroll_yaxis()
Definition: general.cpp:800
std::pair< double, double > get_mouse_axis_pair()
TODO fendrin.
Definition: joystick.cpp:121
std::pair< double, double > get_cursor_polar_coordinates()
TODO fendrin.
Definition: joystick.cpp:208