asm compatibility re-fixed, nsf for asm fixed, msg displ
[fceu.git] / drivers / gp2x / input.c
1 /* FCE Ultra - NES/Famicom Emulator
2  *
3  * Copyright notice for this file:
4  *  Copyright (C) 2002 Ben Parnell
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #define JOY_A   1
22 #define JOY_B   2
23 #define JOY_SELECT      4
24 #define JOY_START       8
25 #define JOY_UP  0x10
26 #define JOY_DOWN        0x20
27 #define JOY_LEFT        0x40
28 #define JOY_RIGHT       0x80
29
30 #include "minimal.h"
31
32
33 extern int swapbuttons;
34 extern int scaled_display;
35 extern int FSkip_setting;
36
37 extern void SetVideoScaling(int pixels,int width,int height);
38
39
40
41 /* UsrInputType[] is user-specified.  InputType[] is current
42         (game loading can override user settings)
43 */
44 static int UsrInputType[2]={SI_GAMEPAD,SI_GAMEPAD};
45 static int InputType[2];
46
47 static int UsrInputTypeFC={SI_NONE};
48 static int InputTypeFC;
49
50 static uint32 JSreturn;
51 int NoWaiting=0;
52
53 static int powerpadsc[2][12];
54 static int powerpadside=0;
55
56
57 static uint32 MouseData[3];
58 static uint8 fkbkeys[0x48];
59 unsigned long lastpad=0;
60
61 extern void ResetNES(void);
62 extern void CleanSurface(void);
63
64 char soundvolmeter[21];
65 int soundvolIndex=0;
66 int L_count=0;
67 int R_count=0;
68 extern int CurrentState;
69 int TurboFireOff=1;
70 int TurboFireTop=0;  // 0 is none  // 1 is  A & X turbo  // 2 is Y & B turbo
71 int TurboFireBottom=0;
72 int turbo_toggle_A=0;
73 int turbo_toggle_B=0;
74
75
76 static void setsoundvol(int soundvolume)
77 {
78     //FCEUI_SetSoundVolume(soundvol);
79     // draw on screen :D
80     gp2x_sound_volume(soundvolume, soundvolume);
81     int meterval=soundvolume/5;
82     for (soundvolIndex=0; soundvolIndex < 20; soundvolIndex++)
83     {
84        if (soundvolIndex < meterval)
85        {
86           soundvolmeter[soundvolIndex]='*';
87        }
88        else
89        {
90           soundvolmeter[soundvolIndex]='_';
91        }
92     }
93     soundvolmeter[20]=0;
94     FCEU_DispMessage("|%s|", soundvolmeter);
95 }
96
97
98
99 void FCEUD_UpdateInput(void)
100 {
101   long lastpad2=lastpad;
102   unsigned long pad=gp2x_joystick_read();
103   uint32 JS=0;
104
105 #define down(b) (pad & GP2X_##b)
106 #define last_down(b) (lastpad & GP2X_##b)
107 #define L_down (pad & GP2X_L)
108 #define R_down (pad & GP2X_R)
109 #define last_L_down (lastpad & GP2X_L)
110 #define last_R_down (lastpad & GP2X_R)
111 #define shift      ((pad     & GP2X_PUSH) || ((pad     & (GP2X_VOL_UP|GP2X_VOL_DOWN)) == (GP2X_VOL_UP|GP2X_VOL_DOWN)))
112 #define last_shift ((lastpad & GP2X_PUSH) || ((lastpad & (GP2X_VOL_UP|GP2X_VOL_DOWN)) == (GP2X_VOL_UP|GP2X_VOL_DOWN)))
113
114   if (L_down && R_down && !(pad & GP2X_PUSH) && !(last_R_down && last_L_down))
115   {
116      ResetNES();
117      puts("Reset");
118      goto no_pad;
119   }
120
121   if (down(VOL_UP) && !down(VOL_DOWN))
122   {
123     soundvol+=1;
124     if (soundvol >= 100) soundvol=100;
125     //FCEUI_SetSoundVolume(soundvol);
126     setsoundvol(soundvol);
127   }
128   else if (down(VOL_DOWN) && !down(VOL_UP))
129   {
130     soundvol-=1;
131     if (soundvol < 0) soundvol=0;
132     //FCEUI_SetSoundVolume(soundvol);
133     setsoundvol(soundvol);
134   }
135
136   if (shift)
137   {
138     // only if it's something else then last time, and not moving around the joystick
139     if (!(pad & (GP2X_UP|GP2X_DOWN|GP2X_LEFT|GP2X_RIGHT)))
140     {
141       if (down(SELECT))
142       {
143         if (last_down(SELECT) && last_shift)
144         {
145           // still pressed down from stretching from last one
146           goto no_pad;
147         }
148         scaled_display = !scaled_display;
149
150         if (scaled_display)
151         {
152           SetVideoScaling(320, 256, 240);
153         }
154         else
155         {
156           SetVideoScaling(320, 320, 240);
157         }
158
159         goto no_pad;
160       }
161       else if (L_down && R_down)
162       {
163         FCEUI_CloseGame();
164         puts("Quit");
165         goto no_pad;
166       }
167       else if (R_down && !(last_R_down && last_shift))
168       {
169        FCEUI_LoadState();
170        goto no_pad;
171       }
172       else if (L_down && !(last_L_down && last_shift))
173       {
174        FCEUI_SaveState();
175        goto no_pad;
176       }
177       else if (down(A) && !(last_down(A) && last_shift))
178       {
179        FSkip_setting--;
180        if (FSkip_setting < 0) {
181         FSkip_setting = -1;
182         FCEUI_DispMessage("Auto frameskip");
183        }
184        else
185         FCEUI_DispMessage("Frameskip: %i", FSkip_setting);
186        goto no_pad;
187       }
188       else if (down(Y) && !(last_down(Y) && last_shift))
189       {
190        FSkip_setting++;
191        if (FSkip_setting > 8) FSkip_setting = 8;
192        FCEUI_DispMessage("Frameskip: %i", FSkip_setting);
193        goto no_pad;
194       }
195     }
196   }
197
198   // r is toggle savestate
199   if (R_down)
200   {
201         if (last_R_down)
202         {
203           R_count++;
204       if ((R_count & 31)== 31)
205       {
206                 CurrentState=(CurrentState+1) % 10;
207                 FCEUI_DispMessage("Now Using Save State %d", CurrentState);
208           }
209         }
210   }
211   else
212   {
213     R_count=0;
214   }
215
216   // l is toggle turbo
217   if (L_down)
218   {
219         if (last_L_down)
220         {
221           L_count++;
222       if ((L_count & 31)== 31)
223       {
224        // 0 is none  // 1 is  Y & B turbo  // 2 is X & A turbo
225         if ((!TurboFireTop) && (!TurboFireBottom))
226         {
227                 // was off
228                 TurboFireTop=1;
229                 TurboFireBottom=0;
230                 if (swapbuttons)
231                 {
232                   FCEUI_DispMessage("Turbo A and Y");
233                 }
234                 else
235                 {
236                   FCEUI_DispMessage("Turbo Y and B");
237                 }
238         }
239         else if (TurboFireTop)
240         {
241                 TurboFireTop=0;
242                 TurboFireBottom=1;
243                 if (swapbuttons)
244                 {
245                   FCEUI_DispMessage("Turbo X and B");
246                 }
247                 else
248                 {
249                   FCEUI_DispMessage("Turbo A and X");
250                 }
251         }
252         else
253         {
254                 TurboFireTop=0;
255                 TurboFireBottom=0;
256                 FCEUI_DispMessage("Turbo Off");
257         }
258
259           }
260         }
261   }
262   else
263   {
264     L_count=0;
265   }
266
267   //unsigned long padTmp=0;
268   // shift the bits in
269   // up
270   //padTmp=(pad & GP2X_UP) ;  // 1 is 2^0,
271   JS |= ((pad & GP2X_UP) << (4-0));  // 0x10 is 2^4
272
273   //padTmp=(pad & GP2X_DOWN);  // 0x10 is 2^4,
274   JS |= ((pad & GP2X_DOWN) << (5-4));  // 0x20 is 2^5
275
276   //padTmp=(pad & GP2X_LEFT);  // 0x4 is 2^2,
277   JS |= ((pad & GP2X_LEFT) << (6-2));  // 0x40 is 2^6
278
279   //padTmp=(pad & GP2X_RIGHT);  // 0x40 is 2^6,
280   JS |= ((pad & GP2X_RIGHT) << (7-6));  // 0x80 is 2^7
281
282
283 #define  A_down (pad & GP2X_A)
284 #define  B_down (pad & GP2X_B)
285 #define  X_down (pad & GP2X_X)
286 #define  Y_down (pad & GP2X_Y)
287
288   // should be 2 cycles held, 1 cycle release
289   turbo_toggle_A=(turbo_toggle_A+1) % 3;
290   turbo_toggle_B=(turbo_toggle_B+1) % 3;
291
292    // 0 is none  // 1 is  Y & B turbo  // 2 is X & A turbo
293   // B or X are both considered A
294   //padTmp=B_down >> 13;  // 2^13,
295
296    if (!(TurboFireTop && (!turbo_toggle_A)))
297    {
298     JS |= ((B_down >> 13) << 0);  // 0x1 is 2^0
299    }
300    // A or Y are both considered B
301    //padTmp=A_down >> 12;  // 2^13,
302    if (!(TurboFireBottom && (!turbo_toggle_B)))
303    {
304     JS |= ((A_down >> 12) << 1);  // 0x2 is 2^1
305    }
306
307   if (swapbuttons)
308   {
309    //padTmp=X_down >> 14;  // 2^13,
310    if (!(TurboFireBottom && (!turbo_toggle_A)))
311    {
312 //    JS |= ((X_down >> 14) << 0);  // 0x1 is 2^0
313     JS |= ((Y_down >> 15) << 0);  // 0x1 is 2^0
314    }
315
316    //padTmp=Y_down >> 15;  // 2^13,
317    if (!(TurboFireTop && (!turbo_toggle_B)))
318    {
319     JS |= ((X_down >> 14) << 1);  // 0x2 is 2^1
320    }
321   }
322   else
323   {
324    //padTmp=X_down >> 14;  // 2^13,
325    if (!(TurboFireBottom && (!turbo_toggle_A)))
326    {
327     JS |= ((X_down >> 14) << 0);  // 0x1 is 2^0
328    }
329
330    //padTmp=Y_down >> 15;  // 2^13,
331    if (!(TurboFireTop && (!turbo_toggle_B)))
332    {
333     JS |= ((Y_down >> 15) << 1);  // 0x2 is 2^1
334    }
335   }
336
337   // select
338   //padTmp=(pad & GP2X_SELECT) >> 9;  // 0x40 is 2^9,
339   JS |= (((pad & GP2X_SELECT) >> 9) << 2);  // 0x4 is 2^2
340
341   // start
342   //padTmp=(pad & GP2X_START) >> 8;  //   2^8,
343   JS |= (((pad & GP2X_START) >> 8) << 3);  // 0x8 is 2^3
344
345   JSreturn = JS;
346   lastpad=pad;
347
348   //JSreturn=(JS&0xFF000000)|(JS&0xFF)|((JS&0xFF0000)>>8)|((JS&0xFF00)<<8);
349
350
351   //  JSreturn=(JSreturn&0xFF000000)|(JSreturn&0xFF)|((JSreturn&0xFF0000)>>8)|((JSreturn&0xFF00)<<8);
352   // TODO: make these bindable, use new interface
353   if(gametype==GIT_FDS)
354   {
355     NoWaiting&=~1;
356         if ((pad & GP2X_PUSH) && (!(pad & GP2X_SELECT)) && (!(pad & GP2X_L)) && (!(pad & GP2X_R)) && (!(lastpad2 & GP2X_PUSH)))
357         {
358       DriverInterface(DES_FDSSELECT,0);
359         }
360         else if ((pad & GP2X_L) && (!(pad & GP2X_SELECT)) && (!(pad & GP2X_PUSH)) && (!(pad & GP2X_R))&& (!(lastpad2 & GP2X_L)))
361         {
362       DriverInterface(DES_FDSINSERT,0);
363         }
364         else if ((pad & GP2X_R) && (!(pad & GP2X_SELECT)) && (!(pad & GP2X_L)) && (!(pad & GP2X_PUSH)) && (!(lastpad2 & GP2X_R)))
365         {
366       DriverInterface(DES_FDSEJECT,0);
367         }
368   }
369   return;
370
371 no_pad:
372   JSreturn=0;
373   lastpad=pad;
374 }
375
376
377 static void InitOtherInput(void)
378 {
379
380    void *InputDPtr;
381
382    int t;
383    int x;
384    int attrib;
385
386    for(t=0,x=0;x<2;x++)
387    {
388     attrib=0;
389     InputDPtr=0;
390     switch(InputType[x])
391     {
392       //case SI_POWERPAD:InputDPtr=&powerpadbuf[x];break;
393      case SI_GAMEPAD:InputDPtr=((uint8 *)&JSreturn)+(x<<1);break;
394      case SI_ARKANOID:InputDPtr=MouseData;t|=1;break;
395      case SI_ZAPPER:InputDPtr=MouseData;
396                                 t|=1;
397                                 attrib=1;
398                                 break;
399     }
400     FCEUI_SetInput(x,InputType[x],InputDPtr,attrib);
401    }
402
403    attrib=0;
404    InputDPtr=0;
405    switch(InputTypeFC)
406    {
407     case SIFC_SHADOW:InputDPtr=MouseData;t|=1;attrib=1;break;
408     case SIFC_ARKANOID:InputDPtr=MouseData;t|=1;break;
409     case SIFC_FKB:InputDPtr=fkbkeys;break;
410    }
411
412    FCEUI_SetInputFC(InputTypeFC,InputDPtr,attrib);
413    FCEUI_DisableFourScore(eoptions&EO_NOFOURSCORE);
414
415    if(t && !(inited&16))
416    {
417     InitMouse();
418     inited|=16;
419    }
420 }