gpfce patch
[fceu.git] / drivers / win / video.c
CommitLineData
c62d2810 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
21static int RecalcCustom(void);
22
23#define VF_DDSTRETCHED 1
24
25#define VEF_LOSTSURFACE 1
26#define VEF____INTERNAL 2
27
28#define VMDF_DXBLT 1
29#define VMDF_STRFS 2
30
31typedef struct {
32 int x;
33 int y;
34 int bpp;
35 int flags;
36 int xscale;
37 int yscale;
38 RECT srect;
39 RECT drect;
40} vmdef;
41
42// left, top, right, bottom
43static vmdef vmodes[11]={
44 {320,240,8,0,1,1}, //0
45 {320,240,8,0,1,1}, //1
46 {512,384,8,0,1,1}, //2
47 {640,480,8,0,1,1}, //3
48 {640,480,8,0,1,1}, //4
49 {640,480,8,0,1,1}, //5
50 {640,480,8,VMDF_DXBLT,2,2}, //6
51 {1024,768,8,VMDF_DXBLT,4,3}, //7
52 {1280,1024,8,VMDF_DXBLT,5,4}, //8
53 {1600,1200,8,VMDF_DXBLT,6,5}, //9
54 {800,600,8,VMDF_DXBLT|VMDF_STRFS,0,0} //10
55 };
56static DDCAPS caps;
57static int mustrestore=0;
58static DWORD CBM[3];
59
60static int bpp;
61static int vflags;
62static int veflags;
63
64int fssync=0;
65int winsync=0;
66
67static uint32 *palettetranslate=0;
68
69PALETTEENTRY color_palette[256];
70static int PaletteChanged=0;
71
72LPDIRECTDRAWCLIPPER lpClipper=0;
73LPDIRECTDRAW lpDD=0;
74LPDIRECTDRAW4 lpDD4=0;
75LPDIRECTDRAWPALETTE lpddpal;
76
77DDSURFACEDESC2 ddsd;
78
79DDSURFACEDESC2 ddsdback;
80LPDIRECTDRAWSURFACE4 lpDDSPrimary=0;
81LPDIRECTDRAWSURFACE4 lpDDSDBack=0;
82LPDIRECTDRAWSURFACE4 lpDDSBack=0;
83
84static void ShowDDErr(char *s)
85{
86 char tempo[512];
87 sprintf(tempo,"DirectDraw: %s",s);
88 FCEUD_PrintError(tempo);
89}
90
91int RestoreDD(int w)
92{
93 if(w)
94 {
95 if(!lpDDSBack) return 0;
96 if(IDirectDrawSurface4_Restore(lpDDSBack)!=DD_OK) return 0;
97 }
98 else
99 {
100 if(!lpDDSPrimary) return 0;
101 if(IDirectDrawSurface4_Restore(lpDDSPrimary)!=DD_OK) return 0;
102 }
103 veflags|=1;
104 return 1;
105}
106
107void FCEUD_SetPalette(unsigned char index, unsigned char r, unsigned char g, unsigned char b)
108{
109 color_palette[index].peRed=r;
110 color_palette[index].peGreen=g;
111 color_palette[index].peBlue=b;
112 PaletteChanged=1;
113}
114
115void FCEUD_GetPalette(unsigned char i, unsigned char *r, unsigned char *g, unsigned char *b)
116{
117 *r=color_palette[i].peRed;
118 *g=color_palette[i].peGreen;
119 *b=color_palette[i].peBlue;
120}
121
122int InitializeDDraw(void)
123{
124 ddrval = DirectDrawCreate(NULL, &lpDD, NULL);
125 if (ddrval != DD_OK)
126 {
127 ShowDDErr("Error creating DirectDraw object.");
128 return 0;
129 }
130
131 ddrval = IDirectDraw_QueryInterface(lpDD,&IID_IDirectDraw4,(LPVOID *)&lpDD4);
132 IDirectDraw_Release(lpDD);
133
134 if (ddrval != DD_OK)
135 {
136 ShowDDErr("Error querying interface.");
137 return 0;
138 }
139
140 caps.dwSize=sizeof(caps);
141 if(IDirectDraw4_GetCaps(lpDD4,&caps,0)!=DD_OK)
142 {
143 ShowDDErr("Error getting capabilities.");
144 return 0;
145 }
146 return 1;
147}
148
149static int GetBPP(void)
150{
151 DDPIXELFORMAT ddpix;
152
153 memset(&ddpix,0,sizeof(ddpix));
154 ddpix.dwSize=sizeof(ddpix);
155
156 ddrval=IDirectDrawSurface4_GetPixelFormat(lpDDSPrimary,&ddpix);
157 if (ddrval != DD_OK)
158 {
159 ShowDDErr("Error getting primary surface pixel format.");
160 return 0;
161 }
162
163 if(ddpix.dwFlags&DDPF_RGB)
164 {
165 bpp=ddpix.DUMMYUNIONNAMEN(1).dwRGBBitCount;
166 CBM[0]=ddpix.DUMMYUNIONNAMEN(2).dwRBitMask;
167 CBM[1]=ddpix.DUMMYUNIONNAMEN(3).dwGBitMask;
168 CBM[2]=ddpix.DUMMYUNIONNAMEN(4).dwBBitMask;
169 }
170 else
171 {
172 ShowDDErr("RGB data not valid.");
173 return 0;
174 }
175 if(bpp==15) bpp=16;
176
177 return 1;
178}
179
180static int InitBPPStuff(void)
181{
182 if(bpp==16)
183 palettetranslate=malloc(65536*4);
184 else if(bpp>=24)
185 palettetranslate=malloc(256*4);
186 else if(bpp==8)
187 {
188 ddrval=IDirectDraw4_CreatePalette( lpDD4, DDPCAPS_8BIT|DDPCAPS_ALLOW256|DDPCAPS_INITIALIZE,color_palette,&lpddpal,NULL);
189 if (ddrval != DD_OK)
190 {
191 ShowDDErr("Error creating palette object.");
192 return 0;
193 }
194 ddrval=IDirectDrawSurface4_SetPalette(lpDDSPrimary, lpddpal);
195 if (ddrval != DD_OK)
196 {
197 ShowDDErr("Error setting palette object.");
198 return 0;
199 }
200 }
201 return 1;
202}
203
204int SetVideoMode(int fs)
205{
206 if(!lpDD4) // DirectDraw not initialized
207 return(1);
208
209 if(fs)
210 if(!vmod)
211 if(!RecalcCustom())
212 return(0);
213
214 vflags=0;
215 veflags=1;
216 PaletteChanged=1;
217
218 ResetVideo();
219
220 if(!fs)
221 {
222 ShowCursorAbs(1);
223 windowedfailed=1;
224 HideFWindow(0);
225
226 ddrval = IDirectDraw4_SetCooperativeLevel ( lpDD4, hAppWnd, DDSCL_NORMAL);
227 if (ddrval != DD_OK)
228 {
229 ShowDDErr("Error setting cooperative level.");
230 return 1;
231 }
232
233 /* Beginning */
234 memset(&ddsd,0,sizeof(ddsd));
235 ddsd.dwSize = sizeof(ddsd);
236 ddsd.dwFlags = DDSD_CAPS;
237 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
238
239 ddrval = IDirectDraw4_CreateSurface ( lpDD4, &ddsd, &lpDDSPrimary,(IUnknown FAR*)NULL);
240 if (ddrval != DD_OK)
241 {
242 ShowDDErr("Error creating primary surface.");
243 return 1;
244 }
245
246 memset(&ddsdback,0,sizeof(ddsdback));
247 ddsdback.dwSize=sizeof(ddsdback);
248 ddsdback.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
249 ddsdback.ddsCaps.dwCaps= DDSCAPS_OFFSCREENPLAIN;
250
251 ddsdback.dwWidth=256;
252 ddsdback.dwHeight=240;
253
254 /* If no blit hardware is present, make sure buffer is created
255 in system memory.
256 */
257 if(!(caps.dwCaps&DDCAPS_BLT))
258 ddsdback.ddsCaps.dwCaps|=DDSCAPS_SYSTEMMEMORY;
259
260 ddrval = IDirectDraw4_CreateSurface ( lpDD4, &ddsdback, &lpDDSBack, (IUnknown FAR*)NULL);
261 if (ddrval != DD_OK)
262 {
263 ShowDDErr("Error creating secondary surface.");
264 return 0;
265 }
266
267 if(!GetBPP())
268 return 0;
269
270 if(bpp!=16 && bpp!=24 && bpp!=32)
271 {
272 ShowDDErr("Current bit depth not supported!");
273 return 0;
274 }
275
276 if(!InitBPPStuff())
277 return 0;
278
279 ddrval=IDirectDraw4_CreateClipper(lpDD4,0,&lpClipper,0);
280 if (ddrval != DD_OK)
281 {
282 ShowDDErr("Error creating clipper.");
283 return 0;
284 }
285
286 ddrval=IDirectDrawClipper_SetHWnd(lpClipper,0,hAppWnd);
287 if (ddrval != DD_OK)
288 {
289 ShowDDErr("Error setting clipper window.");
290 return 0;
291 }
292 ddrval=IDirectDrawSurface4_SetClipper(lpDDSPrimary,lpClipper);
293 if (ddrval != DD_OK)
294 {
295 ShowDDErr("Error attaching clipper to primary surface.");
296 return 0;
297 }
298
299 windowedfailed=0;
300 SetMainWindowStuff();
301 }
302 else
303 {
304 HideFWindow(1);
305
306 ddrval = IDirectDraw4_SetCooperativeLevel ( lpDD4, hAppWnd,DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT);
307 if (ddrval != DD_OK)
308 {
309 ShowDDErr("Error setting cooperative level.");
310 return 0;
311 }
312
313 ddrval = IDirectDraw4_SetDisplayMode(lpDD4, vmodes[vmod].x, vmodes[vmod].y,vmodes[vmod].bpp,0,0);
314 if (ddrval != DD_OK)
315 {
316 ShowDDErr("Error setting display mode.");
317 return 0;
318 }
319 if(vmodes[vmod].flags&VMDF_DXBLT)
320 {
321 memset(&ddsdback,0,sizeof(ddsdback));
322 ddsdback.dwSize=sizeof(ddsdback);
323 ddsdback.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
324 ddsdback.ddsCaps.dwCaps= DDSCAPS_OFFSCREENPLAIN;
325
326 ddsdback.dwWidth=256; //vmodes[vmod].srect.right;
327 ddsdback.dwHeight=240; //vmodes[vmod].srect.bottom;
328
329 if(!(caps.dwCaps&DDCAPS_BLT))
330 ddsdback.ddsCaps.dwCaps|=DDSCAPS_SYSTEMMEMORY;
331
332 ddrval = IDirectDraw4_CreateSurface ( lpDD4, &ddsdback, &lpDDSBack, (IUnknown FAR*)NULL);
333 if(ddrval!=DD_OK)
334 {
335 ShowDDErr("Error creating secondary surface.");
336 return 0;
337 }
338 }
339
340 // create foreground surface
341
342 memset(&ddsd,0,sizeof(ddsd));
343 ddsd.dwSize = sizeof(ddsd);
344
345 ddsd.dwFlags = DDSD_CAPS;
346 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
347
348 if(fssync==2) // Double buffering.
349 {
350 ddsd.dwFlags |= DDSD_BACKBUFFERCOUNT;
351 ddsd.dwBackBufferCount = 1;
352 ddsd.ddsCaps.dwCaps |= DDSCAPS_COMPLEX | DDSCAPS_FLIP;
353 }
354
355 ddrval = IDirectDraw4_CreateSurface ( lpDD4, &ddsd, &lpDDSPrimary,(IUnknown FAR*)NULL);
356 if (ddrval != DD_OK)
357 {
358 ShowDDErr("Error creating primary surface.");
359 return 0;
360 }
361
362 if(fssync==2)
363 {
364 DDSCAPS2 tmp;
365
366 memset(&tmp,0,sizeof(tmp));
367 tmp.dwCaps=DDSCAPS_BACKBUFFER;
368
369 if(IDirectDrawSurface4_GetAttachedSurface(lpDDSPrimary,&tmp,&lpDDSDBack)!=DD_OK)
370 {
371 ShowDDErr("Error getting attached surface.");
372 return 0;
373 }
374 }
375
376 if(!GetBPP())
377 return 0;
378 if(!InitBPPStuff())
379 return 0;
380
381 mustrestore=1;
382 ShowCursorAbs(0);
383 }
384
385 InputScreenChanged(fs);
386 fullscreen=fs;
387 return 1;
388}
389
390static void BlitScreenWindow(uint8 *XBuf);
391static void BlitScreenFull(uint8 *XBuf);
392
393void FCEUD_BlitScreen(uint8 *XBuf)
394{
395 doagain:
396
397 UpdateFCEUWindow();
398
399 if(!(eoptions&EO_BGRUN))
400 while(nofocus)
401 {
402 Sleep(50);
403 BlockingCheck();
404 }
405
406
407 /* This complex statement deserves some explanation.
408 Make sure this special speed throttling hasn't been disabled by the user
409 first. Second, we don't want to throttle the speed if the fast-forward
410 button is pressed down(or during certain network play conditions).
411
412 Now, if we're at this point, we'll throttle speed if sound is disabled.
413 Otherwise, it gets a bit more complicated. We'll throttle speed if focus
414 to FCE Ultra has been lost and we're writing to the primary sound buffer
415 because our sound code won't block. Blocking does seem to work when
416 writing to a secondary buffer, so we won't throttle when a secondary
417 buffer is used.
418 */
419
420 if(!(eoptions&EO_NOTHROTTLE))
421 if(!NoWaiting)
422 if(!soundo || (soundo && nofocus && !(soundoptions&SO_SECONDARY)) )
423 SpeedThrottle();
424
425 if(fullscreen)
426 {
427 if(fssync==1 && !NoWaiting)
428 IDirectDraw4_WaitForVerticalBlank(lpDD4,DDWAITVB_BLOCKBEGIN,0);
429
430 BlitScreenFull(XBuf);
431 }
432 else
433 {
434 if(winsync && !NoWaiting)
435 IDirectDraw4_WaitForVerticalBlank(lpDD4,DDWAITVB_BLOCKBEGIN,0);
436
437 if(!windowedfailed)
438 BlitScreenWindow(XBuf);
439 }
440 if(userpause)
441 {
442 StopSound();
443 Sleep(50);
444 BlockingCheck();
445 goto doagain;
446 }
447}
448
449static INLINE void BlitVidHi(uint8 *src, uint8 *dest, /*int xr,*/ int yr, int pitch)
450{
451 int x,y;
452 int pinc;
453
454 if(!(eoptions&EO_CLIPSIDES))
455 switch(bpp)
456 {
457 case 32:
458
459 pinc=pitch-(256<<2);
460 for(y=yr;y;y--)
461 {
462 for(x=256;x;x--)
463 {
464 *(uint32 *)dest=palettetranslate[(uint32)*src];
465 dest+=4;
466 src++;
467 }
468 dest+=pinc;
469 src+=16;
470 }
471 break;
472
473 case 24:
474 pinc=pitch-(256*3);
475 for(y=yr;y;y--)
476 {
477 for(x=256;x;x--)
478 {
479 uint32 tmp;
480 tmp=palettetranslate[(uint32)*src];
481 *(uint16*)dest=(uint16)tmp;
482 *&dest[2]=(uint8)(tmp>>16);
483 dest+=3;
484 src++;
485 }
486 dest+=pinc;
487 src+=16;
488 }
489 break;
490
491 case 16:
492 pinc=pitch-(256<<1);
493 for(y=yr;y;y--)
494 {
495 for(x=256>>1;x;x--)
496 {
497 *(unsigned long *)dest=palettetranslate[*(unsigned short *)src];
498 dest+=4;
499 src+=2;
500 }
501 dest+=pinc;
502 src+=16;
503 }
504 break;
505 }
506 else
507 switch(bpp)
508 {
509 case 32:
510
511 pinc=pitch-(240<<2);
512 for(y=yr;y;y--)
513 {
514 for(x=240;x;x--)
515 {
516 *(uint32 *)dest=palettetranslate[(uint32)*src];
517 dest+=4;
518 src++;
519 }
520 dest+=pinc;
521 src+=32;
522 }
523 break;
524
525 case 24:
526 pinc=pitch-(240*3);
527 for(y=yr;y;y--)
528 {
529 for(x=240;x;x--)
530 {
531 uint32 tmp;
532 tmp=palettetranslate[(uint32)*src];
533 *(uint16*)dest=(uint16)tmp;
534 *&dest[2]=(uint8)(tmp>>16);
535 dest+=3;
536 src++;
537 }
538 dest+=pinc;
539 src+=32;
540 }
541 break;
542 case 16:
543 pinc=pitch-(240<<1);
544 for(y=yr;y;y--)
545 {
546 for(x=240>>1;x;x--)
547 {
548 *(unsigned long *)dest=palettetranslate[*(unsigned short *)src];
549 dest+=4;
550 src+=2;
551 }
552 dest+=pinc;
553 src+=32;
554 }
555 break;
556 }
557}
558
559static INLINE void FixPaletteHi(void)
560{
561 int x;
562
563 switch(bpp)
564 {
565 case 16:{
566 int cshiftr[3];
567 int cshiftl[3];
568 int a,x,z,y;
569
570 cshiftl[0]=cshiftl[1]=cshiftl[2]=-1;
571 for(a=0;a<3;a++)
572 {
573 for(x=0,y=-1,z=0;x<16;x++)
574 {
575 if(CBM[a]&(1<<x))
576 {
577 if(cshiftl[a]==-1) cshiftl[a]=x;
578 z++;
579 }
580 }
581 cshiftr[a]=(8-z);
582 }
583
584 for(x=0;x<65536;x++)
585 {
586 uint16 lower,upper;
587 lower=(color_palette[x&255].peRed>>cshiftr[0])<<cshiftl[0];
588 lower|=(color_palette[x&255].peGreen>>cshiftr[1])<<cshiftl[1];
589 lower|=(color_palette[x&255].peBlue>>cshiftr[2])<<cshiftl[2];
590 upper=(color_palette[x>>8].peRed>>cshiftr[0])<<cshiftl[0];
591 upper|=(color_palette[x>>8].peGreen>>cshiftr[1])<<cshiftl[1];
592 upper|=(color_palette[x>>8].peBlue>>cshiftr[2])<<cshiftl[2];
593 palettetranslate[x]=lower|(upper<<16);
594 }
595 }
596 break;
597 case 24:
598 case 32:
599 for(x=0;x<256;x++)
600 {
601 uint32 t;
602 t=0;
603 t=color_palette[x].peBlue;
604 t|=color_palette[x].peGreen<<8;
605 t|=color_palette[x].peRed<<16;
606 palettetranslate[x]=t;
607 }
608 break;
609 }
610}
611
612static void BlitScreenWindow(unsigned char *XBuf)
613{
614 int pitch;
615 unsigned char *ScreenLoc;
616 static RECT srect;
617 RECT drect;
618
619 srect.top=srect.left=0;
620 srect.right=VNSWID;
621 srect.bottom=totallines;
622
623 if(PaletteChanged==1)
624 {
625 FixPaletteHi();
626 PaletteChanged=0;
627 }
628 if(!GetClientAbsRect(&drect)) return;
629
630 ddrval=IDirectDrawSurface4_Lock(lpDDSBack,NULL,&ddsdback, 0, NULL);
631 if(ddrval!=DD_OK)
632 {
633 if(ddrval==DDERR_SURFACELOST) RestoreDD(1);
634 return;
635 }
636 pitch=ddsdback.DUMMYUNIONNAMEN(1).lPitch;
637 ScreenLoc=ddsdback.lpSurface;
638
639 if(veflags&1)
640 {
641 memset(ScreenLoc,0,pitch*240);
642 veflags&=~1;
643 }
644
645 BlitVidHi(XBuf+srendline*272+VNSCLIP, ScreenLoc, /*VNSWID,*/ totallines, pitch);
646
647 IDirectDrawSurface4_Unlock(lpDDSBack, NULL);
648
649 if(IDirectDrawSurface4_Blt(lpDDSPrimary, &drect,lpDDSBack,&srect,DDBLT_ASYNC,0)!=DD_OK)
650 {
651 ddrval=IDirectDrawSurface4_Blt(lpDDSPrimary, &drect,lpDDSBack,&srect,DDBLT_WAIT,0);
652 if(ddrval!=DD_OK)
653 {
654 if(ddrval==DDERR_SURFACELOST) {RestoreDD(1);RestoreDD(0);}
655 return;
656 }
657 }
658}
659
660static void BlitScreenFull(uint8 *XBuf)
661{
662 static int pitch;
663 char *ScreenLoc;
664 unsigned long x;
665 uint8 y;
666 RECT srect,drect;
667 LPDIRECTDRAWSURFACE4 lpDDSVPrimary;
668
669
670 if(fssync==2)
671 lpDDSVPrimary=lpDDSDBack;
672 else
673 lpDDSVPrimary=lpDDSPrimary;
674
675 if(PaletteChanged==1)
676 {
677 if(bpp>=16)
678 FixPaletteHi();
679 else
680 for(x=0;x<=0x80;x+=0x80)
681 {
682 ddrval=IDirectDrawPalette_SetEntries(lpddpal,0,0x80^x,128,&color_palette[x]);
683 if(ddrval!=DD_OK)
684 {
685 if(ddrval==DDERR_SURFACELOST) RestoreDD(0);
686 return;
687 }
688 }
689 PaletteChanged=0;
690 }
691
692 if(vmodes[vmod].flags&VMDF_DXBLT)
693 {
694 ddrval=IDirectDrawSurface4_Lock(lpDDSBack,NULL,&ddsdback, 0, NULL);
695 if(ddrval!=DD_OK)
696 {
697 if(ddrval==DDERR_SURFACELOST) RestoreDD(1);
698 return;
699 }
700 ScreenLoc=ddsdback.lpSurface;
701 pitch=ddsdback.DUMMYUNIONNAMEN(1).lPitch;
702
703 srect.top=0;
704 srect.left=0;
705 srect.right=VNSWID;
706 srect.bottom=totallines;
707 if(vmodes[vmod].flags&VMDF_STRFS)
708 {
709 drect.top=0;
710 drect.left=0;
711 drect.right=vmodes[vmod].x;
712 drect.bottom=vmodes[vmod].y;
713 }
714 else
715 {
716 drect.top=(vmodes[vmod].y-(totallines*vmodes[vmod].yscale))>>1;
717 drect.bottom=drect.top+(totallines*vmodes[vmod].yscale);
718 drect.left=(vmodes[vmod].x-VNSWID*vmodes[vmod].xscale)>>1;
719 drect.right=drect.left+VNSWID*vmodes[vmod].xscale;
720 }
721 }
722 else
723 {
724 ddrval=IDirectDrawSurface4_Lock(lpDDSVPrimary,NULL,&ddsd, 0, NULL);
725 if(ddrval!=DD_OK)
726 {
727 if(ddrval==DDERR_SURFACELOST) RestoreDD(0);
728 return;
729 }
730
731 ScreenLoc=ddsd.lpSurface;
732 pitch=ddsd.DUMMYUNIONNAMEN(1).lPitch;
733 }
734
735 if(veflags&1)
736 {
737 if(vmodes[vmod].flags&VMDF_DXBLT)
738 {
739 veflags|=2;
740 memset((char *)ScreenLoc,0,pitch*srect.bottom);
741 }
742 else
743 {
744 memset((char *)ScreenLoc,0,pitch*vmodes[vmod].y);
745 }
746 PaletteChanged=1;
747 veflags&=~1;
748 }
749
750 if(vmod==5)
751 {
752 if(eoptions&EO_CLIPSIDES)
753 {
754 asm volatile(
755 "xorl %%edx, %%edx\n\t"
756 "akoop1:\n\t"
757 "movb $120,%%al \n\t"
758 "akoop2:\n\t"
759 "movb 1(%%esi),%%dl\n\t"
760 "shl $16,%%edx\n\t"
761 "movb (%%esi),%%dl\n\t"
762 "xorl $0x00800080,%%edx\n\t"
763 "movl %%edx,(%%edi)\n\t"
764 "addl $2,%%esi\n\t"
765 "addl $4,%%edi\n\t"
766 "decb %%al\n\t"
767 "jne akoop2\n\t"
768 "addl $32,%%esi\n\t"
769 "addl %%ecx,%%edi\n\t"
770 "decb %%bl\n\t"
771 "jne akoop1\n\t"
772 :
773 : "S" (XBuf+srendline*272+VNSCLIP), "D" (ScreenLoc+((240-totallines)/2)*pitch+(640-(VNSWID<<1))/2),"b" (totallines), "c" ((pitch-VNSWID)<<1)
774 : "%al", "%edx", "%cc" );
775 }
776 else
777 {
778 asm volatile(
779 "xorl %%edx, %%edx\n\t"
780 "koop1:\n\t"
781 "movb $128,%%al \n\t"
782 "koop2:\n\t"
783 "movb 1(%%esi),%%dl\n\t"
784 "shl $16,%%edx\n\t"
785 "movb (%%esi),%%dl\n\t"
786 "xorl $0x00800080,%%edx\n\t"
787 "movl %%edx,(%%edi)\n\t"
788 "addl $2,%%esi\n\t"
789 "addl $4,%%edi\n\t"
790 "decb %%al\n\t"
791 "jne koop2\n\t"
792 "addl $16,%%esi\n\t"
793 "addl %%ecx,%%edi\n\t"
794 "decb %%bl\n\t"
795 "jne koop1\n\t"
796 :
797 : "S" (XBuf+srendline*272), "D" (ScreenLoc+((240-totallines)/2)*pitch+(640-512)/2),"b" (totallines), "c" (pitch-512+pitch)
798 : "%al", "%edx", "%cc" );
799 }
800 }
801 else if(vmod==4)
802 {
803 if(eoptions&EO_CLIPSIDES)
804 {
805 asm volatile(
806 "ayoop1:\n\t"
807 "movb $120,%%al \n\t"
808 "ayoop2:\n\t"
809 "movb 1(%%esi),%%dh\n\t"
810 "movb %%dh,%%dl\n\t"
811 "shl $16,%%edx\n\t"
812 "movb (%%esi),%%dl\n\t"
813 "movb %%dl,%%dh\n\t" // Ugh
814 "xorl $0x80808080,%%edx\n\t"
815 "movl %%edx,(%%edi)\n\t"
816 "addl $2,%%esi\n\t"
817 "addl $4,%%edi\n\t"
818 "decb %%al\n\t"
819 "jne ayoop2\n\t"
820 "addl $32,%%esi\n\t"
821 "addl %%ecx,%%edi\n\t"
822 "decb %%bl\n\t"
823 "jne ayoop1\n\t"
824 :
825 : "S" (XBuf+srendline*272+VNSCLIP), "D" (ScreenLoc+((240-totallines)/2)*pitch+(640-(VNSWID<<1))/2),"b" (totallines), "c" ((pitch-VNSWID)<<1)
826 : "%al", "%edx", "%cc" );
827 }
828 else
829 {
830 asm volatile(
831 "yoop1:\n\t"
832 "movb $128,%%al \n\t"
833 "yoop2:\n\t"
834 "movb 1(%%esi),%%dh\n\t"
835 "movb %%dh,%%dl\n\t"
836 "shl $16,%%edx\n\t"
837 "movb (%%esi),%%dl\n\t"
838 "movb %%dl,%%dh\n\t" // Ugh
839 "xorl $0x80808080,%%edx\n\t"
840 "movl %%edx,(%%edi)\n\t"
841 "addl $2,%%esi\n\t"
842 "addl $4,%%edi\n\t"
843 "decb %%al\n\t"
844 "jne yoop2\n\t"
845 "addl $16,%%esi\n\t"
846 "addl %%ecx,%%edi\n\t"
847 "decb %%bl\n\t"
848 "jne yoop1\n\t"
849 :
850 : "S" (XBuf+srendline*272), "D" (ScreenLoc+((240-totallines)/2)*pitch+(640-512)/2),"b" (totallines), "c" (pitch-512+pitch)
851 : "%al", "%edx", "%cc" );
852 }
853 }
854 else
855 {
856 if(!(vmodes[vmod].flags&VMDF_DXBLT))
857 {
858 ScreenLoc+=((vmodes[vmod].x-VNSWID)>>1)*(bpp>>3)+(((vmodes[vmod].y-totallines)>>1))*pitch;
859 }
860 if(bpp>=16)
861 {
862 BlitVidHi(XBuf+srendline*272+VNSCLIP, ScreenLoc, /*VNSWID,*/ totallines, pitch);
863 }
864 else
865 {
866 XBuf+=srendline*272+VNSCLIP;
867 if(eoptions&EO_CLIPSIDES)
868 {
869 for(y=totallines;y;y--)
870 {
871 for(x=60;x;x--)
872 {
873 *(long *)ScreenLoc=(*(long *)XBuf)^0x80808080;
874 ScreenLoc+=4;
875 XBuf+=4;
876 }
877 ScreenLoc+=pitch-240;
878 XBuf+=32;
879 }
880 }
881 else
882 {
883 for(y=totallines;y;y--)
884 {
885 for(x=64;x;x--)
886 {
887 *(long *)ScreenLoc=(*(long *)XBuf)^0x80808080;
888 ScreenLoc+=4;
889 XBuf+=4;
890 }
891 ScreenLoc+=pitch-256;
892 XBuf+=16;
893 }
894 }
895 }
896 }
897
898 if(vmodes[vmod].flags&VMDF_DXBLT)
899 {
900 IDirectDrawSurface4_Unlock(lpDDSBack, NULL);
901
902 if(veflags&2)
903 {
904 if(IDirectDrawSurface4_Lock(lpDDSVPrimary,NULL,&ddsd, 0, NULL)==DD_OK)
905 {
906 memset(ddsd.lpSurface,0,ddsd.DUMMYUNIONNAMEN(1).lPitch*vmodes[vmod].y);
907 IDirectDrawSurface4_Unlock(lpDDSVPrimary, NULL);
908 veflags&=~2;
909 }
910 }
911
912
913 if(IDirectDrawSurface4_Blt(lpDDSVPrimary, &drect,lpDDSBack,&srect,DDBLT_ASYNC,0)!=DD_OK)
914 {
915 ddrval=IDirectDrawSurface4_Blt(lpDDSVPrimary, &drect,lpDDSBack,&srect,DDBLT_WAIT,0);
916 if(ddrval!=DD_OK)
917 {
918 if(ddrval==DDERR_SURFACELOST)
919 {
920 RestoreDD(0);
921 RestoreDD(1);
922 }
923 return;
924 }
925
926 }
927 }
928 else
929 IDirectDrawSurface4_Unlock(lpDDSVPrimary, NULL);
930 if(fssync==2)
931 {
932 IDirectDrawSurface4_Flip(lpDDSPrimary,0,0);
933
934 }
935}
936
937void ResetVideo(void)
938{
939 ShowCursorAbs(1);
940 if(palettetranslate) {free(palettetranslate);palettetranslate=0;}
941 if(lpDD4)
942 if(mustrestore)
943 {IDirectDraw4_RestoreDisplayMode(lpDD4);mustrestore=0;}
944 if(lpDDSBack) {IDirectDrawSurface4_Release(lpDDSBack);lpDDSBack=0;}
945 if(lpDDSPrimary) {IDirectDrawSurface4_Release(lpDDSPrimary);lpDDSPrimary=0;}
946 if(lpClipper) {IDirectDrawClipper_Release(lpClipper);lpClipper=0;}
947}
948
949static int RecalcCustom(void)
950{
951 vmodes[0].flags&=~VMDF_DXBLT;
952
953 if(vmodes[0].flags&VMDF_STRFS)
954 {
955 vmodes[0].flags|=VMDF_DXBLT;
956
957 vmodes[0].srect.top=srendline;
958 vmodes[0].srect.left=VNSCLIP;
959 vmodes[0].srect.right=256-VNSCLIP;
960 vmodes[0].srect.bottom=erendline+1;
961
962 vmodes[0].drect.top=vmodes[0].drect.left=0;
963 vmodes[0].drect.right=vmodes[0].x;
964 vmodes[0].drect.bottom=vmodes[0].y;
965 }
966 else if(vmodes[0].xscale!=1 || vmodes[0].yscale!=1)
967 {
968 vmodes[0].flags|=VMDF_DXBLT;
969 if(VNSWID*vmodes[0].xscale>vmodes[0].x)
970 {
971 FCEUD_PrintError("Scaled width is out of range. Reverting to no horizontal scaling.");
972 vmodes[0].xscale=1;
973 }
974 if(totallines*vmodes[0].yscale>vmodes[0].y)
975 {
976 FCEUD_PrintError("Scaled height is out of range. Reverting to no vertical scaling.");
977 vmodes[0].yscale=1;
978 }
979
980 vmodes[0].srect.left=VNSCLIP;
981 vmodes[0].srect.top=srendline;
982 vmodes[0].srect.right=256-VNSCLIP;
983 vmodes[0].srect.bottom=erendline+1;
984
985 vmodes[0].drect.top=(vmodes[0].y-(totallines*vmodes[0].yscale))>>1;
986 vmodes[0].drect.bottom=vmodes[0].drect.top+totallines*vmodes[0].yscale;
987
988 vmodes[0].drect.left=(vmodes[0].x-(VNSWID*vmodes[0].xscale))>>1;
989 vmodes[0].drect.right=vmodes[0].drect.left+VNSWID*vmodes[0].xscale;
990 }
991
992 if(vmodes[0].x<VNSWID)
993 {
994 FCEUD_PrintError("Horizontal resolution is too low.");
995 return(0);
996 }
997 if(vmodes[0].y<totallines && !(vmodes[0].flags&VMDF_STRFS))
998 {
999 FCEUD_PrintError("Vertical resolution must not be less than the total number of drawn scanlines.");
1000 return(0);
1001 }
1002
1003 return(1);
1004}
1005
1006BOOL CALLBACK VideoConCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
1007{
1008 static char *vmstr[11]={
1009 "Custom",
1010 "320x240 Full Screen",
1011 "512x384 Centered",
1012 "640x480 Centered",
1013 "640x480 Scanlines",
1014 "640x480 \"4 per 1\"",
1015 "640x480 2x,2y",
1016 "1024x768 4x,3y",
1017 "1280x1024 5x,4y",
1018 "1600x1200 6x,5y",
1019 "800x600 Stretched"
1020 };
1021 int x;
1022
1023 switch(uMsg)
1024 {
1025 case WM_INITDIALOG:
1026 for(x=0;x<11;x++)
1027 SendDlgItemMessage(hwndDlg,100,CB_ADDSTRING,0,(LPARAM)(LPSTR)vmstr[x]);
1028 SendDlgItemMessage(hwndDlg,100,CB_SETCURSEL,vmod,(LPARAM)(LPSTR)0);
1029
1030 SendDlgItemMessage(hwndDlg,202,CB_ADDSTRING,0,(LPARAM)(LPSTR)"8");
1031 SendDlgItemMessage(hwndDlg,202,CB_ADDSTRING,0,(LPARAM)(LPSTR)"16");
1032 SendDlgItemMessage(hwndDlg,202,CB_ADDSTRING,0,(LPARAM)(LPSTR)"24");
1033 SendDlgItemMessage(hwndDlg,202,CB_ADDSTRING,0,(LPARAM)(LPSTR)"32");
1034 SendDlgItemMessage(hwndDlg,202,CB_SETCURSEL,(vmodes[0].bpp>>3)-1,(LPARAM)(LPSTR)0);
1035
1036 SetDlgItemInt(hwndDlg,200,vmodes[0].x,0);
1037 SetDlgItemInt(hwndDlg,201,vmodes[0].y,0);
1038
1039 SetDlgItemInt(hwndDlg,302,vmodes[0].xscale,0);
1040 SetDlgItemInt(hwndDlg,303,vmodes[0].yscale,0);
1041 CheckRadioButton(hwndDlg,300,301,(vmodes[0].flags&VMDF_STRFS)?301:300);
1042 if(eoptions&EO_FSAFTERLOAD)
1043 CheckDlgButton(hwndDlg,102,BST_CHECKED);
1044
1045 if(eoptions&EO_CLIPSIDES)
1046 CheckDlgButton(hwndDlg,106,BST_CHECKED);
1047
1048 SetDlgItemInt(hwndDlg,500,srendlinen,0);
1049 SetDlgItemInt(hwndDlg,501,erendlinen,0);
1050
1051 SetDlgItemInt(hwndDlg,502,srendlinep,0);
1052 SetDlgItemInt(hwndDlg,503,erendlinep,0);
1053
1054
1055 SetDlgItemInt(hwndDlg,103,winsizemul,0);
1056
1057 SendDlgItemMessage(hwndDlg,104,CB_ADDSTRING,0,(LPARAM)(LPSTR)"<none>");
1058 SendDlgItemMessage(hwndDlg,105,CB_ADDSTRING,0,(LPARAM)(LPSTR)"<none>");
1059
1060 SendDlgItemMessage(hwndDlg,104,CB_ADDSTRING,0,(LPARAM)(LPSTR)"Wait for VBlank");
1061 SendDlgItemMessage(hwndDlg,105,CB_ADDSTRING,0,(LPARAM)(LPSTR)"Wait for VBlank");
1062
1063 SendDlgItemMessage(hwndDlg,105,CB_ADDSTRING,0,(LPARAM)(LPSTR)"Double Buffering");
1064
1065 SendDlgItemMessage(hwndDlg,104,CB_SETCURSEL,winsync,(LPARAM)(LPSTR)0);
1066 SendDlgItemMessage(hwndDlg,105,CB_SETCURSEL,fssync,(LPARAM)(LPSTR)0);
1067 break;
1068 case WM_CLOSE:
1069 case WM_QUIT: goto gornk;
1070 case WM_COMMAND:
1071 if(!(wParam>>16))
1072 switch(wParam&0xFFFF)
1073 {
1074 case 1:
1075 gornk:
1076
1077 if(IsDlgButtonChecked(hwndDlg,106)==BST_CHECKED)
1078 eoptions|=EO_CLIPSIDES;
1079 else
1080 eoptions&=~EO_CLIPSIDES;
1081
1082 srendlinen=GetDlgItemInt(hwndDlg,500,0,0);
1083 erendlinen=GetDlgItemInt(hwndDlg,501,0,0);
1084 srendlinep=GetDlgItemInt(hwndDlg,502,0,0);
1085 erendlinep=GetDlgItemInt(hwndDlg,503,0,0);
1086
1087
1088 if(erendlinen>239) erendlinen=239;
1089 if(srendlinen>erendlinen) srendlinen=erendlinen;
1090
1091 if(erendlinep>239) erendlinep=239;
1092 if(srendlinep>erendlinen) srendlinep=erendlinep;
1093
1094 UpdateRendBounds();
1095
1096 if(IsDlgButtonChecked(hwndDlg,301)==BST_CHECKED)
1097 vmodes[0].flags|=VMDF_STRFS;
1098 else
1099 vmodes[0].flags&=~VMDF_STRFS;
1100
1101 vmod=SendDlgItemMessage(hwndDlg,100,CB_GETCURSEL,0,(LPARAM)(LPSTR)0);
1102 vmodes[0].x=GetDlgItemInt(hwndDlg,200,0,0);
1103 vmodes[0].y=GetDlgItemInt(hwndDlg,201,0,0);
1104 vmodes[0].bpp=(SendDlgItemMessage(hwndDlg,202,CB_GETCURSEL,0,(LPARAM)(LPSTR)0)+1)<<3;
1105
1106 vmodes[0].xscale=GetDlgItemInt(hwndDlg,302,0,0);
1107 vmodes[0].yscale=GetDlgItemInt(hwndDlg,303,0,0);
1108
1109 if(IsDlgButtonChecked(hwndDlg,101)==BST_CHECKED)
1110 fullscreen=1;
1111 else
1112 fullscreen=0;
1113 if(IsDlgButtonChecked(hwndDlg,102)==BST_CHECKED)
1114 eoptions|=EO_FSAFTERLOAD;
1115 else
1116 eoptions&=~EO_FSAFTERLOAD;
1117
1118 {
1119 int t=GetDlgItemInt(hwndDlg,103,0,0);
1120 if(t>0 && t<60)
1121 winsizemul=t;
1122 }
1123 winsync=SendDlgItemMessage(hwndDlg,104,CB_GETCURSEL,0,(LPARAM)(LPSTR)0);
1124 fssync=SendDlgItemMessage(hwndDlg,105,CB_GETCURSEL,0,(LPARAM)(LPSTR)0);
1125 EndDialog(hwndDlg,0);
1126 break;
1127 }
1128 }
1129 return 0;
1130}
1131
1132static void SetFSVideoMode(void)
1133{
1134 changerecursive=1;
1135 if(!SetVideoMode(1))
1136 SetVideoMode(0);
1137 changerecursive=0;
1138}
1139
1140
1141
1142void ConfigVideo(void)
1143{
1144 DialogBox(fceu_hInstance,"VIDEOCONFIG",hAppWnd,VideoConCallB);
1145 UpdateRendBounds();
1146 if(fullscreen)
1147 SetFSVideoMode();
1148 else
1149 SetMainWindowStuff();
1150}
1151
1152void DoVideoConfigFix(void)
1153{
1154 UpdateRendBounds();
1155}
1156
1157
1158#ifdef moo
1159 if(!vmod)
1160 {
1161 if(vmodes[0].x<VNSWID)
1162 {
1163 FCEUD_PrintError("Horizontal resolution is too low.");
1164 return 0;
1165 }
1166 if(vmodes[0].y<totallines && !(vmodes[0].flags&VMDF_STRFS))
1167 {
1168 FCEUD_PrintError("Vertical resolution must not be less than the total number of drawn scanlines.");
1169 return 0;
1170 }
1171 }
1172
1173
1174#endif