]> icculus.org git repositories - taylor/freespace2.git/blob - src/io/joy-sdl.cpp
Oops.
[taylor/freespace2.git] / src / io / joy-sdl.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 static int Joy_inited = 0;
19 int joy_num_sticks = 0;
20 int Dead_zone_size = 10;
21 int Cur_joystick = -1;
22 int Joy_sensitivity = 9;
23
24 int joy_pollrate = 1000 / 18;  // poll at 18Hz
25
26 static int Joy_last_x_reading = 0;
27 static int Joy_last_y_reading = 0;
28
29 typedef struct joy_button_info {
30         int     actual_state;           // Set if the button is physically down
31         int     state;                          // Set when the button goes from up to down, cleared on down to up.  Different than actual_state after a flush.
32         int     down_count;
33         int     up_count;
34         int     down_time;
35         uint    last_down_check;        // timestamp in milliseconds of last 
36 } joy_button_info;
37
38 Joy_info joystick;
39
40 int JOYSTICKID1 = 0;    // DDOI - temporary
41 static SDL_Joystick *sdljoy;
42
43 joy_button_info joy_buttons[JOY_TOTAL_BUTTONS];
44
45
46 void joy_close()
47 {
48         if (!Joy_inited)
49                 return;
50
51         Joy_inited = 0;
52         joy_num_sticks = 0;
53         
54         if (sdljoy)
55                 SDL_JoystickClose(sdljoy);
56         sdljoy = NULL;
57         
58         SDL_QuitSubSystem (SDL_INIT_JOYSTICK);
59 }
60
61 void joy_get_caps (int max)
62 {
63         SDL_Joystick *joy;
64         int j;
65
66         for (j=0; j < JOY_NUM_AXES; j++)
67                 joystick.axis_valid[j] = 0;
68
69         for (j=JOYSTICKID1; j<JOYSTICKID1+max; j++) {
70                 joy = SDL_JoystickOpen (j);
71                 if (joy)
72                 {
73                         nprintf (("JOYSTICK", "Joystick #%d: %s\n", j - JOYSTICKID1 + 1, SDL_JoystickName(j)));
74                         if (j == Cur_joystick) {
75                                 for (int i = 0; i < SDL_JoystickNumAxes(joy); i++)
76                                 {
77                                         joystick.axis_valid[i] = 1;
78                                 }
79                         }
80                         SDL_JoystickClose (joy);
81                 }
82         }
83 }
84
85 int joy_down(int btn)
86 {
87         int tmp;
88
89         if ( joy_num_sticks < 1 ) return 0;
90         if ( (btn < 0) || (btn >= JOY_TOTAL_BUTTONS )) return 0;
91
92         tmp = joy_buttons[btn].state;
93
94         return tmp;
95 }
96
97 int joy_down_count(int btn, int reset_count)
98 {
99         int tmp;
100
101         if ( joy_num_sticks < 1 ) return 0;
102         if ( (btn < 0) || (btn >= JOY_TOTAL_BUTTONS)) return 0;
103
104         tmp = joy_buttons[btn].down_count;
105         if ( reset_count ) {
106                 joy_buttons[btn].down_count = 0;
107         }
108
109         return tmp;
110 }
111
112 float joy_down_time(int btn)
113 {
114         float                           rval;
115         unsigned int    now;
116         joy_button_info         *bi;
117
118         if ( joy_num_sticks < 1 ) return 0.0f;
119         if ( (btn < 0) || (btn >= JOY_TOTAL_BUTTONS)) return 0.0f;
120         bi = &joy_buttons[btn];
121
122         now = timer_get_milliseconds();
123
124         if ( bi->down_time == 0 && joy_down(btn) ) {
125                 bi->down_time += joy_pollrate;
126         }
127
128         if ( (now - bi->last_down_check) > 0)
129                 rval = i2fl(bi->down_time) / (now - bi->last_down_check);
130         else
131                 rval = 0.0f;
132
133         bi->down_time = 0;
134         bi->last_down_check = now;
135
136         if (rval < 0)
137                 rval = 0.0f;
138         if (rval > 1)
139                 rval = 1.0f;
140
141         return rval;
142 }
143
144 void joy_flush()
145 {
146         int                     i;
147         joy_button_info *bi;
148
149         if ( joy_num_sticks < 1 ) return;
150
151         for ( i = 0; i < JOY_TOTAL_BUTTONS; i++) {
152                 bi = &joy_buttons[i];
153                 bi->state               = 0;
154                 bi->down_count  = 0;
155                 bi->up_count    = 0;
156                 bi->down_time   = 0;
157                 bi->last_down_check = timer_get_milliseconds();
158         }
159 }
160
161 int joy_get_unscaled_reading(int raw, int axn)
162 {
163         int rng;
164
165         // Make sure it's calibrated properly.
166         if (joystick.axis_center[axn] - joystick.axis_min[axn] < 5)
167                 return 0;
168
169         if (joystick.axis_max[axn] - joystick.axis_center[axn] < 5)
170                 return 0;
171
172         rng = joystick.axis_max[axn] - joystick.axis_min[axn];
173         raw -= joystick.axis_min[axn];  // adjust for linear range starting at 0
174         
175         // cap at limits
176         if (raw < 0)
177                 raw = 0;
178         if (raw > rng)
179                 raw = rng;
180
181         return (int) ((unsigned int) raw * (unsigned int) F1_0 / (unsigned int) rng);  // convert to 0 - F1_0 range.
182 }
183
184 // --------------------------------------------------------------
185 //      joy_get_scaled_reading()
186 //
187 //      input:  raw     =>      the raw value for an axis position
188 //                              axn     =>      axis number, numbered starting at 0
189 //
190 // return:      joy_get_scaled_reading will return a value that represents
191 //                              the joystick pos from -1 to +1 for the specified axis number 'axn', and
192 //                              the raw value 'raw'
193 //
194 int joy_get_scaled_reading(int raw, int axn)
195 {
196         int x, d, dead_zone, rng;
197         float percent, sensitivity_percent, non_sensitivity_percent;
198
199         // Make sure it's calibrated properly.
200         if (joystick.axis_center[axn] - joystick.axis_min[axn] < 5)
201                 return 0;
202
203         if (joystick.axis_max[axn] - joystick.axis_center[axn] < 5)
204                 return 0;
205
206         raw -= joystick.axis_center[axn];
207
208         dead_zone = (joystick.axis_max[axn] - joystick.axis_min[axn]) * Dead_zone_size / 100;
209
210         if (raw < -dead_zone) {
211                 rng = joystick.axis_center[axn] - joystick.axis_min[axn] - dead_zone;
212                 d = -raw - dead_zone;
213
214         } else if (raw > dead_zone) {
215                 rng = joystick.axis_max[axn] - joystick.axis_center[axn] - dead_zone;
216                 d = raw - dead_zone;
217
218         } else
219                 return 0;
220
221         if (d > rng)
222                 d = rng;
223
224         Assert(Joy_sensitivity >= 0 && Joy_sensitivity <= 9);
225
226         // compute percentages as a range between 0 and 1
227         sensitivity_percent = (float) Joy_sensitivity / 9.0f;
228         non_sensitivity_percent = (float) (9 - Joy_sensitivity) / 9.0f;
229
230         // find percent of max axis is at
231         percent = (float) d / (float) rng;
232
233         // work sensitivity on axis value
234         percent = (percent * sensitivity_percent + percent * percent * percent * percent * percent * non_sensitivity_percent);
235
236         x = (int) ((float) F1_0 * percent);
237
238         //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));
239
240         if (raw < 0)
241                 return -x;
242
243         return x;
244 }
245
246 // --------------------------------------------------------------
247 //      joy_get_pos()
248 //
249 //      input:  x               =>              OUTPUT PARAMETER: x-axis position of stick (-1 to 1)
250 //                              y               =>              OUTPUT PARAMETER: y-axis position of stick (-1 to 1)
251 //                              z               =>              OUTPUT PARAMETER: z-axis (throttle) position of stick (-1 to 1)
252 //                              r               =>              OUTPUT PARAMETER: rudder position of stick (-1 to 1)
253 //
254 //      return: success => 1
255 //                              failure => 0
256 //
257 int joy_get_pos(int *x, int *y, int *z, int *rx)
258 {
259         int axis[JOY_NUM_AXES];
260
261         if (x) *x = 0;
262         if (y) *y = 0;
263         if (z) *z = 0;
264         if (rx) *rx = 0;
265
266         if (joy_num_sticks < 1) return 0;
267
268         joystick_read_raw_axis( 6, axis );
269
270         //      joy_get_scaled_reading will return a value represents the joystick pos from -1 to +1
271         if (x && joystick.axis_valid[0])
272                 *x = joy_get_scaled_reading(axis[0], 0);
273         if (y && joystick.axis_valid[1]) 
274                 *y = joy_get_scaled_reading(axis[1], 1);
275         if (z && joystick.axis_valid[2])
276                 *z = joy_get_unscaled_reading(axis[2], 2);
277         if (rx && joystick.axis_valid[3])
278                 *rx = joy_get_scaled_reading(axis[3], 3);
279
280         if (x)
281                 Joy_last_x_reading = *x;
282
283         if (y)
284                 Joy_last_y_reading = *y;
285
286         return 1;
287 }
288
289 void joy_process(int time_delta)
290 {
291         int i;
292         
293         if (!Joy_inited)
294                 return;
295         if (sdljoy == NULL)
296                 return;
297         
298         int buttons = SDL_JoystickNumButtons(sdljoy);
299         int hat = SDL_JoystickGetHat(sdljoy, 0);
300         
301         for (i=0; i < JOY_TOTAL_BUTTONS; i++) {
302                 int state = 0;
303                 
304                 if (i < JOY_NUM_BUTTONS) {
305                         if (i < buttons) {
306                                 state = SDL_JoystickGetButton(sdljoy, i);
307                         }
308                 } else { 
309                         switch (i) {
310                                 case JOY_HATBACK:
311                                         state = (hat & SDL_HAT_DOWN) ? 1 : 0;
312                                         break;
313                                 case JOY_HATFORWARD:
314                                         state = (hat & SDL_HAT_UP) ? 1 : 0;
315                                         break;
316                                 case JOY_HATLEFT:
317                                         state = (hat & SDL_HAT_LEFT) ? 1 : 0;
318                                         break;
319                                 case JOY_HATRIGHT:
320                                         state = (hat & SDL_HAT_RIGHT) ? 1 : 0;
321                                         break;
322                                 default:
323                                         break;
324                         }
325                 }
326                 
327                 if (state != joy_buttons[i].actual_state) {
328                         // Button position physically changed.
329                         joy_buttons[i].actual_state = state;
330                         
331                         if ( state )    {
332                                 // went from up to down
333                                 joy_buttons[i].down_count++;
334                                 joy_buttons[i].down_time = 0;
335                                 
336                                 joy_buttons[i].state = 1;
337                         } else {
338                                 // went from down to up
339                                 if ( joy_buttons[i].state )     {
340                                         joy_buttons[i].up_count++;
341                                 }
342                                 
343                                 joy_buttons[i].state = 0;
344                         }
345                 } else {
346                         // Didn't move... increment time down if down.
347                         if (joy_buttons[i].state) {
348                                 //joy_buttons[i].down_time += joy_pollrate;
349                                 joy_buttons[i].down_time += time_delta;
350                         }
351                 }       
352         }
353 }
354
355 void joy_read()
356 {
357     static Uint32 lasttic = 0;
358     Uint32 curtic = SDL_GetTicks();
359     Uint32 delta = curtic - lasttic;
360     
361     while (delta >= (uint)joy_pollrate) {
362         joy_process(delta);
363         
364         lasttic += joy_pollrate;
365         
366         delta = curtic - lasttic;
367     }
368 }
369
370 int joy_init()
371 {
372         int i, n;
373
374         if (Joy_inited)
375                 return 0;
376
377         if (SDL_InitSubSystem (SDL_INIT_JOYSTICK)<0)
378         {
379                 mprintf(("Could not initialize joystick\n"));
380                 return 0;
381         }
382
383         Joy_inited = 1;
384         n = SDL_NumJoysticks ();
385
386         Cur_joystick = os_config_read_uint (NULL, "CurrentJoystick", JOYSTICKID1);
387
388         joy_get_caps(n);
389
390         if (n < 1) {
391                 mprintf(("No joysticks found\n"));
392                 return 0;
393         }
394
395         sdljoy = SDL_JoystickOpen(Cur_joystick);
396         if (sdljoy == NULL) {
397                 mprintf(("Unable to init joystick %d\n", Cur_joystick));
398         }
399         
400         joy_flush ();
401
402         joy_num_sticks = n;
403
404         // Fake a calibration
405         if (joy_num_sticks > 0) {
406                 // joy_set_cen();
407                 for (i=0; i<4; i++) {
408                         joystick.axis_center[i] = 32768;
409                         joystick.axis_min[i] = 0;
410                         joystick.axis_max[i] = 65536;
411                 }
412         }
413
414         return joy_num_sticks;
415 }
416
417 void joy_set_cen()
418 {
419         joystick_read_raw_axis( 2, joystick.axis_center );
420 }
421
422 int joystick_read_raw_axis(int num_axes, int *axis)
423 {
424         int i;
425         int num;
426         
427         if (sdljoy == NULL)
428                 return 0;
429         
430         num = SDL_JoystickNumAxes(sdljoy);
431         
432         for (i = 0; i < num_axes; i++) {
433                 if (i < num) {
434                         axis[i] = SDL_JoystickGetAxis(sdljoy, i) + 32768;
435                 } else {
436                         axis[i] = 32768;
437                 }
438         }
439         
440         return 1;
441 }
442
443 void joy_ff_adjust_handling(int speed)
444 {
445 //      STUB_FUNCTION;
446 }
447
448 void joy_ff_afterburn_off()
449 {
450 //      STUB_FUNCTION;
451 }
452
453 void joy_ff_afterburn_on()
454 {
455 //      STUB_FUNCTION;
456 }
457
458 void joy_ff_deathroll()
459 {
460 //      STUB_FUNCTION;
461 }
462
463 void joy_ff_docked()
464 {
465 //      STUB_FUNCTION;
466 }
467
468 void joy_ff_explode()
469 {
470 //      STUB_FUNCTION;
471 }
472
473 void joy_ff_fly_by(int mag)
474 {
475 //      STUB_FUNCTION;
476 }
477
478 void joy_ff_mission_init(vector v)
479 {
480 //      STUB_FUNCTION;
481 }
482
483 void joy_ff_play_dir_effect(float x, float y)
484 {
485 //      STUB_FUNCTION;
486 }
487
488 void joy_ff_play_primary_shoot(int gain)
489 {
490 //      STUB_FUNCTION;
491 }
492
493 void joy_ff_play_reload_effect()
494 {
495 //      STUB_FUNCTION;
496 }
497
498 void joy_ff_play_secondary_shoot(int gain)
499 {
500 //      STUB_FUNCTION;
501 }
502
503 void joy_ff_play_vector_effect(vector *v, float scaler)
504 {
505 //      STUB_FUNCTION;
506 }
507
508 void joy_ff_stop_effects()
509 {
510         joy_ff_afterburn_off();
511 }