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