FS2_Open
Open source remastering of the Freespace 2 engine
joy-unix.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) Volition, Inc. 1999. All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell
5  * or otherwise commercially exploit the source or things you created based on
6  * the source.
7  */
8 
9 
10 #ifndef WIN32 // Goober5000
11 
12 #include "globalincs/pstypes.h"
13 #include "io/joy.h"
14 #include "math/fix.h"
15 #include "io/key.h"
16 #include "io/timer.h"
17 #include "osapi/osregistry.h"
18 #include "io/joy_ff.h"
19 #include "osapi/osapi.h"
20 #include "SDL.h"
21 
22 static int Joy_inited = 0;
23 static int joy_num_sticks = 0;
24 static int joy_num_buttons = 0;
25 static int joy_num_axes = 0;
26 static int joy_num_hats = 0;
27 int Dead_zone_size = 10;
28 int Cur_joystick = -1;
30 
31 int joy_pollrate = 1000 / 18; // poll at 18Hz
32 
33 static int Joy_last_x_reading = 0;
34 static int Joy_last_y_reading = 0;
35 
36 typedef struct joy_button_info {
37  int actual_state; // Set if the button is physically down
38  int state; // Set when the button goes from up to down, cleared on down to up. Different than actual_state after a flush.
40  int up_count;
41  int down_time;
42  uint last_down_check; // timestamp in milliseconds of last
44 
46 
47 int JOYSTICKID1 = 0; // DDOI - temporary
48 static SDL_Joystick *sdljoy;
49 
51 
52 
53 void joy_close()
54 {
55  if (!Joy_inited)
56  return;
57 
58  Joy_inited = 0;
59  joy_num_sticks = 0;
60 
61  if (sdljoy)
62  SDL_JoystickClose(sdljoy);
63 
64  sdljoy = NULL;
65 
66  SDL_QuitSubSystem (SDL_INIT_JOYSTICK);
67 }
68 
69 void joy_get_caps (int max)
70 {
71  SDL_Joystick *joy;
72  int j;
73 
74  for (j=0; j < JOY_NUM_AXES; j++)
75  joystick.axis_valid[j] = 0;
76 
77  for (j=JOYSTICKID1; j<JOYSTICKID1+max; j++) {
78  joy = SDL_JoystickOpen (j);
79  if (joy)
80  {
81  nprintf (("JOYSTICK", "Joystick #%d: %s\n", j - JOYSTICKID1 + 1, SDL_JoystickName(j)));
82  if (j == Cur_joystick) {
83  for (int i = 0; i < SDL_JoystickNumAxes(joy); i++)
84  {
85  joystick.axis_valid[i] = 1;
86  }
87  }
88  SDL_JoystickClose (joy);
89  }
90  }
91 }
92 
93 int joy_down(int btn)
94 {
95  int tmp;
96 
97  if ( joy_num_sticks < 1 ) return 0;
98  if ( (btn < 0) || (btn >= JOY_TOTAL_BUTTONS )) return 0;
99 
100  tmp = joy_buttons[btn].state;
101 
102  return tmp;
103 }
104 
105 int joy_down_count(int btn, int reset_count)
106 {
107  int tmp;
108 
109  if ( joy_num_sticks < 1 ) return 0;
110  if ( (btn < 0) || (btn >= JOY_TOTAL_BUTTONS)) return 0;
111 
112  tmp = joy_buttons[btn].down_count;
113 
114  if ( reset_count )
115  joy_buttons[btn].down_count = 0;
116 
117  return tmp;
118 }
119 
120 float joy_down_time(int btn)
121 {
122  float rval;
123  unsigned int now;
124  joy_button_info *bi;
125 
126  if ( joy_num_sticks < 1 ) return 0.0f;
127  if ( (btn < 0) || (btn >= JOY_TOTAL_BUTTONS)) return 0.0f;
128  bi = &joy_buttons[btn];
129 
130  now = timer_get_milliseconds();
131 
132  if ( bi->down_time == 0 && joy_down(btn) ) {
133  bi->down_time += joy_pollrate;
134  }
135 
136  if ( (now - bi->last_down_check) > 0)
137  rval = i2fl(bi->down_time) / (now - bi->last_down_check);
138  else
139  rval = 0.0f;
140 
141  bi->down_time = 0;
142  bi->last_down_check = now;
143 
144  if (rval < 0)
145  rval = 0.0f;
146  if (rval > 1)
147  rval = 1.0f;
148 
149  return rval;
150 }
151 
152 void joy_flush()
153 {
154  int i;
155  joy_button_info *bi;
156 
157  if ( joy_num_sticks < 1 )
158  return;
159 
160  for ( i = 0; i < JOY_TOTAL_BUTTONS; i++) {
161  bi = &joy_buttons[i];
162  bi->actual_state = 0;
163  bi->state = 0;
164  bi->down_count = 0;
165  bi->up_count = 0;
166  bi->down_time = 0;
168  }
169 }
170 
171 int joy_get_unscaled_reading(int raw, int axn)
172 {
173  int rng;
174 
175  // Make sure it's calibrated properly.
176  if (joystick.axis_center[axn] - joystick.axis_min[axn] < 5)
177  return 0;
178 
179  if (joystick.axis_max[axn] - joystick.axis_center[axn] < 5)
180  return 0;
181 
182  rng = joystick.axis_max[axn] - joystick.axis_min[axn];
183  raw -= joystick.axis_min[axn]; // adjust for linear range starting at 0
184 
185  // cap at limits
186  if (raw < 0)
187  raw = 0;
188  if (raw > rng)
189  raw = rng;
190 
191  return (int) ((uint) raw * (uint) F1_0 / (uint) rng); // convert to 0 - F1_0 range.
192 }
193 
194 // --------------------------------------------------------------
195 // joy_get_scaled_reading()
196 //
197 // input: raw => the raw value for an axis position
198 // axn => axis number, numbered starting at 0
199 //
200 // return: joy_get_scaled_reading will return a value that represents
201 // the joystick pos from -1 to +1 for the specified axis number 'axn', and
202 // the raw value 'raw'
203 //
204 int joy_get_scaled_reading(int raw, int axn)
205 {
206  int x, d, dead_zone, rng;
207  float percent, sensitivity_percent, non_sensitivity_percent;
208 
209  // Make sure it's calibrated properly.
210  if (joystick.axis_center[axn] - joystick.axis_min[axn] < 5)
211  return 0;
212 
213  if (joystick.axis_max[axn] - joystick.axis_center[axn] < 5)
214  return 0;
215 
216  raw -= joystick.axis_center[axn];
217 
218  dead_zone = (joystick.axis_max[axn] - joystick.axis_min[axn]) * Dead_zone_size / 100;
219 
220  if (raw < -dead_zone) {
221  rng = joystick.axis_center[axn] - joystick.axis_min[axn] - dead_zone;
222  d = -raw - dead_zone;
223 
224  } else if (raw > dead_zone) {
225  rng = joystick.axis_max[axn] - joystick.axis_center[axn] - dead_zone;
226  d = raw - dead_zone;
227 
228  } else
229  return 0;
230 
231  if (d > rng)
232  d = rng;
233 
234  Assert(Joy_sensitivity >= 0 && Joy_sensitivity <= 9);
235 
236  // compute percentages as a range between 0 and 1
237  sensitivity_percent = (float) Joy_sensitivity / 9.0f;
238  non_sensitivity_percent = (float) (9 - Joy_sensitivity) / 9.0f;
239 
240  // find percent of max axis is at
241  percent = (float) d / (float) rng;
242 
243  // work sensitivity on axis value
244  percent = (percent * sensitivity_percent + percent * percent * percent * percent * percent * non_sensitivity_percent);
245 
246  x = (int) ((float) F1_0 * percent);
247 
248  //nprintf(("AI", "d=%6i, sens=%3i, percent=%6.3f, val=%6i, ratio=%6.3f\n", d, Joy_sensitivity, percent, (raw<0) ? -x : x, (float) d/x));
249 
250  if (raw < 0)
251  return -x;
252 
253  return x;
254 }
255 
256 // --------------------------------------------------------------
257 // joy_get_pos()
258 //
259 // input: x => OUTPUT PARAMETER: x-axis position of stick (-1 to 1)
260 // y => OUTPUT PARAMETER: y-axis position of stick (-1 to 1)
261 // z => OUTPUT PARAMETER: z-axis (throttle) position of stick (-1 to 1)
262 // r => OUTPUT PARAMETER: rudder position of stick (-1 to 1)
263 //
264 // return: success => 1
265 // failure => 0
266 //
267 int joy_get_pos(int *x, int *y, int *z, int *rx)
268 {
269  int axis[JOY_NUM_AXES];
270 
271  if (x) *x = 0;
272  if (y) *y = 0;
273  if (z) *z = 0;
274  if (rx) *rx = 0;
275 
276  if (joy_num_sticks < 1) return 0;
277 
278  joystick_read_raw_axis( 6, axis );
279 
280  // joy_get_scaled_reading will return a value represents the joystick pos from -1 to +1
281  if (x && joystick.axis_valid[0])
282  *x = joy_get_scaled_reading(axis[0], 0);
283  if (y && joystick.axis_valid[1])
284  *y = joy_get_scaled_reading(axis[1], 1);
285  if (z && joystick.axis_valid[2])
286  *z = joy_get_unscaled_reading(axis[2], 2);
287  if (rx && joystick.axis_valid[3])
288  *rx = joy_get_scaled_reading(axis[3], 3);
289 
290  if (x)
291  Joy_last_x_reading = *x;
292 
293  if (y)
294  Joy_last_y_reading = *y;
295 
296  return 1;
297 }
298 
299 void joy_process(int time_delta)
300 {
302 
303 /* int i;
304 
305  if (!Joy_inited)
306  return;
307 
308  int hat = SDL_JoystickGetHat(sdljoy, 0);
309 
310  for (i=0; i < JOY_TOTAL_BUTTONS; i++) {
311  int state = 0;
312 
313  if (i < JOY_NUM_BUTTONS) {
314  if (i < joy_num_buttons) {
315  state = SDL_JoystickGetButton(sdljoy, i);
316  }
317  } else {
318  switch (i) {
319  case JOY_HATBACK:
320  state = (hat & SDL_HAT_DOWN) ? 1 : 0;
321  break;
322  case JOY_HATFORWARD:
323  state = (hat & SDL_HAT_UP) ? 1 : 0;
324  break;
325  case JOY_HATLEFT:
326  state = (hat & SDL_HAT_LEFT) ? 1 : 0;
327  break;
328  case JOY_HATRIGHT:
329  state = (hat & SDL_HAT_RIGHT) ? 1 : 0;
330  break;
331  default:
332  break;
333  }
334  }
335 
336  if (state != joy_buttons[i].actual_state) {
337  // Button position physically changed.
338  joy_buttons[i].actual_state = state;
339 
340  if ( state ) {
341  // went from up to down
342  joy_buttons[i].down_count++;
343  joy_buttons[i].down_time = 0;
344 
345  joy_buttons[i].state = 1;
346  } else {
347  // went from down to up
348  if ( joy_buttons[i].state ) {
349  joy_buttons[i].up_count++;
350  }
351 
352  joy_buttons[i].state = 0;
353  }
354  } else {
355  // Didn't move... increment time down if down.
356  if (joy_buttons[i].state) {
357  //joy_buttons[i].down_time += joy_pollrate;
358  joy_buttons[i].down_time += time_delta;
359  }
360  }
361  } */
362 }
363 
364 
365 void joy_set_button_state(int button, int state)
366 {
367  if (!Joy_inited)
368  return;
369 
370  if (state != joy_buttons[button].actual_state) {
371  // Button position physically changed.
372  joy_buttons[button].actual_state = state;
373 
374  if ( state ) {
375  // went from up to down
376  joy_buttons[button].down_count++;
377  joy_buttons[button].down_time = 0;
378 
379  joy_buttons[button].state = 1;
380  } else {
381  // went from down to up
382  if ( joy_buttons[button].state )
383  joy_buttons[button].up_count++;
384 
385  joy_buttons[button].state = 0;
386  }
387  } else {
388  // Didn't move... increment time down if down.
389  if (joy_buttons[button].state)
390  joy_buttons[button].down_time += joy_pollrate;
391  }
392 }
393 
394 void joy_set_hat_state(int position)
395 {
396  int state = 0;
397 
398  if (!Joy_inited)
399  return;
400 
401  for (int i=JOY_NUM_BUTTONS-1; i<JOY_TOTAL_BUTTONS; i++) {
402  switch (i) {
403  case JOY_HATBACK:
404  state = (position == SDL_HAT_DOWN) ? 1 : 0;
405  break;
406  case JOY_HATFORWARD:
407  state = (position == SDL_HAT_UP) ? 1 : 0;
408  break;
409  case JOY_HATLEFT:
410  state = (position == SDL_HAT_LEFT) ? 1 : 0;
411  break;
412  case JOY_HATRIGHT:
413  state = (position == SDL_HAT_RIGHT) ? 1 : 0;
414  break;
415  default:
416  break;
417  }
418 
419  if (state != joy_buttons[i].actual_state) {
420  // Button position physically changed.
421  joy_buttons[i].actual_state = state;
422 
423  if ( state ) {
424  // went from up to down
425  joy_buttons[i].down_count++;
426  joy_buttons[i].down_time = 0;
427 
428  joy_buttons[i].state = 1;
429  } else {
430  // went from down to up
431  if ( joy_buttons[i].state ) {
432  joy_buttons[i].up_count++;
433  }
434 
435  joy_buttons[i].state = 0;
436  }
437  } else {
438  // Didn't move... increment time down if down.
439  if (joy_buttons[i].state) {
440  joy_buttons[i].down_time += joy_pollrate;
441  }
442  }
443  }
444 }
445 
446 void joy_poll()
447 {
449 
450 /* if (!Joy_inited)
451  return;
452 
453  uint lasttic = 0;
454  uint curtic = SDL_GetTicks();
455  uint delta = curtic - lasttic;
456 
457  while (delta >= (uint)joy_pollrate) {
458  joy_process(delta);
459 
460  lasttic += joy_pollrate;
461 
462  delta = curtic - lasttic;
463  } */
464 }
465 
466 int joy_init()
467 {
468  int i, n;
469 
470  if (Joy_inited)
471  return 0;
472 
473  if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0) {
474  mprintf(("Could not initialize joystick\n"));
475  return 0;
476  }
477 
478  // enable event processing of the joystick
479  if ( (SDL_JoystickEventState(SDL_ENABLE)) != SDL_ENABLE ) {
480  mprintf(("ERROR: Unable to initialize joystick event processing!\n"));
481  SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
482  return 0;
483  }
484 
485  n = SDL_NumJoysticks();
486 
487  if (n < 1) {
488  mprintf(("No joysticks found\n"));
489  SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
490  return 0;
491  }
492 
493  joy_get_caps(n);
494 
495  Cur_joystick = os_config_read_uint(NULL, "CurrentJoystick", JOYSTICKID1);
496 
497  sdljoy = SDL_JoystickOpen(Cur_joystick);
498 
499  if (sdljoy == NULL) {
500  mprintf(("Unable to init joystick %d\n", Cur_joystick));
501  SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
502  return 0;
503  }
504 
505  joy_flush();
506 
507  joy_num_sticks = n;
508 
509  joy_num_buttons = SDL_JoystickNumButtons(sdljoy);
510  joy_num_axes = SDL_JoystickNumAxes(sdljoy);
511  joy_num_hats = SDL_JoystickNumHats(sdljoy);
512 
513  mprintf(( "\nJoystick INITTED!\n\n" ));
514  mprintf(( "Using '%s' as the primary joystick:\n", SDL_JoystickName(Cur_joystick) ));
515  mprintf(( " Number of axes: %i\n", joy_num_axes ));
516  mprintf(( " Number of buttons: %i\n", joy_num_buttons ));
517  mprintf(( " Number of hats: %i\n", joy_num_hats ));
518  mprintf(( " Number of trackballs: %i\n\n", SDL_JoystickNumBalls(sdljoy) ));
519 
520  // Fake a calibration
521  if (joy_num_sticks > 0) {
522  for (i=0; i<JOY_NUM_AXES; i++) {
523  joystick.axis_center[i] = 32768;
524  joystick.axis_min[i] = 0;
525  joystick.axis_max[i] = 65536;
526  }
527  }
528 
529  // we poll for axis type motion so be sure to ignore that during normal event state polling
530  SDL_EventState( SDL_JOYAXISMOTION, SDL_IGNORE );
531  SDL_EventState( SDL_JOYBALLMOTION, SDL_IGNORE );
532 
533  // we do want to make sure that hat/button presses go through event polling though
534  // (should be on by default already, just here as a reminder)
535  SDL_EventState( SDL_JOYBUTTONDOWN, SDL_ENABLE );
536  SDL_EventState( SDL_JOYBUTTONUP, SDL_ENABLE );
537  SDL_EventState( SDL_JOYHATMOTION, SDL_ENABLE );
538 
539  Joy_inited = 1;
540 
541  return joy_num_sticks;
542 }
543 
545 {
546  joystick_read_raw_axis( 2, joystick.axis_center );
547 }
548 
549 int joystick_read_raw_axis(int num_axes, int *axis)
550 {
551  int i;
552 
553  if (!Joy_inited) {
554  // fake a return value so that controlconfig doesn't get freaky with no joystick
555  for (i = 0; i < num_axes; i++) {
556  axis[i] = 32768;
557  }
558 
559  return 0;
560  }
561 
562  Assert( num_axes <= JOY_NUM_AXES );
563 
564  for (i = 0; i < num_axes; i++) {
565  if (i < joy_num_axes) {
566  axis[i] = SDL_JoystickGetAxis(sdljoy, i) + 32768;
567  } else {
568  axis[i] = 32768;
569  }
570  }
571 
572  return 1;
573 }
574 
575 void joy_ff_adjust_handling(int speed)
576 {
577 // STUB_FUNCTION;
578 }
579 
581 {
582 // STUB_FUNCTION;
583 }
584 
586 {
587 // STUB_FUNCTION;
588 }
589 
591 {
592 // STUB_FUNCTION;
593 }
594 
596 {
597 // STUB_FUNCTION;
598 }
599 
601 {
602 // STUB_FUNCTION;
603 }
604 
605 void joy_ff_fly_by(int mag)
606 {
607 // STUB_FUNCTION;
608 }
609 
611 {
612 // STUB_FUNCTION;
613 }
614 
615 void joy_ff_play_dir_effect(float x, float y)
616 {
617 // STUB_FUNCTION;
618 }
619 
621 {
622 // STUB_FUNCTION;
623 }
624 
626 {
627 // STUB_FUNCTION;
628 }
629 
631 {
632 // STUB_FUNCTION;
633 }
634 
635 void joy_ff_play_vector_effect(vec3d *v, float scaler)
636 {
637 // STUB_FUNCTION;
638 }
639 
641 {
643 }
644 
645 #endif // Goober5000 - #ifndef WIN32
int axis_max[JOY_NUM_AXES]
Definition: joy.h:31
#define JOY_NUM_AXES
Definition: joy.h:18
int Joy_sensitivity
Definition: joy-unix.cpp:29
int i
Definition: multi_pxo.cpp:466
uint os_config_read_uint(const char *section, const char *name, uint default_value)
Definition: osregistry.cpp:372
void joy_ff_afterburn_on()
Definition: joy-unix.cpp:585
int axis_center[JOY_NUM_AXES]
Definition: joy.h:30
Definition: joy.h:27
void joy_ff_stop_effects()
Definition: joy-unix.cpp:640
int joy_down(int btn)
Definition: joy-unix.cpp:93
#define F1_0
Definition: fix.h:15
struct joy_button_info joy_button_info
int joy_pollrate
Definition: joy-unix.cpp:31
void joy_close()
Definition: joy-unix.cpp:53
int Dead_zone_size
Definition: joy-unix.cpp:27
void joy_ff_mission_init(vec3d v)
Definition: joy-unix.cpp:610
int joy_init()
Definition: joy-unix.cpp:466
Assert(pm!=NULL)
Definition: pstypes.h:88
#define JOY_HATRIGHT
Definition: joy.h:23
#define mprintf(args)
Definition: pstypes.h:238
int joy_get_pos(int *x, int *y, int *z, int *rx)
Definition: joy-unix.cpp:267
joy_button_info joy_buttons[JOY_TOTAL_BUTTONS]
Definition: joy-unix.cpp:50
void joy_set_cen()
Definition: joy-unix.cpp:544
GLclampf f
Definition: Glext.h:7097
void joy_ff_afterburn_off()
Definition: joy-unix.cpp:580
void joy_get_caps(int max)
Definition: joy-unix.cpp:69
void joy_ff_deathroll()
Definition: joy-unix.cpp:590
void joy_process(int time_delta)
Definition: joy-unix.cpp:299
int Cur_joystick
Definition: joy-unix.cpp:28
int axis_min[JOY_NUM_AXES]
Definition: joy.h:29
void joy_set_button_state(int button, int state)
Definition: joy-unix.cpp:365
typedef int(SCP_EXT_CALLCONV *SCPDLL_PFVERSION)(SCPDLL_Version *)
#define JOY_HATLEFT
Definition: joy.h:22
void joy_ff_play_primary_shoot(int gain)
Definition: joy-unix.cpp:620
void joy_ff_fly_by(int mag)
Definition: joy-unix.cpp:605
unsigned int uint
Definition: pstypes.h:64
int joystick_read_raw_axis(int num_axes, int *axis)
Definition: joy-unix.cpp:549
#define nprintf(args)
Definition: pstypes.h:239
void joy_ff_play_dir_effect(float x, float y)
Definition: joy-unix.cpp:615
void joy_ff_play_reload_effect()
Definition: joy-unix.cpp:625
void joy_flush()
Definition: joy-unix.cpp:152
void joy_ff_explode()
Definition: joy-unix.cpp:600
GLdouble GLdouble z
Definition: Glext.h:5451
uint last_down_check
Definition: joy-unix.cpp:42
int JOYSTICKID1
Definition: joy-unix.cpp:47
GLint GLint GLint GLint GLint x
Definition: Glext.h:5182
for(int idx=0;idx< i;idx++)
Definition: multi_pxo.cpp:472
GLclampd n
Definition: Glext.h:7286
void joy_ff_play_secondary_shoot(int gain)
Definition: joy-unix.cpp:630
float joy_down_time(int btn)
Definition: joy-unix.cpp:120
typedef float(SCP_EXT_CALLCONV *SCPTRACKIR_PFFLOATVOID)()
#define JOY_TOTAL_BUTTONS
Definition: joy.h:17
int joy_get_scaled_reading(int raw, int axn)
Definition: joy-unix.cpp:204
void joy_ff_docked()
Definition: joy-unix.cpp:595
int joy_num_sticks
Definition: joy.cpp:30
#define JOY_NUM_BUTTONS
Definition: joy.h:15
#define i2fl(i)
Definition: floating.h:32
#define STUB_FUNCTION
Definition: config.h:67
Joy_info joystick
Definition: joy-unix.cpp:45
int joy_down_count(int btn, int reset_count)
Definition: joy-unix.cpp:105
int joy
#define JOY_HATBACK
Definition: joy.h:20
int joy_get_unscaled_reading(int raw, int axn)
Definition: joy-unix.cpp:171
void joy_ff_adjust_handling(int speed)
Definition: joy-unix.cpp:575
void joy_set_hat_state(int position)
Definition: joy-unix.cpp:394
int axis_valid[JOY_NUM_AXES]
Definition: joy.h:28
int timer_get_milliseconds()
Definition: timer.cpp:150
void joy_poll()
Definition: joy-unix.cpp:446
const GLdouble * v
Definition: Glext.h:5322
void joy_ff_play_vector_effect(vec3d *v, float scaler)
Definition: joy-unix.cpp:635
#define JOY_HATFORWARD
Definition: joy.h:21
GLint y
Definition: Gl.h:1505