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