bg renderer split
[fceu.git] / input.c
1 /* FCE Ultra - NES/Famicom Emulator
2  *
3  * Copyright notice for this file:
4  *  Copyright (C) 1998 BERO 
5  *  Copyright (C) 2002 Ben Parnell
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21 #include <string.h>
22 #include "types.h"
23 #include "x6502.h"
24
25 #include "fce.h"
26 #include "sound.h"
27 #include "netplay.h"
28 #include "svga.h"
29
30 #include "input.h"
31
32 extern INPUTC *FCEU_InitZapper(int w);
33 extern INPUTC *FCEU_InitPowerpad(int w);
34 extern INPUTC *FCEU_InitArkanoid(int w);
35
36 extern INPUTCFC *FCEU_InitArkanoidFC(void);
37 extern INPUTCFC *FCEU_InitSpaceShadow(void);
38 extern INPUTCFC *FCEU_InitFKB(void);
39 static uint8 joy_readbit[2];
40 static uint16 joy[2]={0,0};
41
42 extern int coinon;
43
44 static int FSDisable=0; /* Set to 1 if NES-style four-player adapter is disabled. */
45 static int JPAttrib[2]={0,0};
46 static int JPType[2]={0,0};
47 static void *InputDataPtr[2];
48
49 static int JPAttribFC=0;
50 static int JPTypeFC=0;
51 static void *InputDataPtrFC;
52
53 void (*InputScanlineHook)(uint8 *buf, int line);
54
55 static INPUTC DummyJPort={0,0,0,0,0};
56 static INPUTC *JPorts[2]={&DummyJPort,&DummyJPort};
57 static INPUTCFC *FCExp=0;
58
59 static uint8 FP_FASTAPASS(1) ReadGPVS(int w)
60 {
61                 uint8 ret=0;
62
63                 if(joy_readbit[w]>=8)
64                  ret=1;
65                 else
66                 {
67                  ret = ((joy[w]>>(joy_readbit[w]))&1);
68                  joy_readbit[w]++;
69                 }
70                 return ret;
71 }
72
73 static uint8 FP_FASTAPASS(1) ReadGP(int w)
74 {
75                 uint8 ret;
76                 //if(JoyMulti) 
77                 //{
78                  //ret = ((joy[w]>>(joy_readbit[w]))&1)|
79                  //(((joy[w]>>(joy_readbit[w]+8))&1)<<1);
80                  //if(joy_readbit[w]>8) ret=0;
81                 //}
82                 ret = ((joy[w]>>(joy_readbit[w]))&1);
83                 if(FSDisable)
84                 {
85                  if(joy_readbit[w]>=8) ret|=1;
86                 }
87                 else
88                 {
89                  if(joy_readbit[w]==19-w) ret|=1;
90                 }
91                 joy_readbit[w]++;
92                 return ret;
93 }
94
95 static DECLFR(JPRead)
96 {
97         uint8 ret=0;
98
99         if(JPorts[A&1]->Read)
100          ret|=JPorts[A&1]->Read(A&1);
101         
102         if(FCExp)
103          if(FCExp->Read)
104           ret=FCExp->Read(A&1,ret);
105
106         ret|=X.DB&0xC0;
107         return(ret);
108 }
109
110 static DECLFW(B4016)
111 {
112         if(FCExp)
113          if(FCExp->Write)
114           FCExp->Write(V&7);
115
116         if(JPorts[0]->Write)
117          JPorts[0]->Write(V&1);
118         if(JPorts[1]->Write)
119          JPorts[1]->Write(V&1);
120
121         if((PSG[0x16]&1) && (!(V&1)))
122         {
123          /* This strobe code is just for convenience.  If it were
124             with the code in input / *.c, it would more accurately represent
125             what's really going on.  But who wants accuracy? ;)
126             Seriously, though, this shouldn't be a problem.
127          */
128          if(JPorts[0]->Strobe)
129           JPorts[0]->Strobe(0);
130          if(JPorts[1]->Strobe)
131           JPorts[1]->Strobe(1);
132          if(FCExp)
133           if(FCExp->Strobe)
134            FCExp->Strobe();
135          }
136          PSG[0x16]=V;
137 }
138
139 static void FP_FASTAPASS(1) StrobeGP(int w)
140 {
141         joy_readbit[w]=0;
142 }
143
144 static INPUTC GPC={ReadGP,0,StrobeGP,0,0,0};
145 static INPUTC GPCVS={ReadGPVS,0,StrobeGP,0,0,0};
146
147 void DrawInput(uint8 *buf)
148 {
149  int x;
150
151  for(x=0;x<2;x++)
152   if(JPorts[x]->Draw)
153    JPorts[x]->Draw(x,buf,JPAttrib[x]);
154  if(FCExp)
155   if(FCExp->Draw)
156    FCExp->Draw(buf,JPAttribFC);
157 }
158
159 void UpdateInput(void)
160 {
161         int x;
162
163         for(x=0;x<2;x++)
164         {
165          switch(JPType[x])
166          {
167           case SI_GAMEPAD:
168                 if(!x) joy[0]=*(uint16 *)InputDataPtr[0];
169                 else joy[1]=*(uint16 *)InputDataPtr[1];
170                 break;
171           default:
172                 if(JPorts[x]->Update)
173                  JPorts[x]->Update(x,InputDataPtr[x],JPAttrib[x]);
174                 break;
175          }
176         }
177         if(FCExp)
178          if(FCExp->Update)
179           FCExp->Update(InputDataPtrFC,JPAttribFC);
180
181         if(FCEUGameInfo.type==GIT_VSUNI)
182         {
183          uint16 t=joy[0];
184          joy[0]=(joy[0]&0xC)|(joy[1]&0xF3);
185          joy[1]=(joy[1]&0xC)|(t&0xF3);
186          if(coinon) coinon--;
187         }
188         #ifdef NETWORK
189         if(netplay) NetplayUpdate(&joy[0],&joy[1]);
190         #endif
191         FlushCommandQueue();
192 }
193
194 static DECLFR(VSUNIRead0)
195 {
196         uint8 ret=0;
197
198         if(JPorts[0]->Read)
199          ret|=(JPorts[0]->Read(0))&1;
200
201         ret|=(vsdip&3)<<3;
202         if(coinon)
203          ret|=0x4;
204         return ret;
205 }
206
207 static DECLFR(VSUNIRead1)
208 {
209         uint8 ret=0;
210
211         if(JPorts[1]->Read)
212          ret|=(JPorts[1]->Read(1))&1;
213         ret|=vsdip&0xFC;
214         return ret;
215 }
216
217 static void SLHLHook(uint8 *buf, int line)
218 {
219  int x;
220
221  for(x=0;x<2;x++)
222   if(JPorts[x]->SLHook)
223    JPorts[x]->SLHook(x,buf,line);
224  if(FCExp) 
225   if(FCExp->SLHook)
226    FCExp->SLHook(buf,line);
227 }
228
229 static void CheckSLHook(void)
230 {
231         InputScanlineHook=0;
232         if(JPorts[0]->SLHook || JPorts[1]->SLHook)
233          InputScanlineHook=SLHLHook;
234         if(FCExp)
235          if(FCExp->SLHook)
236           InputScanlineHook=SLHLHook;
237 }
238
239 static void FASTAPASS(1) SetInputStuff(int x)
240 {
241          switch(JPType[x])
242          {
243           case SI_GAMEPAD:
244            if(FCEUGameInfo.type==GIT_VSUNI)
245             JPorts[x]=&GPCVS;
246            else
247             JPorts[x]=&GPC;
248           break;
249           case SI_ARKANOID:JPorts[x]=FCEU_InitArkanoid(x);break;
250           case SI_ZAPPER:JPorts[x]=FCEU_InitZapper(x);break;
251           case SI_POWERPAD:JPorts[x]=FCEU_InitPowerpad(x);break;
252           case SI_NONE:JPorts[x]=&DummyJPort;break;
253          }
254
255         CheckSLHook();
256 }
257
258 static uint8 F4ReadBit[2];
259 static void StrobeFami4(void)
260 {
261  F4ReadBit[0]=F4ReadBit[1]=0;
262 }
263
264 static uint8 FP_FASTAPASS(2) ReadFami4(int w, uint8 ret)
265 {
266  ret&=1;
267
268  ret |= ((joy[w]>>(F4ReadBit[w]+8))&1)<<1;
269  if(F4ReadBit[w]>=8) ret|=2;
270  else F4ReadBit[w]++;
271
272  return(ret);
273 }
274
275 static INPUTCFC FAMI4C={ReadFami4,0,StrobeFami4,0,0,0};
276 static void SetInputStuffFC(void)
277 {
278         switch(JPTypeFC)
279         {
280          case SIFC_NONE:FCExp=0;break;
281          case SIFC_ARKANOID:FCExp=FCEU_InitArkanoidFC();break;
282          case SIFC_SHADOW:FCExp=FCEU_InitSpaceShadow();break;
283          case SIFC_4PLAYER:FCExp=&FAMI4C;memset(&F4ReadBit,0,sizeof(F4ReadBit));break;
284          case SIFC_FKB:FCExp=FCEU_InitFKB();break;
285         }
286         CheckSLHook();
287 }
288
289 // VS Unisystem code called after SetInputMap() hooks B4016.  Need to
290 // rewrite code to make this more sane?
291
292 void InitializeInput(void)
293
294         memset(joy_readbit,0,sizeof(joy_readbit));
295         memset(joy,0,sizeof(joy));
296
297         if(FCEUGameInfo.type==GIT_VSUNI)
298         {
299          SetReadHandler(0x4016,0x4016,VSUNIRead0);
300          SetReadHandler(0x4017,0x4017,VSUNIRead1);
301         }
302         else
303          SetReadHandler(0x4016,0x4017,JPRead);
304         SetWriteHandler(0x4016,0x4016,B4016);
305
306         SetInputStuff(0);
307         SetInputStuff(1);
308         SetInputStuffFC();
309 }
310
311 void FCEUI_SetInput(int port, int type, void *ptr, int attrib)
312 {
313  JPAttrib[port]=attrib;
314  JPType[port]=type;
315  InputDataPtr[port]=ptr;
316  SetInputStuff(port);
317 }
318
319 void FCEUI_DisableFourScore(int s)
320 {
321  FSDisable=s;
322 }
323
324 void FCEUI_SetInputFC(int type, void *ptr, int attrib)
325 {
326  JPAttribFC=attrib;
327  JPTypeFC=type;
328  InputDataPtrFC=ptr;
329  SetInputStuffFC();
330 }