]> icculus.org git repositories - taylor/freespace2.git/blob - src/io/joy.cpp
remove broken DCF() functions
[taylor/freespace2.git] / src / io / joy.cpp
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 #include "pstypes.h"
10 #include "joy.h"
11 #include "fix.h"
12 #include "key.h"
13 #include "timer.h"
14 #include "osregistry.h"
15 #include "joy_ff.h"
16 #include "osapi.h"
17
18
19 static int Joy_inited = 0;
20 int Dead_zone_size = 10;
21 int Cur_joystick = -1;
22 int Joy_sensitivity = 9;
23
24 static int Joy_last_x_reading = 0;
25 static int Joy_last_y_reading = 0;
26
27 typedef struct joy_button_info {
28         int     actual_state;           // Set if the button is physically down
29         int     state;                          // Set when the button goes from up to down, cleared on down to up.  Different than actual_state after a flush.
30         int     down_count;
31         int     up_count;
32         int     down_time;
33         uint    last_down_check;        // timestamp in milliseconds of last
34 } joy_button_info;
35
36 static Joy_info joystick;
37
38 SDL_Joystick *sdljoy;
39 static SDL_JoystickID joy_id = -1;
40
41 joy_button_info joy_buttons[JOY_TOTAL_BUTTONS];
42
43
44 int joystick_get_id()
45 {
46         return joy_id;
47 }
48
49 void joy_close()
50 {
51         if (!Joy_inited)
52                 return;
53
54         joy_ff_shutdown();
55
56         Joy_inited = 0;
57         joy_id = -1;
58
59         if (SDL_JoystickGetAttached(sdljoy)) {
60                 SDL_JoystickClose(sdljoy);
61         }
62
63         sdljoy = NULL;
64
65         SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
66 }
67
68 void joy_get_caps()
69 {
70         SDL_Joystick *joy;
71         int j, max_count;
72
73         max_count = SDL_NumJoysticks();
74
75         for (j = 0; j < max_count; j++) {
76                 joy = SDL_JoystickOpen(j);
77
78                 if (joy) {
79                 //      nprintf (("JOYSTICK", "Joystick #%d: %s\n", j - JOYSTICKID1 + 1, SDL_JoystickName(j)));
80                         mprintf(("Joystick #%d: %s  %s\n", j + 1, SDL_JoystickName(joy), (j == Cur_joystick) ? "*" : " "));
81                         mprintf(("  Axes: %d\n", SDL_JoystickNumAxes(joy)));
82                         mprintf(("  Buttons: %d\n", SDL_JoystickNumButtons(joy)));
83                         mprintf(("  Hats: %d\n", SDL_JoystickNumHats(joy)));
84                         mprintf(("  Balls: %d\n", SDL_JoystickNumBalls(joy)));
85                         mprintf(("  Haptic: %s\n", SDL_JoystickIsHaptic(joy) ? "Yes" : "No"));
86
87                         SDL_JoystickClose (joy);
88                 }
89         }
90
91         mprintf(("\n"));
92 }
93
94 int joy_down(int btn)
95 {
96         int tmp;
97
98         if ( !Joy_inited ) {
99                 return 0;
100         }
101
102         if ( (btn < 0) || (btn >= JOY_TOTAL_BUTTONS)) {
103                 return 0;
104         }
105
106         tmp = joy_buttons[btn].state;
107
108         return tmp;
109 }
110
111 int joy_down_count(int btn, int reset_count)
112 {
113         int tmp;
114
115         if ( !Joy_inited ) {
116                 return 0;
117         }
118
119         if ( (btn < 0) || (btn >= JOY_TOTAL_BUTTONS)) {
120                 return 0;
121         }
122
123         tmp = joy_buttons[btn].down_count;
124         if ( reset_count ) {
125                 joy_buttons[btn].down_count = 0;
126         }
127
128         return tmp;
129 }
130
131 float joy_down_time(int btn)
132 {
133         float                           rval;
134         unsigned int    now, delta;
135         joy_button_info         *bi;
136
137         if ( !Joy_inited ) {
138                 return 0.0f;
139         }
140
141         if ( (btn < 0) || (btn >= JOY_TOTAL_BUTTONS)) {
142                 return 0.0f;
143         }
144
145         bi = &joy_buttons[btn];
146
147         now = timer_get_milliseconds();
148         delta = now - bi->last_down_check;
149
150         if ( (now - bi->last_down_check) > 0)
151                 rval = i2fl((now - bi->down_time)) / delta;
152         else
153                 rval = 0.0f;
154
155         bi->down_time = 0;
156         bi->last_down_check = now;
157
158         if (rval < 0)
159                 rval = 0.0f;
160         if (rval > 1)
161                 rval = 1.0f;
162
163         return rval;
164 }
165
166 void joy_mark_button(int btn, int state)
167 {
168         int i;
169         joy_button_info *bi;
170
171         if ( !Joy_inited ) {
172                 return;
173         }
174
175         if ( (btn < 0) || (btn >= JOY_TOTAL_BUTTONS)) {
176                 return;
177         }
178
179         bi = &joy_buttons[btn];
180
181         if (state) {
182                 // button pressed
183                 bi->down_count++;
184
185                 bi->state = 1;
186                 bi->down_time = timer_get_milliseconds();
187
188                 // toggle off other positions if hat
189                 if (btn >= JOY_HATBACK) {
190                         for (i = JOY_HATBACK; i < (JOY_HATBACK+JOY_NUM_HAT_POS); i++) {
191                                 if (btn != i) {
192                                         joy_buttons[i].state = 0;
193                                 }
194                         }
195                 }
196         } else {
197                 // button released
198         //      bi->up_count++;
199
200                 bi->state = 0;
201
202                 // special hat handling - make sure all hat pos are off
203                 if (btn == JOY_HATBACK) {
204                         for (i = JOY_HATBACK; i < (JOY_HATBACK+JOY_NUM_HAT_POS); i++) {
205                                 joy_buttons[i].state = 0;
206                         }
207                 }
208         }
209 }
210
211 void joy_flush()
212 {
213         int                     i;
214         joy_button_info *bi;
215
216         if ( !Joy_inited ) {
217                 return;
218         }
219
220         for ( i = 0; i < JOY_TOTAL_BUTTONS; i++) {
221                 bi = &joy_buttons[i];
222                 bi->state               = 0;
223                 bi->down_count  = 0;
224                 bi->up_count    = 0;
225                 bi->down_time   = 0;
226                 bi->last_down_check = timer_get_milliseconds();
227         }
228 }
229
230 int joy_get_unscaled_reading(int axn)
231 {
232         int rng;
233
234         if ( !Joy_inited ) {
235                 return 0;
236         }
237
238         if (axn >= joystick.num_axes) {
239                 return 0;
240         }
241
242         int raw = joystick.axis_current[axn];
243
244         rng = joystick.axis_max[axn] - joystick.axis_min[axn];
245         raw -= joystick.axis_min[axn];  // adjust for linear range starting at 0
246
247         // cap at limits
248         if (raw < 0)
249                 raw = 0;
250         if (raw > rng)
251                 raw = rng;
252
253         return (int) ((unsigned int) raw * (unsigned int) F1_0 / (unsigned int) rng);  // convert to 0 - F1_0 range.
254 }
255
256 // --------------------------------------------------------------
257 //      joy_get_scaled_reading()
258 //
259 //      input:  raw     =>      the raw value for an axis position
260 //                              axn     =>      axis number, numbered starting at 0
261 //
262 // return:      joy_get_scaled_reading will return a value that represents
263 //                              the joystick pos from -1 to +1 for the specified axis number 'axn', and
264 //                              the raw value 'raw'
265 //
266 int joy_get_scaled_reading(int axn)
267 {
268         int x, d, dead_zone, rng, raw;
269         float percent, sensitivity_percent, non_sensitivity_percent;
270
271         if ( !Joy_inited ) {
272                 return 0;
273         }
274
275         if (axn >= joystick.num_axes) {
276                 return 0;
277         }
278
279         raw = joystick.axis_current[axn] - joystick.axis_center[axn];
280
281         dead_zone = (joystick.axis_max[axn] - joystick.axis_min[axn]) * Dead_zone_size / 100;
282
283         if (raw < -dead_zone) {
284                 rng = joystick.axis_center[axn] - joystick.axis_min[axn] - dead_zone;
285                 d = -raw - dead_zone;
286
287         } else if (raw > dead_zone) {
288                 rng = joystick.axis_max[axn] - joystick.axis_center[axn] - dead_zone;
289                 d = raw - dead_zone;
290
291         } else {
292                 return 0;
293         }
294
295         if (d > rng)
296                 d = rng;
297
298         Assert(Joy_sensitivity >= 0 && Joy_sensitivity <= 9);
299
300         // compute percentages as a range between 0 and 1
301         sensitivity_percent = (float) Joy_sensitivity / 9.0f;
302         non_sensitivity_percent = (float) (9 - Joy_sensitivity) / 9.0f;
303
304         // find percent of max axis is at
305         percent = (float) d / (float) rng;
306
307         // work sensitivity on axis value
308         percent = (percent * sensitivity_percent + percent * percent * percent * percent * percent * non_sensitivity_percent);
309
310         x = (int) ((float) F1_0 * percent);
311
312         //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));
313
314         if (raw < 0) {
315                 return -x;
316         }
317
318         return x;
319 }
320
321 // --------------------------------------------------------------
322 //      joy_get_pos()
323 //
324 //      input:  x               =>              OUTPUT PARAMETER: x-axis position of stick (-1 to 1)
325 //                              y               =>              OUTPUT PARAMETER: y-axis position of stick (-1 to 1)
326 //                              z               =>              OUTPUT PARAMETER: z-axis (throttle) position of stick (-1 to 1)
327 //                              r               =>              OUTPUT PARAMETER: rudder position of stick (-1 to 1)
328 //
329 //      return: success => 1
330 //                              failure => 0
331 //
332 int joy_get_pos(int *x, int *y, int *z, int *rx)
333 {
334         if (x) *x = 0;
335         if (y) *y = 0;
336         if (z) *z = 0;
337         if (rx) *rx = 0;
338
339         if ( !Joy_inited ) {
340                 return 0;
341         }
342
343         //      joy_get_scaled_reading will return a value represents the joystick
344         //      pos from -1 to +1
345         if (x && joystick.num_axes > 0) {
346                 *x = joy_get_scaled_reading(0);
347                 Joy_last_x_reading = *x;
348         }
349
350         if (y && joystick.num_axes > 1) {
351                 *y = joy_get_scaled_reading(1);
352                 Joy_last_y_reading = *y;
353         }
354
355         if (z && joystick.num_axes > 2) {
356                 *z = joy_get_unscaled_reading(2);
357         }
358
359         if (rx && joystick.num_axes > 3) {
360                 *rx = joy_get_scaled_reading(3);
361         }
362
363         return 1;
364 }
365
366 int joy_init()
367 {
368         int i, num_sticks;
369
370         if (Joy_inited) {
371                 return 0;
372         }
373
374         if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0) {
375                 mprintf(("Could not initialize joystick\n"));
376                 return 0;
377         }
378
379         num_sticks = SDL_NumJoysticks();
380
381         if (num_sticks < 1) {
382                 mprintf(("No joysticks found\n"));
383                 return 0;
384         }
385
386         Cur_joystick = os_config_read_uint (NULL, "CurrentJoystick", 0);
387
388         if (Cur_joystick >= num_sticks) {
389                 Cur_joystick = 0;
390         }
391
392         joy_get_caps();
393
394         sdljoy = SDL_JoystickOpen(Cur_joystick);
395
396         if (sdljoy == NULL) {
397                 mprintf(("Unable to init joystick %d\n", Cur_joystick));
398                 return 0;
399         }
400
401         Joy_inited = 1;
402
403         joy_id = SDL_JoystickInstanceID(sdljoy);
404
405         joystick.num_axes = SDL_JoystickNumAxes(sdljoy);
406
407         joy_flush();
408
409         // Fake a calibration
410         joy_set_cen();
411
412         for (i = 0; i < JOY_NUM_AXES; i++) {
413                 joystick.axis_min[i] = 0;
414                 joystick.axis_max[i] = 65536;
415                 joystick.axis_current[i] = 32768;
416         }
417
418         joy_ff_init();
419
420         return num_sticks;
421 }
422
423 void joy_set_cen()
424 {
425         if ( !Joy_inited ) {
426                 return;
427         }
428
429         for (int i = 0; i < JOY_NUM_AXES; i++) {
430                 if (i < joystick.num_axes) {
431                         joystick.axis_center[i] = SDL_JoystickGetAxis(sdljoy, i) + 32768;
432                 } else {
433                         joystick.axis_center[i] = 32768;
434                 }
435         }
436 }
437
438 int joystick_read_raw_axis(int num_axes, int *axis)
439 {
440         int i;
441
442         if ( !Joy_inited ) {
443                 return 0;
444         }
445
446         for (i = 0; i < num_axes; i++) {
447                 if (i < joystick.num_axes) {
448                         axis[i] = joystick.axis_current[i];
449                 } else {
450                         axis[i] = 32768;
451                 }
452         }
453
454         return 1;
455 }
456
457 bool joy_axis_valid(int axis)
458 {
459         return (axis < joystick.num_axes);
460 }
461
462 void joystick_update_axis(int axis, int value)
463 {
464         if (axis < JOY_NUM_AXES) {
465                 joystick.axis_current[axis] = value + 32768;
466         }
467 }