]> icculus.org git repositories - btb/d2x.git/blob - arch/sdl/joy.c
Fix sdl joystick axis problem, all arch use global variable joy_num_axes
[btb/d2x.git] / arch / sdl / joy.c
1 /* $Id: joy.c,v 1.14 2004-11-22 23:32:54 btb Exp $ */
2 /*
3  *
4  * SDL joystick support
5  *
6  *
7  */
8
9 #ifdef HAVE_CONFIG_H
10 #include <conf.h>
11 #endif
12
13 #include <string.h>   // for memset
14 #include <SDL.h>
15
16 #include "joy.h"
17 #include "error.h"
18 #include "timer.h"
19 #include "console.h"
20 #include "event.h"
21 #include "text.h"
22
23 #define MAX_JOYSTICKS 16
24
25 #define MAX_AXES_PER_JOYSTICK 8
26 #define MAX_BUTTONS_PER_JOYSTICK 16
27 #define MAX_HATS_PER_JOYSTICK 4
28
29 extern int joybutton_text[]; //from kconfig.c
30
31 char joy_present = 0;
32 int num_joysticks = 0;
33
34 int joy_deadzone = 0;
35
36 int joy_num_axes = 0;
37
38 struct joybutton {
39         int state;
40         int last_state;
41         fix time_went_down;
42         int num_downs;
43         int num_ups;
44 };
45
46 struct joyaxis {
47         int             value;
48         int             min_val;
49         int             center_val;
50         int             max_val;
51 };
52
53 /* This struct is a "virtual" joystick, which includes all the axes
54  * and buttons of every joystick found.
55  */
56 static struct joyinfo {
57         int n_axes;
58         int n_buttons;
59         struct joyaxis axes[JOY_MAX_AXES];
60         struct joybutton buttons[MAX_BUTTONS];
61 } Joystick;
62
63 /* This struct is an array, with one entry for each physical joystick
64  * found.
65  */
66 static struct {
67         SDL_Joystick *handle;
68         int n_axes;
69         int n_buttons;
70         int n_hats;
71         int hat_map[MAX_HATS_PER_JOYSTICK];  //Note: Descent expects hats to be buttons, so these are indices into Joystick.buttons
72         int axis_map[MAX_AXES_PER_JOYSTICK];
73         int button_map[MAX_BUTTONS_PER_JOYSTICK];
74 } SDL_Joysticks[MAX_JOYSTICKS];
75
76 void joy_button_handler(SDL_JoyButtonEvent *jbe)
77 {
78         int button;
79
80         button = SDL_Joysticks[jbe->which].button_map[jbe->button];
81
82         Joystick.buttons[button].state = jbe->state;
83
84         switch (jbe->type) {
85         case SDL_JOYBUTTONDOWN:
86                 Joystick.buttons[button].time_went_down
87                         = timer_get_fixed_seconds();
88                 Joystick.buttons[button].num_downs++;
89                 break;
90         case SDL_JOYBUTTONUP:
91                 Joystick.buttons[button].num_ups++;
92                 break;
93         }
94 }
95
96 void joy_hat_handler(SDL_JoyHatEvent *jhe)
97 {
98         int hat = SDL_Joysticks[jhe->which].hat_map[jhe->hat];
99         int hbi;
100
101         //Save last state of the hat-button
102         Joystick.buttons[hat  ].last_state = Joystick.buttons[hat  ].state;
103         Joystick.buttons[hat+1].last_state = Joystick.buttons[hat+1].state;
104         Joystick.buttons[hat+2].last_state = Joystick.buttons[hat+2].state;
105         Joystick.buttons[hat+3].last_state = Joystick.buttons[hat+3].state;
106
107         //get current state of the hat-button
108         Joystick.buttons[hat  ].state = ((jhe->value & SDL_HAT_UP)>0);
109         Joystick.buttons[hat+1].state = ((jhe->value & SDL_HAT_RIGHT)>0);
110         Joystick.buttons[hat+2].state = ((jhe->value & SDL_HAT_DOWN)>0);
111         Joystick.buttons[hat+3].state = ((jhe->value & SDL_HAT_LEFT)>0);
112
113         //determine if a hat-button up or down event based on state and last_state
114         for(hbi=0;hbi<4;hbi++)
115         {
116                 if(     !Joystick.buttons[hat+hbi].last_state && Joystick.buttons[hat+hbi].state) //last_state up, current state down
117                 {
118                         Joystick.buttons[hat+hbi].time_went_down
119                                 = timer_get_fixed_seconds();
120                         Joystick.buttons[hat+hbi].num_downs++;
121                 }
122                 else if(Joystick.buttons[hat+hbi].last_state && !Joystick.buttons[hat+hbi].state)  //last_state down, current state up
123                 {
124                         Joystick.buttons[hat+hbi].num_ups++;
125                 }
126         }
127 }
128
129 void joy_axis_handler(SDL_JoyAxisEvent *jae)
130 {
131         int axis;
132
133         axis = SDL_Joysticks[jae->which].axis_map[jae->axis];
134         
135         Joystick.axes[axis].value = jae->value;
136 }
137
138
139 /* ----------------------------------------------- */
140
141 int joy_init()
142 {
143         int i,j,n;
144
145         if (SDL_Init(SDL_INIT_JOYSTICK) < 0) {
146                 con_printf(CON_VERBOSE, "sdl-joystick: initialisation failed: %s.",SDL_GetError());
147                 return 0;
148         }
149
150         memset(&Joystick,0,sizeof(Joystick));
151
152         n = SDL_NumJoysticks();
153
154         con_printf(CON_VERBOSE, "sdl-joystick: found %d joysticks\n", n);
155         for (i = 0; i < n; i++) {
156                 con_printf(CON_VERBOSE, "sdl-joystick %d: %s\n", i, SDL_JoystickName(i));
157                 SDL_Joysticks[num_joysticks].handle = SDL_JoystickOpen(i);
158                 if (SDL_Joysticks[num_joysticks].handle) {
159                         joy_present = 1;
160
161                         SDL_Joysticks[num_joysticks].n_axes
162                                 = SDL_JoystickNumAxes(SDL_Joysticks[num_joysticks].handle);
163                         if(SDL_Joysticks[num_joysticks].n_axes > MAX_AXES_PER_JOYSTICK)
164                         {
165                                 Warning("sdl-joystick: found %d axes, only %d supported.  Game may be unstable.\n", SDL_Joysticks[num_joysticks].n_axes, MAX_AXES_PER_JOYSTICK);
166                                 SDL_Joysticks[num_joysticks].n_axes = MAX_AXES_PER_JOYSTICK;
167                         }
168
169                         SDL_Joysticks[num_joysticks].n_buttons
170                                 = SDL_JoystickNumButtons(SDL_Joysticks[num_joysticks].handle);
171                         if(SDL_Joysticks[num_joysticks].n_buttons > MAX_BUTTONS_PER_JOYSTICK)
172                         {
173                                 Warning("sdl-joystick: found %d buttons, only %d supported.  Game may be unstable.\n", SDL_Joysticks[num_joysticks].n_buttons, MAX_BUTTONS_PER_JOYSTICK);
174                                 SDL_Joysticks[num_joysticks].n_buttons = MAX_BUTTONS_PER_JOYSTICK;
175                         }
176
177                         SDL_Joysticks[num_joysticks].n_hats
178                                 = SDL_JoystickNumHats(SDL_Joysticks[num_joysticks].handle);
179                         if(SDL_Joysticks[num_joysticks].n_hats > MAX_HATS_PER_JOYSTICK)
180                         {
181                                 Warning("sdl-joystick: found %d hats, only %d supported.  Game may be unstable.\n", SDL_Joysticks[num_joysticks].n_hats, MAX_HATS_PER_JOYSTICK);
182                                 SDL_Joysticks[num_joysticks].n_hats = MAX_HATS_PER_JOYSTICK;
183                         }
184
185                         con_printf(CON_VERBOSE, "sdl-joystick: %d axes\n", SDL_Joysticks[num_joysticks].n_axes);
186                         con_printf(CON_VERBOSE, "sdl-joystick: %d buttons\n", SDL_Joysticks[num_joysticks].n_buttons);
187                         con_printf(CON_VERBOSE, "sdl-joystick: %d hats\n", SDL_Joysticks[num_joysticks].n_hats);
188
189                         for (j=0; j < SDL_Joysticks[num_joysticks].n_axes; j++)
190                                 SDL_Joysticks[num_joysticks].axis_map[j] = Joystick.n_axes++;
191                         for (j=0; j < SDL_Joysticks[num_joysticks].n_buttons; j++)
192                                 SDL_Joysticks[num_joysticks].button_map[j] = Joystick.n_buttons++;
193                         for (j=0; j < SDL_Joysticks[num_joysticks].n_hats; j++)
194                         {
195                                 SDL_Joysticks[num_joysticks].hat_map[j] = Joystick.n_buttons;
196                                 //a hat counts as four buttons
197                                 joybutton_text[Joystick.n_buttons++] = j?TNUM_HAT2_U:TNUM_HAT_U;
198                                 joybutton_text[Joystick.n_buttons++] = j?TNUM_HAT2_R:TNUM_HAT_R;
199                                 joybutton_text[Joystick.n_buttons++] = j?TNUM_HAT2_D:TNUM_HAT_D;
200                                 joybutton_text[Joystick.n_buttons++] = j?TNUM_HAT2_L:TNUM_HAT_L;
201                         }
202
203                         num_joysticks++;
204                 }
205                 else
206                         con_printf(CON_VERBOSE, "sdl-joystick: initialization failed!\n");
207
208                 con_printf(CON_VERBOSE, "sdl-joystick: %d axes (total)\n", Joystick.n_axes);
209                 con_printf(CON_VERBOSE, "sdl-joystick: %d buttons (total)\n", Joystick.n_buttons);
210         }
211
212         joy_num_axes = Joystick.n_axes;
213
214         return joy_present;
215 }
216
217 void joy_close()
218 {
219         while (num_joysticks)
220                 SDL_JoystickClose(SDL_Joysticks[--num_joysticks].handle);
221 }
222
223 void joy_get_pos(int *x, int *y)
224 {
225         int axis[JOY_MAX_AXES];
226
227         if (!num_joysticks) {
228                 *x=*y=0;
229                 return;
230         }
231
232         joystick_read_raw_axis (JOY_ALL_AXIS, axis);
233
234         *x = joy_get_scaled_reading( axis[0], 0 );
235         *y = joy_get_scaled_reading( axis[1], 1 );
236 }
237
238 int joy_get_btns()
239 {
240 #if 0 // This is never used?
241         int i, buttons = 0;
242         for (i=0; i++; i<buttons) {
243                 switch (Joystick.buttons[i].state) {
244                 case SDL_PRESSED:
245                         buttons |= 1<<i;
246                         break;
247                 case SDL_RELEASED:
248                         break;
249                 }
250         }
251         return buttons;
252 #else
253         return 0;
254 #endif
255 }
256
257 int joy_get_button_down_cnt( int btn )
258 {
259         int num_downs;
260
261         if (!num_joysticks)
262                 return 0;
263
264         event_poll();
265
266         num_downs = Joystick.buttons[btn].num_downs;
267         Joystick.buttons[btn].num_downs = 0;
268
269         return num_downs;
270 }
271
272 fix joy_get_button_down_time(int btn)
273 {
274         fix time = F0_0;
275
276         if (!num_joysticks)
277                 return 0;
278
279         event_poll();
280
281         switch (Joystick.buttons[btn].state) {
282         case SDL_PRESSED:
283                 time = timer_get_fixed_seconds() - Joystick.buttons[btn].time_went_down;
284                 Joystick.buttons[btn].time_went_down = timer_get_fixed_seconds();
285                 break;
286         case SDL_RELEASED:
287                 time = 0;
288                 break;
289         }
290
291         return time;
292 }
293
294 ubyte joystick_read_raw_axis( ubyte mask, int * axis )
295 {
296         int i;
297         ubyte channel_masks = 0;
298         
299         if (!num_joysticks)
300                 return 0;
301
302         event_poll();
303
304         for (i = 0; i < Joystick.n_axes; i++) {
305                 if ((axis[i] = Joystick.axes[i].value))
306                         channel_masks |= 1 << i;
307         }
308
309         return channel_masks;
310 }
311
312 void joy_flush()
313 {
314         int i;
315
316         if (!num_joysticks)
317                 return;
318
319         for (i = 0; i < Joystick.n_buttons; i++) {
320                 Joystick.buttons[i].time_went_down = 0;
321                 Joystick.buttons[i].num_downs = 0;
322         }
323         
324 }
325
326 int joy_get_button_state( int btn )
327 {
328         if (!num_joysticks)
329                 return 0;
330
331         if(btn >= Joystick.n_buttons)
332                 return 0;
333
334         event_poll();
335
336         return Joystick.buttons[btn].state;
337 }
338
339 void joy_get_cal_vals(int *axis_min, int *axis_center, int *axis_max)
340 {
341         int i;
342
343         for (i = 0; i < Joystick.n_axes; i++) {
344                 axis_center[i] = Joystick.axes[i].center_val;
345                 axis_min[i] = Joystick.axes[i].min_val;
346                 axis_max[i] = Joystick.axes[i].max_val;
347         }
348 }
349
350 void joy_set_cal_vals(int *axis_min, int *axis_center, int *axis_max)
351 {
352         int i;
353
354         for (i = 0; i < Joystick.n_axes; i++) {
355                 Joystick.axes[i].center_val = axis_center[i];
356                 Joystick.axes[i].min_val = axis_min[i];
357                 Joystick.axes[i].max_val = axis_max[i];
358         }
359 }
360
361 int joy_get_scaled_reading( int raw, int axis_num )
362 {
363 #if 1
364         return raw/256;
365 #else
366         int d, x;
367
368         raw -= Joystick.axes[axis_num].center_val;
369         
370         if (raw < 0)
371                 d = Joystick.axes[axis_num].center_val - Joystick.axes[axis_num].min_val;
372         else if (raw > 0)
373                 d = Joystick.axes[axis_num].max_val - Joystick.axes[axis_num].center_val;
374         else
375                 d = 0;
376         
377         if (d)
378                 x = ((raw << 7) / d);
379         else
380                 x = 0;
381         
382         if ( x < -128 )
383                 x = -128;
384         if ( x > 127 )
385                 x = 127;
386         
387         d =  (joy_deadzone) * 6;
388         if ((x > (-1*d)) && (x < d))
389                 x = 0;
390         
391         return x;
392 #endif
393 }
394
395 void joy_set_slow_reading( int flag )
396 {
397 }