always fill on blanking
[fceu.git] / input.c
CommitLineData
c62d2810 1/* FCE Ultra - NES/Famicom Emulator
2 *
3 * Copyright notice for this file:
5a2aa426 4 * Copyright (C) 1998 BERO
c62d2810 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 */
5232c20c 21#include <string.h>
c62d2810 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"
890e37ba 31#include "state.h"
5a2aa426 32#include "movie.h"
c62d2810 33
d97315ac 34#include "fds.h"
35#include "vsuni.h"
4fdfab07 36#include "dprintf.h"
37
c62d2810 38extern INPUTC *FCEU_InitZapper(int w);
e328100e 39extern INPUTC *FCEU_InitPowerpadA(int w);
c62d2810 40extern INPUTC *FCEU_InitArkanoid(int w);
41
42extern INPUTCFC *FCEU_InitArkanoidFC(void);
43extern INPUTCFC *FCEU_InitSpaceShadow(void);
44extern INPUTCFC *FCEU_InitFKB(void);
45static uint8 joy_readbit[2];
890e37ba 46static uint8 joy[4]={0,0,0,0};
47static uint8 LastStrobe;
c62d2810 48
c62d2810 49static int FSDisable=0; /* Set to 1 if NES-style four-player adapter is disabled. */
50static int JPAttrib[2]={0,0};
51static int JPType[2]={0,0};
52static void *InputDataPtr[2];
53
54static int JPAttribFC=0;
55static int JPTypeFC=0;
56static void *InputDataPtrFC;
57
e328100e 58void (*InputScanlineHook)(uint8 *bg, uint8 *spr, uint32 linets, int final);
c62d2810 59
60static INPUTC DummyJPort={0,0,0,0,0};
61static INPUTC *JPorts[2]={&DummyJPort,&DummyJPort};
62static INPUTCFC *FCExp=0;
63
d97315ac 64/* This function is a quick hack to get the NSF player to use emulated gamepad
65 input.
66*/
67uint8 FCEU_GetJoyJoy(void)
68{
69 return(joy[0]|joy[1]|joy[2]|joy[3]);
70}
71
c62d2810 72static uint8 FP_FASTAPASS(1) ReadGPVS(int w)
73{
74 uint8 ret=0;
75
76 if(joy_readbit[w]>=8)
77 ret=1;
78 else
79 {
80 ret = ((joy[w]>>(joy_readbit[w]))&1);
81 joy_readbit[w]++;
82 }
83 return ret;
84}
85
86static uint8 FP_FASTAPASS(1) ReadGP(int w)
87{
88 uint8 ret;
5a2aa426 89 //if(JoyMulti)
c62d2810 90 //{
91 //ret = ((joy[w]>>(joy_readbit[w]))&1)|
92 //(((joy[w]>>(joy_readbit[w]+8))&1)<<1);
93 //if(joy_readbit[w]>8) ret=0;
94 //}
95 ret = ((joy[w]>>(joy_readbit[w]))&1);
96 if(FSDisable)
97 {
98 if(joy_readbit[w]>=8) ret|=1;
99 }
100 else
101 {
102 if(joy_readbit[w]==19-w) ret|=1;
103 }
104 joy_readbit[w]++;
105 return ret;
106}
107
108static DECLFR(JPRead)
109{
110 uint8 ret=0;
111
112 if(JPorts[A&1]->Read)
113 ret|=JPorts[A&1]->Read(A&1);
5a2aa426 114
c62d2810 115 if(FCExp)
116 if(FCExp->Read)
117 ret=FCExp->Read(A&1,ret);
118
119 ret|=X.DB&0xC0;
6f6bc6fa 120 dprintf("JPRead %i %02x", A&1, ret);
c62d2810 121 return(ret);
122}
123
124static DECLFW(B4016)
125{
126 if(FCExp)
127 if(FCExp->Write)
128 FCExp->Write(V&7);
129
130 if(JPorts[0]->Write)
131 JPorts[0]->Write(V&1);
132 if(JPorts[1]->Write)
133 JPorts[1]->Write(V&1);
134
890e37ba 135 if((LastStrobe&1) && (!(V&1)))
c62d2810 136 {
137 /* This strobe code is just for convenience. If it were
138 with the code in input / *.c, it would more accurately represent
139 what's really going on. But who wants accuracy? ;)
140 Seriously, though, this shouldn't be a problem.
141 */
142 if(JPorts[0]->Strobe)
143 JPorts[0]->Strobe(0);
144 if(JPorts[1]->Strobe)
145 JPorts[1]->Strobe(1);
146 if(FCExp)
147 if(FCExp->Strobe)
148 FCExp->Strobe();
149 }
890e37ba 150 LastStrobe=V&1;
c62d2810 151}
152
153static void FP_FASTAPASS(1) StrobeGP(int w)
154{
155 joy_readbit[w]=0;
156}
157
158static INPUTC GPC={ReadGP,0,StrobeGP,0,0,0};
159static INPUTC GPCVS={ReadGPVS,0,StrobeGP,0,0,0};
160
161void DrawInput(uint8 *buf)
162{
163 int x;
164
165 for(x=0;x<2;x++)
166 if(JPorts[x]->Draw)
167 JPorts[x]->Draw(x,buf,JPAttrib[x]);
168 if(FCExp)
169 if(FCExp->Draw)
170 FCExp->Draw(buf,JPAttribFC);
171}
172
173void UpdateInput(void)
174{
175 int x;
176
177 for(x=0;x<2;x++)
178 {
179 switch(JPType[x])
180 {
181 case SI_GAMEPAD:
182 if(!x) joy[0]=*(uint16 *)InputDataPtr[0];
183 else joy[1]=*(uint16 *)InputDataPtr[1];
184 break;
185 default:
186 if(JPorts[x]->Update)
187 JPorts[x]->Update(x,InputDataPtr[x],JPAttrib[x]);
188 break;
189 }
190 }
191 if(FCExp)
192 if(FCExp->Update)
193 FCExp->Update(InputDataPtrFC,JPAttribFC);
194
195 if(FCEUGameInfo.type==GIT_VSUNI)
196 {
197 uint16 t=joy[0];
198 joy[0]=(joy[0]&0xC)|(joy[1]&0xF3);
199 joy[1]=(joy[1]&0xC)|(t&0xF3);
200 if(coinon) coinon--;
201 }
202 #ifdef NETWORK
203 if(netplay) NetplayUpdate(&joy[0],&joy[1]);
204 #endif
5a2aa426 205 if (current < 0) FCEUMOV_AddJoy(joy);
ea80a45b 206 else framecount++; // for debug
d97315ac 207 //FlushCommandQueue();
c62d2810 208}
209
210static DECLFR(VSUNIRead0)
211{
212 uint8 ret=0;
213
214 if(JPorts[0]->Read)
215 ret|=(JPorts[0]->Read(0))&1;
216
217 ret|=(vsdip&3)<<3;
218 if(coinon)
219 ret|=0x4;
220 return ret;
221}
222
223static DECLFR(VSUNIRead1)
224{
225 uint8 ret=0;
226
227 if(JPorts[1]->Read)
228 ret|=(JPorts[1]->Read(1))&1;
229 ret|=vsdip&0xFC;
230 return ret;
231}
232
e328100e 233static void SLHLHook(uint8 *bg, uint8 *spr, uint32 linets, int final)
c62d2810 234{
235 int x;
236
237 for(x=0;x<2;x++)
238 if(JPorts[x]->SLHook)
e328100e 239 JPorts[x]->SLHook(x,bg,spr,linets,final);
5a2aa426 240 if(FCExp)
c62d2810 241 if(FCExp->SLHook)
e328100e 242 FCExp->SLHook(bg,spr,linets,final);
c62d2810 243}
244
245static void CheckSLHook(void)
246{
247 InputScanlineHook=0;
248 if(JPorts[0]->SLHook || JPorts[1]->SLHook)
249 InputScanlineHook=SLHLHook;
250 if(FCExp)
251 if(FCExp->SLHook)
252 InputScanlineHook=SLHLHook;
253}
254
255static void FASTAPASS(1) SetInputStuff(int x)
256{
257 switch(JPType[x])
258 {
259 case SI_GAMEPAD:
260 if(FCEUGameInfo.type==GIT_VSUNI)
261 JPorts[x]=&GPCVS;
262 else
263 JPorts[x]=&GPC;
264 break;
265 case SI_ARKANOID:JPorts[x]=FCEU_InitArkanoid(x);break;
266 case SI_ZAPPER:JPorts[x]=FCEU_InitZapper(x);break;
e328100e 267 case SI_POWERPADA:JPorts[x]=FCEU_InitPowerpadA(x);break;
c62d2810 268 case SI_NONE:JPorts[x]=&DummyJPort;break;
269 }
270
271 CheckSLHook();
272}
273
274static uint8 F4ReadBit[2];
275static void StrobeFami4(void)
276{
277 F4ReadBit[0]=F4ReadBit[1]=0;
278}
279
280static uint8 FP_FASTAPASS(2) ReadFami4(int w, uint8 ret)
281{
282 ret&=1;
283
284 ret |= ((joy[w]>>(F4ReadBit[w]+8))&1)<<1;
285 if(F4ReadBit[w]>=8) ret|=2;
286 else F4ReadBit[w]++;
287
288 return(ret);
289}
290
291static INPUTCFC FAMI4C={ReadFami4,0,StrobeFami4,0,0,0};
292static void SetInputStuffFC(void)
293{
294 switch(JPTypeFC)
295 {
296 case SIFC_NONE:FCExp=0;break;
297 case SIFC_ARKANOID:FCExp=FCEU_InitArkanoidFC();break;
298 case SIFC_SHADOW:FCExp=FCEU_InitSpaceShadow();break;
299 case SIFC_4PLAYER:FCExp=&FAMI4C;memset(&F4ReadBit,0,sizeof(F4ReadBit));break;
300 case SIFC_FKB:FCExp=FCEU_InitFKB();break;
301 }
302 CheckSLHook();
303}
304
305// VS Unisystem code called after SetInputMap() hooks B4016. Need to
306// rewrite code to make this more sane?
307
308void InitializeInput(void)
5a2aa426 309{
c62d2810 310 memset(joy_readbit,0,sizeof(joy_readbit));
311 memset(joy,0,sizeof(joy));
890e37ba 312 LastStrobe=0;
c62d2810 313
314 if(FCEUGameInfo.type==GIT_VSUNI)
315 {
316 SetReadHandler(0x4016,0x4016,VSUNIRead0);
317 SetReadHandler(0x4017,0x4017,VSUNIRead1);
318 }
319 else
320 SetReadHandler(0x4016,0x4017,JPRead);
321 SetWriteHandler(0x4016,0x4016,B4016);
322
323 SetInputStuff(0);
324 SetInputStuff(1);
325 SetInputStuffFC();
326}
327
328void FCEUI_SetInput(int port, int type, void *ptr, int attrib)
329{
330 JPAttrib[port]=attrib;
331 JPType[port]=type;
332 InputDataPtr[port]=ptr;
333 SetInputStuff(port);
334}
335
336void FCEUI_DisableFourScore(int s)
337{
338 FSDisable=s;
339}
340
341void FCEUI_SetInputFC(int type, void *ptr, int attrib)
342{
343 JPAttribFC=attrib;
344 JPTypeFC=type;
345 InputDataPtrFC=ptr;
346 SetInputStuffFC();
347}
890e37ba 348
890e37ba 349void FCEU_DoSimpleCommand(int cmd)
350{
c4980f9e 351 printf("FCEU_DoSimpleCommand: %i\n", cmd);
890e37ba 352 switch(cmd)
353 {
d97315ac 354 case FCEUNPCMD_FDSINSERT: FCEU_FDSInsert();break;
355 case FCEUNPCMD_FDSSELECT: FCEU_FDSSelect();break;
890e37ba 356// case FCEUNPCMD_FDSEJECT: FCEU_FDSEject();break;
d97315ac 357 case FCEUNPCMD_VSUNICOIN: FCEU_VSUniCoin(); break;
358 case FCEUNPCMD_VSUNIDIP0 ... (FCEUNPCMD_VSUNIDIP0 + 7): FCEU_VSUniToggleDIP(cmd - FCEUNPCMD_VSUNIDIP0);break;
890e37ba 359 case FCEUNPCMD_POWER: PowerNES();break;
360 case FCEUNPCMD_RESET: ResetNES();break;
361 default: printf("FCEU_DoSimpleCommand: can't handle cmd %i\n", cmd); break;
362 }
363}
364
d97315ac 365void FCEU_QSimpleCommand(int cmd)
366{
367// if(FCEUnetplay)
368// FCEUNET_SendCommand(cmd, 0);
369// else
370 {
371 // totally wrong:
372// if(!FCEUMOV_IsPlaying())
373// FCEU_DoSimpleCommand(cmd);
374// else
375// FCEUMOV_AddCommand(cmd);
376
377 FCEU_DoSimpleCommand(cmd);
378// if(FCEUMOV_IsRecording())
379// FCEUMOV_AddCommand(cmd);
380 }
381}
382
383void FCEUI_FDSSelect(void)
384{
385 FCEU_QSimpleCommand(FCEUNPCMD_FDSSELECT);
386}
387
388int FCEUI_FDSInsert(void)
389{
390 FCEU_QSimpleCommand(FCEUNPCMD_FDSINSERT);
391 return(1);
392}
393
394/*
395int FCEUI_FDSEject(void)
396{
397 FCEU_QSimpleCommand(FCEUNPCMD_FDSEJECT);
398 return(1);
399}
400*/
401void FCEUI_VSUniToggleDIP(int w)
402{
403 FCEU_QSimpleCommand(FCEUNPCMD_VSUNIDIP0 + w);
404}
405
406void FCEUI_VSUniCoin(void)
407{
408 FCEU_QSimpleCommand(FCEUNPCMD_VSUNICOIN);
409}
410
411void FCEUI_ResetNES(void)
412{
413 FCEU_QSimpleCommand(FCEUNPCMD_RESET);
414}
415
416void FCEUI_PowerNES(void)
417{
418 FCEU_QSimpleCommand(FCEUNPCMD_POWER);
419}
420
421
890e37ba 422
423SFORMAT FCEUCTRL_STATEINFO[]={
424 { joy_readbit, 2, "JYRB"},
425 { joy, 4, "JOYS"},
426 { &LastStrobe, 1, "LSTS"},
427 { 0 }
428};
429
430