]> icculus.org git repositories - btb/d2x.git/blob - arch/dos/joyc.c
divide negative window x-coordinates properly, fixing random crashes
[btb/d2x.git] / arch / dos / joyc.c
1 /* $Id: joyc.c,v 1.7 2005-04-04 09:18:08 btb Exp $ */
2 /*
3 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
4 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
5 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
6 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
7 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
8 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
9 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
10 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
11 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
12 COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
13 */
14
15 /*
16  * 
17  * Routines for joystick reading.
18  * 
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include <conf.h>
23 #endif
24
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <dos.h>
28
29 //#define ARCADE 1
30
31 #include "pstypes.h"
32 #include "mono.h"
33 #include "joy.h"
34 #include "u_dpmi.h"
35 #include "timer.h"
36
37 #include "args.h"
38
39 extern int joy_bogus_reading;
40 int JOY_PORT = 513; //201h;
41 int joy_deadzone = 0;
42
43 int joy_read_stick_asm2( int read_masks, int * event_buffer, int timeout );
44 int joy_read_stick_friendly2( int read_masks, int * event_buffer, int timeout );
45 int joy_read_stick_polled2( int read_masks, int * event_buffer, int timeout );
46 int joy_read_stick_bios2( int read_masks, int * event_buffer, int timeout );
47 int joy_read_buttons_bios2();
48 void joy_read_buttons_bios_end2();
49
50
51 //In key.c
52 // ebx = read mask                                                                           
53 // edi = pointer to buffer                                                                                                                                                                                      
54 // returns number of events                                                                                                                                                                             
55
56 char joy_installed = 0;
57 char joy_present = 0;
58
59 typedef struct Button_info {
60         ubyte           ignore;
61         ubyte           state;
62         ubyte           last_state;
63         int             timedown;
64         ubyte           downcount;
65         ubyte           upcount;
66 } Button_info;
67
68 typedef struct Joy_info {
69         ubyte                   present_mask;
70         ubyte                   slow_read;
71         int                     max_timer;
72         int                     read_count;
73         ubyte                   last_value;
74         Button_info buttons[JOY_MAX_BUTTONS];
75         int                     axis_min[4];
76         int                     axis_center[4];
77         int                     axis_max[4];
78 } Joy_info;
79
80 Joy_info joystick;
81
82 ubyte joy_read_buttons()
83 {
84  return ((~(inp(JOY_PORT) >> 4))&0xf);
85 }
86
87 void joy_get_cal_vals(int *axis_min, int *axis_center, int *axis_max)
88 {
89         int i;
90
91         for (i = 0; i < JOY_NUM_AXES; i++)
92         {
93                 axis_min[i] = joystick.axis_min[i];
94                 axis_center[i] = joystick.axis_center[i];
95                 axis_max[i] = joystick.axis_max[i];
96         }
97 }
98
99 void joy_set_cal_vals(int *axis_min, int *axis_center, int *axis_max)
100 {
101         int i;
102
103         for (i = 0; i < JOY_NUM_AXES; i++)
104         {
105                 joystick.axis_min[i] = axis_min[i];
106                 joystick.axis_center[i] = axis_center[i];
107                 joystick.axis_max[i] = axis_max[i];
108         }
109 }
110
111
112 ubyte joy_get_present_mask()    {
113         return joystick.present_mask;
114 }
115
116 void joy_set_timer_rate(int max_value ) {
117         _disable();
118         joystick.max_timer = max_value;
119         _enable();
120 }
121
122 int joy_get_timer_rate()        {
123         return joystick.max_timer;
124 }
125
126
127 void joy_flush()        {
128         int i;
129
130         if (!joy_installed) return;
131
132         _disable();
133         for (i = 0; i < JOY_MAX_BUTTONS; i++)
134         {
135                 joystick.buttons[i].ignore = 0;
136                 joystick.buttons[i].state = 0;
137                 joystick.buttons[i].timedown = 0;
138                 joystick.buttons[i].downcount = 0;      
139                 joystick.buttons[i].upcount = 0;        
140         }
141         _enable();
142
143 }
144
145
146 void joy_handler(int ticks_this_time)   {
147         ubyte value;
148         int i, state;
149         Button_info * button;
150
151 //      joystick.max_timer = ticks_this_time;
152
153         if ( joystick.slow_read & JOY_BIOS_READINGS )           {
154                 joystick.read_count++;
155                 if ( joystick.read_count > 7 )  {
156                         joystick.read_count = 0;
157                         value = joy_read_buttons_bios2();
158                         joystick.last_value = value;
159                 } else {
160                         value = joystick.last_value;
161                 }               
162         } else {
163                 value = joy_read_buttons(); //JOY_READ_BUTTONS;
164         }
165
166         for (i = 0; i < JOY_MAX_BUTTONS; i++)
167         {
168                 button = &joystick.buttons[i];
169                 if (!button->ignore) {
170                         if ( i < 5 )
171                                 state = (value >> i) & 1;
172                         else if (i==(value+4))  
173                                 state = 1;
174                         else
175                                 state = 0;
176
177                         if ( button->last_state == state )      {
178                                 if (state) button->timedown += ticks_this_time;
179                         } else {
180                                 if (state)      {
181                                         button->downcount += state;
182                                         button->state = 1;
183                                 } else {        
184                                         button->upcount += button->state;
185                                         button->state = 0;
186                                 }
187                                 button->last_state = state;
188                         }
189                 }
190         }
191 }
192
193 void joy_handler_end()  {               // Dummy function to help calculate size of joystick handler function
194 }
195
196
197 ubyte joy_read_raw_buttons()    {
198         if ( joystick.slow_read & JOY_BIOS_READINGS )   
199                 return joy_read_buttons_bios2();
200         else 
201                 return joy_read_buttons(); //JOY_READ_BUTTONS;
202 }
203
204 void joy_set_slow_reading(int flag)
205 {
206         joystick.slow_read |= flag;
207         joy_set_cen();
208 }
209
210 ubyte joystick_read_raw_axis( ubyte mask, int * axis )
211 {
212         ubyte read_masks, org_masks;
213         int t, t1, t2, buffer[4*2+2];
214         int e, i, num_channels, c;
215
216         axis[0] = 0; axis[1] = 0;
217         axis[2] = 0; axis[3] = 0;
218
219         if (!joy_installed) return 0;
220
221         read_masks = 0;
222         org_masks = mask;
223
224         mask &= joystick.present_mask;                  // Don't read non-present channels
225         if ( mask==0 )  {
226                 return 0;               // Don't read if no stick connected.
227         }
228
229         if ( joystick.slow_read & JOY_SLOW_READINGS )   {
230                 for (c=0; c<4; c++ )    {               
231                         if ( mask & (1 << c))   {
232                                 // Time out at  (1/100th of a second)
233
234                                 if ( joystick.slow_read & JOY_POLLED_READINGS )
235                                         num_channels = joy_read_stick_polled2( (1 << c), buffer, 65536 );
236                                 else if ( joystick.slow_read & JOY_BIOS_READINGS )
237                                         num_channels = joy_read_stick_bios2( (1 << c), buffer, 65536 );
238                                 else if ( joystick.slow_read & JOY_FRIENDLY_READINGS )
239                                         num_channels = joy_read_stick_friendly2( (1 << c), buffer, (1193180/100) );
240                                 else
241                                         num_channels = joy_read_stick_asm2( (1 << c), buffer, (1193180/100) );
242         
243                                 if ( num_channels > 0 ) {
244                                         t1 = buffer[0];
245                                         e = buffer[1];
246                                         t2 = buffer[2];
247                                         if ( joystick.slow_read & (JOY_POLLED_READINGS|JOY_BIOS_READINGS) )     {
248                                                 t = t2 - t1;
249                                         } else {                        
250                                                 if ( t1 > t2 )
251                                                         t = t1 - t2;
252                                                 else                            {
253                                                         t = t1 + joystick.max_timer - t2;
254                                                         //mprintf( 0, "%d, %d, %d, %d\n", t1, t2, joystick.max_timer, t );
255                                                 }
256                                         }
257         
258                                         if ( e & 1 ) { axis[0] = t; read_masks |= 1; }
259                                         if ( e & 2 ) { axis[1] = t; read_masks |= 2; }
260                                         if ( e & 4 ) { axis[2] = t; read_masks |= 4; }
261                                         if ( e & 8 ) { axis[3] = t; read_masks |= 8; }
262                                 }
263                         }
264                 }
265         } else {
266                 // Time out at  (1/100th of a second)
267                 if ( joystick.slow_read & JOY_POLLED_READINGS )
268                         num_channels = joy_read_stick_polled2( mask, buffer, 65536 );
269                 else if ( joystick.slow_read & JOY_BIOS_READINGS )
270                         num_channels = joy_read_stick_bios2( mask, buffer, 65536 );
271                 else if ( joystick.slow_read & JOY_FRIENDLY_READINGS )
272                         num_channels = joy_read_stick_friendly2( mask, buffer, (1193180/100) );
273                 else 
274                         num_channels = joy_read_stick_asm2( mask, buffer, (1193180/100) );
275                 //mprintf(( 0, "(%d)\n", num_channels ));
276         
277                 for (i=0; i<num_channels; i++ ) {
278                         t1 = buffer[0];
279                         t2 = buffer[i*2+2];
280                         
281                         if ( joystick.slow_read & (JOY_POLLED_READINGS|JOY_BIOS_READINGS) )     {
282                                 t = t2 - t1;
283                         } else {                        
284                                 if ( t1 > t2 )
285                                         t = t1 - t2;
286                                 else                            {
287                                         t = t1 + joystick.max_timer - t2;
288                                         //mprintf(( 0, "%d, %d, %d, %d\n", t1, t2, joystick.max_timer, t ));
289                                 }
290                         }               
291                         e = buffer[i*2+1];
292         
293                         if ( e & 1 ) { axis[0] = t; read_masks |= 1; }
294                         if ( e & 2 ) { axis[1] = t; read_masks |= 2; }
295                         if ( e & 4 ) { axis[2] = t; read_masks |= 4; }
296                         if ( e & 8 ) { axis[3] = t; read_masks |= 8; }
297                 }
298                 
299         }
300
301         return read_masks;
302 }
303
304 #ifdef __GNUC__
305 #define near
306 #endif
307
308 int joy_init()  
309 {
310         int i;
311         int temp_axis[4];
312
313 //        if(FindArg("-joy209"))
314 //         use_alt_joyport=1;
315         if(FindArg("-joy209"))
316          JOY_PORT = 521;  //209h;
317          
318         joy_flush();
319
320         _disable();
321         for (i = 0; i < JOY_MAX_BUTTONS; i++)
322                 joystick.buttons[i].last_state = 0;
323         _enable();
324
325         if ( !joy_installed )   {
326                 joy_present = 0;
327                 joy_installed = 1;
328                 //joystick.max_timer = 65536;
329                 joystick.slow_read = 0;
330                 joystick.read_count = 0;
331                 joystick.last_value = 0;
332
333                 //--------------- lock everything for the virtal memory ----------------------------------
334                 if (!dpmi_lock_region ((void near *)joy_read_buttons_bios2, (char *)joy_read_buttons_bios_end2 - (char near *)joy_read_buttons_bios2))   {
335                         printf( "Error locking joystick handler (read bios)!\n" );
336                         exit(1);
337                 }
338
339
340
341                 if (!dpmi_lock_region ((void near *)joy_handler, (char *)joy_handler_end - (char near *)joy_handler))   {
342                         printf( "Error locking joystick handler!\n" );
343                         exit(1);
344                 }
345
346                 if (!dpmi_lock_region (&joystick, sizeof(Joy_info)))    {
347                         printf( "Error locking joystick handler's data!\n" );
348                         exit(1);
349                 }
350
351                 timer_set_joyhandler(joy_handler);
352         }
353
354         // Do initial cheapy calibration...
355         joystick.present_mask = JOY_ALL_AXIS;           // Assume they're all present
356         do      {
357                 joystick.present_mask = joystick_read_raw_axis( JOY_ALL_AXIS, temp_axis );
358         } while( joy_bogus_reading );
359
360         if ( joystick.present_mask & 3 )
361                 joy_present = 1;
362         else
363                 joy_present = 0;
364
365         return joy_present;
366 }
367
368 void joy_close()        
369 {
370         if (!joy_installed) return;
371         joy_installed = 0;
372 }
373
374 void joy_set_ul()       
375 {
376         joystick.present_mask = JOY_ALL_AXIS;           // Assume they're all present
377         do      {
378                 joystick.present_mask = joystick_read_raw_axis( JOY_ALL_AXIS, joystick.axis_min );
379         } while( joy_bogus_reading );
380         if ( joystick.present_mask & 3 )
381                 joy_present = 1;
382         else
383                 joy_present = 0;
384 }
385
386 void joy_set_lr()       
387 {
388         joystick.present_mask = JOY_ALL_AXIS;           // Assume they're all present
389         do {
390                 joystick.present_mask = joystick_read_raw_axis( JOY_ALL_AXIS, joystick.axis_max );
391         } while( joy_bogus_reading );
392
393         if ( joystick.present_mask & 3 )
394                 joy_present = 1;
395         else
396                 joy_present = 0;
397 }
398
399 void joy_set_cen() 
400 {
401         joystick.present_mask = JOY_ALL_AXIS;           // Assume they're all present
402         do {
403                 joystick.present_mask = joystick_read_raw_axis( JOY_ALL_AXIS, joystick.axis_center );
404         } while( joy_bogus_reading );
405
406         if ( joystick.present_mask & 3 )
407                 joy_present = 1;
408         else
409                 joy_present = 0;
410 }
411
412 void joy_set_cen_fake(int channel)      
413 {
414
415         int i,n=0;
416         int minx, maxx, cenx;
417         
418         minx=maxx=cenx=0;
419
420         for (i=0; i<4; i++ )    {
421                 if ( (joystick.present_mask & (1<<i)) && (i!=channel) ) {
422                         n++;
423                         minx += joystick.axis_min[i];
424                         maxx += joystick.axis_max[i];
425                         cenx += joystick.axis_center[i];
426                 }
427         }
428         minx /= n;
429         maxx /= n;
430         cenx /= n;
431
432         joystick.axis_min[channel] = minx;
433         joystick.axis_max[channel] = maxx;
434         joystick.axis_center[channel] = cenx;
435 }
436
437 int joy_get_scaled_reading( int raw, int axn )  
438 {
439  int x, d, dz;
440
441  // Make sure it's calibrated properly.
442 //added/changed on 8/14/98 to allow smaller calibrating sticks to work (by Eivind Brendryen)--was <5
443    if ( joystick.axis_center[axn] - joystick.axis_min[axn] < 2 )
444     return 0;
445    if ( joystick.axis_max[axn] - joystick.axis_center[axn] < 2 )
446     return 0;
447 //end change - Victor Rachels  (by Eivind Brendryen)
448
449   raw -= joystick.axis_center[axn];
450
451    if ( raw < 0 )
452     d = joystick.axis_center[axn]-joystick.axis_min[axn];
453    else
454     d = joystick.axis_max[axn]-joystick.axis_center[axn];
455
456
457    if ( d )
458     x = (raw << 7) / d;
459    else
460     x = 0;
461
462
463    if ( x < -128 )
464     x = -128;
465    if ( x > 127 )
466     x = 127;
467
468 //added on 4/13/99 by Victor Rachels to add deadzone control
469   dz =  (joy_deadzone) * 6;
470    if ((x > (-1*dz)) && (x < dz))
471     x = 0;
472 //end this section addition -VR
473
474   return x;
475 }
476
477 int last_reading[4] = { 0, 0, 0, 0 };
478
479 void joy_get_pos( int *x, int *y )      
480 {
481         ubyte flags;
482         int axis[4];
483
484         if ((!joy_installed)||(!joy_present)) { *x=*y=0; return; }
485
486         flags=joystick_read_raw_axis( JOY_1_X_AXIS+JOY_1_Y_AXIS, axis );
487
488         if ( joy_bogus_reading )        {
489                 axis[0] = last_reading[0];
490                 axis[1] = last_reading[1];
491                 flags = JOY_1_X_AXIS+JOY_1_Y_AXIS;
492         } else {
493                 last_reading[0] = axis[0];
494                 last_reading[1] = axis[1];
495         }
496
497         if ( flags & JOY_1_X_AXIS )
498                 *x = joy_get_scaled_reading( axis[0], 0 );
499         else
500                 *x = 0;
501
502         if ( flags & JOY_1_Y_AXIS )
503                 *y = joy_get_scaled_reading( axis[1], 1 );
504         else
505                 *y = 0;
506 }
507
508 ubyte joy_read_stick( ubyte masks, int *axis )  
509 {
510         ubyte flags;
511         int raw_axis[4];
512
513         if ((!joy_installed)||(!joy_present)) { 
514                 axis[0] = 0; axis[1] = 0;
515                 axis[2] = 0; axis[3] = 0;
516                 return 0;  
517         }
518
519         flags=joystick_read_raw_axis( masks, raw_axis );
520
521         if ( joy_bogus_reading )        {
522                 axis[0] = last_reading[0];
523                 axis[1] = last_reading[1];
524                 axis[2] = last_reading[2];
525                 axis[3] = last_reading[3];
526                 flags = masks;
527         } else {
528                 last_reading[0] = axis[0];
529                 last_reading[1] = axis[1];
530                 last_reading[2] = axis[2];
531                 last_reading[3] = axis[3];
532         }
533
534         if ( flags & JOY_1_X_AXIS )
535                 axis[0] = joy_get_scaled_reading( raw_axis[0], 0 );
536         else
537                 axis[0] = 0;
538
539         if ( flags & JOY_1_Y_AXIS )
540                 axis[1] = joy_get_scaled_reading( raw_axis[1], 1 );
541         else
542                 axis[1] = 0;
543
544         if ( flags & JOY_2_X_AXIS )
545                 axis[2] = joy_get_scaled_reading( raw_axis[2], 2 );
546         else
547                 axis[2] = 0;
548
549         if ( flags & JOY_2_Y_AXIS )
550                 axis[3] = joy_get_scaled_reading( raw_axis[3], 3 );
551         else
552                 axis[3] = 0;
553
554         return flags;
555 }
556
557
558 int joy_get_btns()      
559 {
560         if ((!joy_installed)||(!joy_present)) return 0;
561
562         return joy_read_raw_buttons();
563 }
564
565 void joy_get_btn_down_cnt( int *btn0, int *btn1 ) 
566 {
567         if ((!joy_installed)||(!joy_present)) { *btn0=*btn1=0; return; }
568
569         _disable();
570         *btn0 = joystick.buttons[0].downcount;
571         joystick.buttons[0].downcount = 0;
572         *btn1 = joystick.buttons[1].downcount;
573         joystick.buttons[1].downcount = 0;
574         _enable();
575 }
576
577 int joy_get_button_state( int btn )     
578 {
579         int count;
580
581         if ((!joy_installed)||(!joy_present)) return 0;
582
583         if (btn >= JOY_MAX_BUTTONS)
584                 return 0;
585
586         _disable();
587         count = joystick.buttons[btn].state;
588         _enable();
589         
590         return  count;
591 }
592
593 int joy_get_button_up_cnt( int btn ) 
594 {
595         int count;
596
597         if ((!joy_installed)||(!joy_present)) return 0;
598
599         if (btn >= JOY_MAX_BUTTONS)
600                 return 0;
601
602         _disable();
603         count = joystick.buttons[btn].upcount;
604         joystick.buttons[btn].upcount = 0;
605         _enable();
606
607         return count;
608 }
609
610 int joy_get_button_down_cnt( int btn ) 
611 {
612         int count;
613
614         if ((!joy_installed)||(!joy_present)) return 0;
615         if (btn >= JOY_MAX_BUTTONS)
616                 return 0;
617
618         _disable();
619         count = joystick.buttons[btn].downcount;
620         joystick.buttons[btn].downcount = 0;
621         _enable();
622
623         return count;
624 }
625
626         
627 fix joy_get_button_down_time( int btn ) 
628 {
629         fix count;
630
631         if ((!joy_installed)||(!joy_present)) return 0;
632         if (btn >= JOY_MAX_BUTTONS)
633                 return 0;
634
635         _disable();
636         count = joystick.buttons[btn].timedown;
637         joystick.buttons[btn].timedown = 0;
638         _enable();
639
640         return fixmuldiv(count, 65536, 1193180 );
641 }
642
643 void joy_get_btn_up_cnt( int *btn0, int *btn1 ) 
644 {
645         if ((!joy_installed)||(!joy_present)) { *btn0=*btn1=0; return; }
646
647         _disable();
648         *btn0 = joystick.buttons[0].upcount;
649         joystick.buttons[0].upcount = 0;
650         *btn1 = joystick.buttons[1].upcount;
651         joystick.buttons[1].upcount = 0;
652         _enable();
653 }
654
655 void joy_set_btn_values( int btn, int state, fix timedown, int downcount, int upcount )
656 {
657         _disable();
658         joystick.buttons[btn].ignore = 1;
659         joystick.buttons[btn].state = state;
660         joystick.buttons[btn].timedown = fixmuldiv( timedown, 1193180, 65536 );
661         joystick.buttons[btn].downcount = downcount;
662         joystick.buttons[btn].upcount = upcount;
663         _enable();
664 }
665
666 void joy_poll()
667 {
668         if ( joystick.slow_read & JOY_BIOS_READINGS )   
669                 joystick.last_value = joy_read_buttons_bios2();
670 }