more opt. in sound.c, vol incresed
[fceu.git] / svga.c
CommitLineData
c62d2810 1/* FCE Ultra - NES/Famicom Emulator
2 *
3 * Copyright notice for this file:
22f08d95 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 */
21
22/* SVGA High Level Routines
23 FCE / FCE Ultra
24*/
25#include <stdio.h>
26#include <stdlib.h>
27#include <math.h>
28#include <string.h>
29
30#include <stdarg.h>
31
32
33#ifndef M_PI
34#define M_PI 3.14159265358979323846
35#endif
36
37#include "types.h"
22f08d95 38#include "svga.h"
c62d2810 39#include "fce.h"
40#include "general.h"
41#include "video.h"
42#include "sound.h"
43#include "version.h"
44#include "nsf.h"
45#include "palette.h"
46#include "fds.h"
47#include "netplay.h"
48#include "state.h"
49#include "cart.h"
50#include "input.h"
51
92764e62 52#include "vsuni.h"
53
c62d2810 54FCEUS FSettings;
55
56static int howlong;
57static char errmsg[65];
58
59void FCEU_PrintError(char *format, ...)
60{
61 char temp[2048];
62
63 va_list ap;
64
65 va_start(ap,format);
66 vsprintf(temp,format,ap);
67 FCEUD_PrintError(temp);
68
69 va_end(ap);
70}
71
72void FCEU_DispMessage(char *format, ...)
73{
74 va_list ap;
75
76 va_start(ap,format);
77 vsprintf(errmsg,format,ap);
78 va_end(ap);
79
80 howlong=180;
989672f4 81 if (errmsg[0] != '|')
82 printf("%s\n", errmsg);
c62d2810 83}
84
85void FCEUI_SetRenderedLines(int ntscf, int ntscl, int palf, int pall)
86{
87 FSettings.UsrFirstSLine[0]=ntscf;
88 FSettings.UsrLastSLine[0]=ntscl;
89 FSettings.UsrFirstSLine[1]=palf;
90 FSettings.UsrLastSLine[1]=pall;
91 if(PAL)
92 {
93 FSettings.FirstSLine=FSettings.UsrFirstSLine[1];
94 FSettings.LastSLine=FSettings.UsrLastSLine[1];
95 }
96 else
97 {
98 FSettings.FirstSLine=FSettings.UsrFirstSLine[0];
99 FSettings.LastSLine=FSettings.UsrLastSLine[0];
100 }
101
102}
103
104void FCEUI_SetVidSystem(int a)
105{
106 FSettings.PAL=a?1:0;
107 FCEU_ResetVidSys();
108 FCEU_ResetPalette();
109}
110
111int FCEUI_GetCurrentVidSystem(int *slstart, int *slend)
112{
113 if(slstart)
114 *slstart=FSettings.FirstSLine;
115 if(slend)
116 *slend=FSettings.LastSLine;
117 return(PAL);
118}
119
120#ifdef NETWORK
121void FCEUI_SetNetworkPlay(int type)
122{
123 FSettings.NetworkPlay=type;
124}
125#endif
126
127void FCEUI_SetGameGenie(int a)
128{
129 FSettings.GameGenie=a?1:0;
130}
131
c62d2810 132#ifndef NETWORK
133#define netplay 0
134#endif
135
136static uint8 StateShow=0;
137
138uint8 Exit=0;
139
140uint8 DIPS=0;
d97315ac 141//uint8 vsdip=0;
142//int coinon=0;
c62d2810 143
92764e62 144//uint8 pale=0;
c62d2810 145uint8 CommandQueue=0;
146
147static int controlselect=0;
148static int ntsccol=0;
149static int ntsctint=46+10;
150static int ntschue=72;
151static int controllength=0;
152
92764e62 153#if 0
c62d2810 154pal *palo;
155static pal *palpoint[8]=
156 {
157 palette,
158 palettevscv,
159 palettevssmb,
160 palettevsmar,
161 palettevsgoon,
162 palettevsslalom,
163 palettevseb,
164 rp2c04001
165 };
92764e62 166#endif
c62d2810 167
168void FCEUI_SetSnapName(int a)
169{
170 FSettings.SnapName=a;
171}
172
173void FCEUI_SaveExtraDataUnderBase(int a)
174{
175 FSettings.SUnderBase=a;
176}
177
92764e62 178#if 0
c62d2810 179void FCEUI_SetPaletteArray(uint8 *pal)
180{
181 if(!pal)
182 palpoint[0]=palette;
183 else
184 {
185 int x;
186 palpoint[0]=palettec;
187 for(x=0;x<64;x++)
188 {
189 palpoint[0][x].r=*((uint8 *)pal+x+x+x);
190 palpoint[0][x].g=*((uint8 *)pal+x+x+x+1);
191 palpoint[0][x].b=*((uint8 *)pal+x+x+x+2);
192 }
193 }
194 FCEU_ResetPalette();
195}
92764e62 196#endif
c62d2810 197
198void FCEUI_SelectState(int w)
199{
22f08d95 200 if(netplay!=2 && FCEUGameInfo.type!=GIT_NSF)
c62d2810 201 CommandQueue=42+w;
202}
203
204void FCEUI_SaveState(void)
205{
206 if(netplay!=2 && FCEUGameInfo.type!=GIT_NSF)
207 CommandQueue=40;
208}
209
210void FCEUI_LoadState(void)
211{
22f08d95 212 if(netplay!=2 && FCEUGameInfo.type!=GIT_NSF)
c62d2810 213 CommandQueue=41;
214}
215
216int32 FCEUI_GetDesiredFPS(void)
217{
218 if(PAL)
219 return(838977920); // ~50.007
220 else
221 return(1008307711); // ~60.1
222}
223
224static int dosnapsave=0;
225void FCEUI_SaveSnapshot(void)
226{
227 dosnapsave=1;
228}
229
230/* I like the sounds of breaking necks. */
231static void ReallySnap(void)
232{
233 int x=SaveSnapshot();
234 if(!x)
235 FCEU_DispMessage("Error saving screen snapshot.");
236 else
237 FCEU_DispMessage("Screen snapshot %d saved.",x-1);
238}
239
240void DriverInterface(int w, void *d)
241{
242 switch(w)
243 {
244 case DES_NTSCCOL:ntsccol=*(int *)d;FCEU_ResetPalette();break;
245 case DES_RESET:if(netplay!=2) CommandQueue=30;break;
246 case DES_POWER:if(netplay!=2) CommandQueue=31;break;
247 case DES_GETNTSCTINT:*(int*)d=ntsctint;break;
248 case DES_GETNTSCHUE:*(int*)d=ntschue;break;
249 case DES_SETNTSCTINT:ntsctint=*(int*)d;if(ntsccol)FCEU_ResetPalette();break;
250 case DES_SETNTSCHUE:ntschue=*(int*)d;if(ntsccol)FCEU_ResetPalette();break;
251
252 case DES_FDSINSERT:if(netplay!=2) CommandQueue=2;break;
253 case DES_FDSEJECT:if(netplay!=2) CommandQueue=3;break;
254 case DES_FDSSELECT:if(netplay!=2) CommandQueue=1;break;
d97315ac 255/*
c62d2810 256 case DES_NSFINC:NSFControl(1);break;
257 case DES_NSFDEC:NSFControl(2);break;
22f08d95 258 case DES_NSFRES:NSFControl(0);break;
d97315ac 259*/
c62d2810 260 case DES_VSUNIDIPSET:CommandQueue=10+(int)d;break;
261 case DES_VSUNITOGGLEDIPVIEW:CommandQueue=10;break;
262 case DES_VSUNICOIN:CommandQueue=19;break;
263 case DES_NTSCSELHUE:if(ntsccol && FCEUGameInfo.type!=GIT_VSUNI && !PAL && FCEUGameInfo.type!=GIT_NSF){controlselect=1;controllength=360;}break;
264 case DES_NTSCSELTINT:if(ntsccol && FCEUGameInfo.type!=GIT_VSUNI && !PAL && FCEUGameInfo.type!=GIT_NSF){controlselect=2;controllength=360;}break;
92764e62 265#if 0
c62d2810 266 case DES_NTSCDEC:
267 if(ntsccol && FCEUGameInfo.type!=GIT_VSUNI && !PAL && FCEUGameInfo.type!=GIT_NSF)
268 {
269 char which;
270 if(controlselect)
271 {
272 if(controllength)
273 {
274 which=controlselect==1?ntschue:ntsctint;
275 which--;
276 if(which<0) which=0;
22f08d95 277 if(controlselect==1)
278 ntschue=which;
279 else ntsctint=which;
c62d2810 280 CalculatePalette();
281 }
282 controllength=360;
283 }
284 }
285 break;
22f08d95 286 case DES_NTSCINC:
c62d2810 287 if(ntsccol && FCEUGameInfo.type!=GIT_VSUNI && !PAL && FCEUGameInfo.type!=GIT_NSF)
288 if(controlselect)
289 {
290 if(controllength)
291 {
292 switch(controlselect)
293 {
294 case 1:ntschue++;
295 if(ntschue>128) ntschue=128;
296 CalculatePalette();
297 break;
298 case 2:ntsctint++;
299 if(ntsctint>128) ntsctint=128;
300 CalculatePalette();
301 break;
302 }
303 }
304 controllength=360;
305 }
306 break;
92764e62 307#endif
c62d2810 308 }
309}
310
92764e62 311#if 0
c62d2810 312static uint8 lastd=0;
313void SetNESDeemph(uint8 d, int force)
314{
315 static uint16 rtmul[7]={32768*1.239,32768*.794,32768*1.019,32768*.905,32768*1.023,32768*.741,32768*.75};
316 static uint16 gtmul[7]={32768*.915,32768*1.086,32768*.98,32768*1.026,32768*.908,32768*.987,32768*.75};
317 static uint16 btmul[7]={32768*.743,32768*.882,32768*.653,32768*1.277,32768*.979,32768*.101,32768*.75};
318 uint32 r,g,b;
319 int x;
320
22f08d95 321 /* If it's not forced(only forced when the palette changes),
322 don't waste cpu time if the same deemphasis bits are set as the last call.
c62d2810 323 */
22f08d95 324 if(!force)
c62d2810 325 {
22f08d95 326 if(d==lastd)
c62d2810 327 return;
328 }
329 else /* Only set this when palette has changed. */
330 {
331 r=rtmul[6];
332 g=rtmul[6];
333 b=rtmul[6];
334
335 for(x=0;x<0x40;x++)
336 {
337 uint32 m,n,o;
338 m=palo[x].r;
339 n=palo[x].g;
340 o=palo[x].b;
341 m=(m*r)>>15;
342 n=(n*g)>>15;
343 o=(o*b)>>15;
344 if(m>0xff) m=0xff;
345 if(n>0xff) n=0xff;
346 if(o>0xff) o=0xff;
347 FCEUD_SetPalette(x|0x40,m,n,o);
5232c20c 348
349
c62d2810 350 }
351 }
352 if(!d) return; /* No deemphasis, so return. */
353
354 r=rtmul[d-1];
355 g=gtmul[d-1];
356 b=btmul[d-1];
357
358 for(x=0;x<0x40;x++)
359 {
360 uint32 m,n,o;
361
362 m=palo[x].r;
363 n=palo[x].g;
364 o=palo[x].b;
365 m=(m*r)>>15;
366 n=(n*g)>>15;
367 o=(o*b)>>15;
368 if(m>0xff) m=0xff;
369 if(n>0xff) n=0xff;
370 if(o>0xff) o=0xff;
371
372 FCEUD_SetPalette(x|0xC0,m,n,o);
5232c20c 373
c62d2810 374 }
22f08d95 375
c62d2810 376 lastd=d;
377}
378
379#define HUEVAL ((double)((double)ntschue/(double)2)+(double)300)
380#define TINTVAL ((double)((double)ntsctint/(double)128))
381
382static void CalculatePalette(void)
383{
384 int x,z;
385 int r,g,b;
386 double s,y,theta;
387 static uint8 cols[16]={0,24,21,18,15,12,9,6,3,0,33,30,27,0,0,0};
388 static uint8 br1[4]={6,9,12,12};
389 static double br2[4]={.29,.45,.73,.9};
390 static double br3[4]={0,.24,.47,.77};
22f08d95 391
c62d2810 392 for(x=0;x<=3;x++)
393 for(z=0;z<16;z++)
394 {
395 s=(double)TINTVAL;
396 y=(double)br2[x];
397 if(z==0) {s=0;y=((double)br1[x])/12;}
22f08d95 398
c62d2810 399 if(z>=13)
400 {
401 s=y=0;
402 if(z==13)
22f08d95 403 y=(double)br3[x];
c62d2810 404 }
405
406 theta=(double)M_PI*(double)(((double)cols[z]*10+HUEVAL)/(double)180);
407 r=(int)(((double)y+(double)s*(double)sin(theta))*(double)256);
408 g=(int)(((double)y-(double)((double)27/(double)53)*s*(double)sin(theta)+(double)((double)10/(double)53)*s*cos(theta))*(double)256);
22f08d95 409 b=(int)(((double)y-(double)s*(double)cos(theta))*(double)256);
c62d2810 410
411 // TODO: Fix RGB to compensate for phosphor changes(add to red??).
412
413 if(r>255) r=255;
414 if(g>255) g=255;
415 if(b>255) b=255;
416 if(r<0) r=0;
417 if(g<0) g=0;
418 if(b<0) b=0;
22f08d95 419
c62d2810 420 paletten[(x<<4)+z].r=r;
421 paletten[(x<<4)+z].g=g;
422 paletten[(x<<4)+z].b=b;
423 }
424 WritePalette();
425}
92764e62 426#endif
c62d2810 427
428#include "drawing.h"
429#ifdef FRAMESKIP
430void FCEU_PutImageDummy(void)
431{
432 if(FCEUGameInfo.type!=GIT_NSF)
433 {
434 if(controllength) controllength--;
435 }
436 if(StateShow) StateShow--; /* DrawState() */
437 if(howlong) howlong--; /* DrawMessage() */
438 #ifdef FPS
439 {
440 extern uint64 frcount;
441 frcount++;
442 }
443 #endif
444
445}
446#endif
447
448void FCEU_PutImage(void)
449{
450 if(FCEUGameInfo.type==GIT_NSF)
451 {
452 DrawNSF(XBuf);
453 /* Save snapshot after NSF screen is drawn. Why would we want to
454 do it before?
455 */
456 if(dosnapsave)
457 {
458 ReallySnap();
459 dosnapsave=0;
460 }
461 }
462 else
22f08d95 463 {
c62d2810 464 /* Save snapshot before overlay stuff is written. */
465 if(dosnapsave)
466 {
467 ReallySnap();
468 dosnapsave=0;
469 }
92764e62 470 if(FCEUGameInfo.type==GIT_VSUNI)
471 FCEU_VSUniDraw(XBuf);
472 //if(StateShow) DrawState();
473
474 //FCEU_DrawSaveStates(XBuf);
475 //FCEU_DrawMovies(XBuf);
476 //FCEU_DrawNTSCControlBars(XBuf);
477 //FCEU_DrawRecordingStatus(XBuf);
478
479 //if(controllength) {controllength--;DrawBars();}
c62d2810 480 }
481 DrawMessage();
482 #ifdef FPS
483 {
484 extern uint64 frcount;
485 frcount++;
486 }
487 #endif
488 DrawInput(XBuf+8);
489}
490
92764e62 491#if 0
c62d2810 492static int ipalette=0;
493
494void LoadGamePalette(void)
495{
496 uint8 ptmp[192];
497 FILE *fp;
498 ipalette=0;
499 if((fp=fopen(FCEU_MakeFName(FCEUMKF_PALETTE,0,0),"rb")))
500 {
501 int x;
502 fread(ptmp,1,192,fp);
503 fclose(fp);
504 for(x=0;x<64;x++)
505 {
506 palettei[x].r=ptmp[x+x+x];
507 palettei[x].g=ptmp[x+x+x+1];
508 palettei[x].b=ptmp[x+x+x+2];
509 }
510 ipalette=1;
511 }
512}
513
514void FCEU_ResetPalette(void)
515{
516 ChoosePalette();
517 WritePalette();
518}
519
520static void ChoosePalette(void)
521{
522 if(FCEUGameInfo.type==GIT_NSF)
22f08d95 523 palo=NSFPalette;
c62d2810 524 else if(ipalette)
525 palo=palettei;
526 else if(ntsccol && !PAL && FCEUGameInfo.type!=GIT_VSUNI)
527 {
528 palo=paletten;
529 CalculatePalette();
530 }
531 else
22f08d95 532 palo=palpoint[pale];
c62d2810 533}
534
535void WritePalette(void)
536{
537 int x;
538
539 for(x=0;x<6;x++)
540 FCEUD_SetPalette(x+128,unvpalette[x].r,unvpalette[x].g,unvpalette[x].b);
541 if(FCEUGameInfo.type==GIT_NSF)
542 {
543 for(x=0;x<39;x++)
22f08d95 544 FCEUD_SetPalette(x,palo[x].r,palo[x].g,palo[x].b);
c62d2810 545 }
546 else
547 {
548 for(x=0;x<64;x++)
549 FCEUD_SetPalette(x,palo[x].r,palo[x].g,palo[x].b);
550 SetNESDeemph(lastd,1);
551 }
552}
553
554void FlushCommandQueue(void)
555{
556 if(!netplay && CommandQueue) {DoCommand(CommandQueue);CommandQueue=0;}
557}
558
559void DoCommand(uint8 c)
560{
561 switch(c)
562 {
563 case 1:FDSControl(FDS_SELECT);break;
564 case 2:FDSControl(FDS_IDISK);break;
565 case 3:FDSControl(FDS_EJECT);break;
566
567 case 10:DIPS^=2;break;
568 case 11:vsdip^=1;DIPS|=2;break;
569 case 12:vsdip^=2;DIPS|=2;break;
570 case 13:vsdip^=4;DIPS|=2;break;
571 case 14:vsdip^=8;DIPS|=2;break;
572 case 15:vsdip^=0x10;DIPS|=2;break;
573 case 16:vsdip^=0x20;DIPS|=2;break;
574 case 17:vsdip^=0x40;DIPS|=2;break;
575 case 18:vsdip^=0x80;DIPS|=2;break;
576 case 19:coinon=6;break;
577 case 30:ResetNES();break;
578 case 31:PowerNES();break;
579 case 40:CheckStates();StateShow=0;SaveState();break;
580 case 41:CheckStates();StateShow=0;LoadState();break;
581 case 42: case 43: case 44: case 45: case 46: case 47: case 48: case 49:
582 case 50: case 51:StateShow=180;CurrentState=c-42;CheckStates();break;
583 }
584}
d97315ac 585#endif
586