/* FCE Ultra - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2002 Xodnizel * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ static int RecalcCustom(void); #define VF_DDSTRETCHED 1 #define VEF_LOSTSURFACE 1 #define VEF____INTERNAL 2 #define VMDF_DXBLT 1 #define VMDF_STRFS 2 typedef struct { int x; int y; int bpp; int flags; int xscale; int yscale; RECT srect; RECT drect; int special; } vmdef; // left, top, right, bottom static vmdef vmodes[11]={ {320,240,8,0,1,1,0}, //0 {320,240,8,0,1,1,0}, //1 {512,384,8,0,1,1,0}, //2 {640,480,8,0,1,1,0}, //3 {640,480,8,0,1,1,0}, //4 {640,480,8,0,1,1,0}, //5 {640,480,8,VMDF_DXBLT,2,2,0}, //6 {1024,768,8,VMDF_DXBLT,4,3,0}, //7 {1280,1024,8,VMDF_DXBLT,5,4,0}, //8 {1600,1200,8,VMDF_DXBLT,6,5,0}, //9 {800,600,8,VMDF_DXBLT|VMDF_STRFS,0,0} //10 }; static DDCAPS caps; static int mustrestore=0; static DWORD CBM[3]; static int bpp; static int vflags; static int veflags; static int winspecial = 0; int disvaccel = 0; /* Disable video hardware acceleration. */ int fssync=0; int winsync=0; #ifdef _USE_SHARED_MEMORY_ PALETTEENTRY *color_palette; // shared memory changes HANDLE mapColorPalette; #else PALETTEENTRY color_palette[256]; #endif //_USE_SHARED_MEMORY_ static int PaletteChanged=0; LPDIRECTDRAWCLIPPER lpClipper=0; LPDIRECTDRAW lpDD=0; LPDIRECTDRAW7 lpDD7=0; LPDIRECTDRAWPALETTE lpddpal = 0; DDSURFACEDESC2 ddsd; DDSURFACEDESC2 ddsdback; LPDIRECTDRAWSURFACE7 lpDDSPrimary=0; LPDIRECTDRAWSURFACE7 lpDDSDBack=0; LPDIRECTDRAWSURFACE7 lpDDSBack=0; static void ShowDDErr(char *s) { char tempo[512]; sprintf(tempo,"DirectDraw: %s",s); FCEUD_PrintError(tempo); } int RestoreDD(int w) { if(w) { if(!lpDDSBack) return 0; if(IDirectDrawSurface7_Restore(lpDDSBack)!=DD_OK) return 0; } else { if(!lpDDSPrimary) return 0; if(IDirectDrawSurface7_Restore(lpDDSPrimary)!=DD_OK) return 0; } veflags|=1; return 1; } void FCEUD_SetPalette(unsigned char index, unsigned char r, unsigned char g, unsigned char b) { color_palette[index].peRed=r; color_palette[index].peGreen=g; color_palette[index].peBlue=b; PaletteChanged=1; } void FCEUD_GetPalette(unsigned char i, unsigned char *r, unsigned char *g, unsigned char *b) { *r=color_palette[i].peRed; *g=color_palette[i].peGreen; *b=color_palette[i].peBlue; } static int InitializeDDraw(int fs) { #ifdef _USE_SHARED_MEMORY_ mapColorPalette = CreateFileMapping((HANDLE)0xFFFFFFFF,NULL,PAGE_READWRITE, 0, 256 * sizeof(PALETTEENTRY),"fceu.ColorPalette"); if(mapColorPalette == NULL || GetLastError() == ERROR_ALREADY_EXISTS) { CloseHandle(mapColorPalette); mapColorPalette = NULL; color_palette = (PALETTEENTRY*)malloc(256 * sizeof(PALETTEENTRY)); //mbg merge 7/18/06 added cast } else color_palette = (PALETTEENTRY *)MapViewOfFile(mapColorPalette, FILE_MAP_WRITE, 0, 0, 0); #endif //(disvaccel&(1<<(fs?1:0)))?(GUID FAR *)DDCREATE_EMULATIONONLY: ddrval = DirectDrawCreate((disvaccel&(1<<(fs?1:0)))?(GUID FAR *)DDCREATE_EMULATIONONLY:NULL, &lpDD, NULL); if (ddrval != DD_OK) { ShowDDErr("Error creating DirectDraw object."); return 0; } //mbg merge 7/17/06 changed: ddrval = IDirectDraw_QueryInterface(lpDD,IID_IDirectDraw7,(LPVOID *)&lpDD7); //ddrval = IDirectDraw_QueryInterface(lpDD,&IID_IDirectDraw7,(LPVOID *)&lpDD7); IDirectDraw_Release(lpDD); if (ddrval != DD_OK) { ShowDDErr("Error querying interface."); return 0; } caps.dwSize=sizeof(caps); if(IDirectDraw7_GetCaps(lpDD7,&caps,0)!=DD_OK) { ShowDDErr("Error getting capabilities."); return 0; } return 1; } static int GetBPP(void) { DDPIXELFORMAT ddpix; memset(&ddpix,0,sizeof(ddpix)); ddpix.dwSize=sizeof(ddpix); ddrval=IDirectDrawSurface7_GetPixelFormat(lpDDSPrimary,&ddpix); if (ddrval != DD_OK) { ShowDDErr("Error getting primary surface pixel format."); return 0; } if(ddpix.dwFlags&DDPF_RGB) { //mbg merge 7/17/06 removed silly dummy union stuff now that we have c++ bpp=ddpix.dwRGBBitCount; CBM[0]=ddpix.dwRBitMask; CBM[1]=ddpix.dwGBitMask; CBM[2]=ddpix.dwBBitMask; } else { ShowDDErr("RGB data not valid."); return 0; } if(bpp==15) bpp=16; return 1; } static int InitBPPStuff(int fs) { if(bpp >= 16) { InitBlitToHigh(bpp >> 3, CBM[0], CBM[1], CBM[2], 0, fs?vmodes[vmod].special:winspecial); } else if(bpp==8) { ddrval=IDirectDraw7_CreatePalette( lpDD7, DDPCAPS_8BIT|DDPCAPS_ALLOW256|DDPCAPS_INITIALIZE,color_palette,&lpddpal,NULL); if (ddrval != DD_OK) { ShowDDErr("Error creating palette object."); return 0; } ddrval=IDirectDrawSurface7_SetPalette(lpDDSPrimary, lpddpal); if (ddrval != DD_OK) { ShowDDErr("Error setting palette object."); return 0; } } return 1; } int SetVideoMode(int fs) { int specmul; // Special scaler size multiplier if(fs) if(!vmod) if(!RecalcCustom()) return(0); vflags=0; veflags=1; PaletteChanged=1; ResetVideo(); StopSound(); if(!InitializeDDraw(fs)) return(1); // DirectDraw not initialized if(!fs) { if(winspecial == 2 || winspecial == 1) specmul = 2; else if(winspecial == 3 || winspecial == 4) specmul = 3; else specmul = 1; ShowCursorAbs(1); windowedfailed=1; HideFWindow(0); ddrval = IDirectDraw7_SetCooperativeLevel ( lpDD7, hAppWnd, DDSCL_NORMAL); if (ddrval != DD_OK) { ShowDDErr("Error setting cooperative level."); return 1; } /* Beginning */ memset(&ddsd,0,sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_CAPS; ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; ddrval = IDirectDraw7_CreateSurface ( lpDD7, &ddsd, &lpDDSPrimary,(IUnknown FAR*)NULL); if (ddrval != DD_OK) { FCEU_PrintError("%08x, %d\n",ddrval,lpDD7); ShowDDErr("Error creating primary surface."); return 1; } memset(&ddsdback,0,sizeof(ddsdback)); ddsdback.dwSize=sizeof(ddsdback); ddsdback.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; ddsdback.ddsCaps.dwCaps= DDSCAPS_OFFSCREENPLAIN; ddsdback.dwWidth=256 * specmul; ddsdback.dwHeight=240 * specmul; /* If the blit hardware can't stretch, assume it's cheap(and slow) and create the buffer in system memory. */ if(!(caps.dwCaps&DDCAPS_BLTSTRETCH)) ddsdback.ddsCaps.dwCaps|=DDSCAPS_SYSTEMMEMORY; ddrval = IDirectDraw7_CreateSurface ( lpDD7, &ddsdback, &lpDDSBack, (IUnknown FAR*)NULL); if (ddrval != DD_OK) { ShowDDErr("Error creating secondary surface."); return 0; } if(!GetBPP()) return 0; if(bpp!=16 && bpp!=24 && bpp!=32) { ShowDDErr("Current bit depth not supported!"); return 0; } if(!InitBPPStuff(fs)) return 0; ddrval=IDirectDraw7_CreateClipper(lpDD7,0,&lpClipper,0); if (ddrval != DD_OK) { ShowDDErr("Error creating clipper."); return 0; } ddrval=IDirectDrawClipper_SetHWnd(lpClipper,0,hAppWnd); if (ddrval != DD_OK) { ShowDDErr("Error setting clipper window."); return 0; } ddrval=IDirectDrawSurface7_SetClipper(lpDDSPrimary,lpClipper); if (ddrval != DD_OK) { ShowDDErr("Error attaching clipper to primary surface."); return 0; } windowedfailed=0; SetMainWindowStuff(); } else /* Following is full-screen */ { if(vmod == 0) { if(vmodes[0].special == 2 || vmodes[0].special == 1) specmul = 2; else if(vmodes[0].special == 3 || vmodes[0].special == 4) specmul = 3; else specmul = 1; } HideFWindow(1); ddrval = IDirectDraw7_SetCooperativeLevel ( lpDD7, hAppWnd,DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT); if (ddrval != DD_OK) { ShowDDErr("Error setting cooperative level."); return 0; } ddrval = IDirectDraw7_SetDisplayMode(lpDD7, vmodes[vmod].x, vmodes[vmod].y,vmodes[vmod].bpp,0,0); if (ddrval != DD_OK) { ShowDDErr("Error setting display mode."); return 0; } if(vmodes[vmod].flags&VMDF_DXBLT) { memset(&ddsdback,0,sizeof(ddsdback)); ddsdback.dwSize=sizeof(ddsdback); ddsdback.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; ddsdback.ddsCaps.dwCaps= DDSCAPS_OFFSCREENPLAIN; ddsdback.dwWidth=256 * specmul; //vmodes[vmod].srect.right; ddsdback.dwHeight=240 * specmul; //vmodes[vmod].srect.bottom; if(!(caps.dwCaps&DDCAPS_BLTSTRETCH)) ddsdback.ddsCaps.dwCaps|=DDSCAPS_SYSTEMMEMORY; ddrval = IDirectDraw7_CreateSurface ( lpDD7, &ddsdback, &lpDDSBack, (IUnknown FAR*)NULL); if(ddrval!=DD_OK) { ShowDDErr("Error creating secondary surface."); return 0; } } // create foreground surface memset(&ddsd,0,sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_CAPS; ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; if(fssync==3) // Double buffering. { ddsd.dwFlags |= DDSD_BACKBUFFERCOUNT; ddsd.dwBackBufferCount = 1; ddsd.ddsCaps.dwCaps |= DDSCAPS_COMPLEX | DDSCAPS_FLIP; } ddrval = IDirectDraw7_CreateSurface ( lpDD7, &ddsd, &lpDDSPrimary,(IUnknown FAR*)NULL); if (ddrval != DD_OK) { ShowDDErr("Error creating primary surface."); return 0; } if(fssync==3) { DDSCAPS2 tmp; memset(&tmp,0,sizeof(tmp)); tmp.dwCaps=DDSCAPS_BACKBUFFER; if(IDirectDrawSurface7_GetAttachedSurface(lpDDSPrimary,&tmp,&lpDDSDBack)!=DD_OK) { ShowDDErr("Error getting attached surface."); return 0; } } if(!GetBPP()) return 0; if(!InitBPPStuff(fs)) return 0; mustrestore=1; ShowCursorAbs(0); } InputScreenChanged(fs); fullscreen=fs; return 1; } static void BlitScreenWindow(uint8 *XBuf); static void BlitScreenFull(uint8 *XBuf); //static uint8 *XBSave; void FCEUD_BlitScreen(uint8 *XBuf) { xbsave = XBuf; if(!NoWaiting) { int ws; if(fullscreen) ws=fssync; else ws = winsync; if(ws==1) IDirectDraw7_WaitForVerticalBlank(lpDD7,DDWAITVB_BLOCKBEGIN,0); else if(ws == 2) { BOOL invb = 0; while((DD_OK == IDirectDraw7_GetVerticalBlankStatus(lpDD7,&invb)) && !invb) Sleep(0); } } if(fullscreen) { BlitScreenFull(XBuf); } else { if(!windowedfailed) BlitScreenWindow(XBuf); } } static void FixPaletteHi(void) { SetPaletteBlitToHigh((uint8*)color_palette); //mbg merge 7/17/06 added cast } static void BlitScreenWindow(unsigned char *XBuf) { int pitch; unsigned char *ScreenLoc; static RECT srect; RECT drect; int specialmul; if(winspecial == 2 || winspecial == 1) specialmul = 2; else if(winspecial == 4 || winspecial == 3) specialmul = 3; else specialmul = 1; srect.top=srect.left=0; srect.right=VNSWID * specialmul; srect.bottom=totallines * specialmul; if(PaletteChanged==1) { FixPaletteHi(); PaletteChanged=0; } if(!GetClientAbsRect(&drect)) return; ddrval=IDirectDrawSurface7_Lock(lpDDSBack,NULL,&ddsdback, 0, NULL); if(ddrval!=DD_OK) { if(ddrval==DDERR_SURFACELOST) RestoreDD(1); return; } //mbg merge 7/17/06 removing dummyunion stuff pitch=ddsdback.lPitch; ScreenLoc=(unsigned char*)ddsdback.lpSurface; //mbg merge 7/17/06 added cst if(veflags&1) { memset(ScreenLoc,0,pitch*240); veflags&=~1; } Blit8ToHigh(XBuf+srendline*256+VNSCLIP,ScreenLoc, VNSWID, totallines, pitch,specialmul,specialmul); IDirectDrawSurface7_Unlock(lpDDSBack, NULL); if(IDirectDrawSurface7_Blt(lpDDSPrimary, &drect,lpDDSBack,&srect,DDBLT_ASYNC,0)!=DD_OK) { ddrval=IDirectDrawSurface7_Blt(lpDDSPrimary, &drect,lpDDSBack,&srect,DDBLT_WAIT,0); if(ddrval!=DD_OK) { if(ddrval==DDERR_SURFACELOST) {RestoreDD(1);RestoreDD(0);} return; } } } static void BlitScreenFull(uint8 *XBuf) { static int pitch; char *ScreenLoc; //unsigned long x; //mbg merge 7/17/06 removed //uint8 y; //mbg merge 7/17/06 removed RECT srect,drect; LPDIRECTDRAWSURFACE7 lpDDSVPrimary; int specmul; // Special scaler size multiplier if(vmodes[0].special == 2 || vmodes[0].special == 1) specmul = 2; else if(vmodes[0].special == 3 || vmodes[0].special == 4) specmul = 3; else specmul = 1; if(fssync==3) lpDDSVPrimary=lpDDSDBack; else lpDDSVPrimary=lpDDSPrimary; if(PaletteChanged==1) { if(bpp>=16) FixPaletteHi(); else { ddrval=IDirectDrawPalette_SetEntries(lpddpal,0,0,256,color_palette); if(ddrval!=DD_OK) { if(ddrval==DDERR_SURFACELOST) RestoreDD(0); return; } } PaletteChanged=0; } if(vmodes[vmod].flags&VMDF_DXBLT) { ddrval=IDirectDrawSurface7_Lock(lpDDSBack,NULL,&ddsdback, 0, NULL); if(ddrval!=DD_OK) { if(ddrval==DDERR_SURFACELOST) RestoreDD(1); return; } ScreenLoc=(char *)ddsdback.lpSurface; //mbg merge 7/17/06 added cast pitch=ddsdback.lPitch; //mbg merge 7/17/06 removed dummyunion stuff srect.top=0; srect.left=0; srect.right=VNSWID * specmul; srect.bottom=totallines * specmul; if(vmodes[vmod].flags&VMDF_STRFS) { drect.top=0; drect.left=0; drect.right=vmodes[vmod].x; drect.bottom=vmodes[vmod].y; } else { drect.top=(vmodes[vmod].y-(totallines*vmodes[vmod].yscale))>>1; drect.bottom=drect.top+(totallines*vmodes[vmod].yscale); drect.left=(vmodes[vmod].x-VNSWID*vmodes[vmod].xscale)>>1; drect.right=drect.left+VNSWID*vmodes[vmod].xscale; } } else { ddrval=IDirectDrawSurface7_Lock(lpDDSVPrimary,NULL,&ddsd, 0, NULL); if(ddrval!=DD_OK) { if(ddrval==DDERR_SURFACELOST) RestoreDD(0); return; } ScreenLoc=(char*)ddsd.lpSurface; //mbg merge 7/17/06 added cast pitch=ddsd.lPitch; //mbg merge 7/17/06 removing dummyunion stuff } if(veflags&1) { if(vmodes[vmod].flags&VMDF_DXBLT) { veflags|=2; memset((char *)ScreenLoc,0,pitch*srect.bottom); } else { memset((char *)ScreenLoc,0,pitch*vmodes[vmod].y); } PaletteChanged=1; veflags&=~1; } //mbg 6/29/06 merge #ifndef MSVC if(vmod==5) { if(eoptions&EO_CLIPSIDES) { asm volatile( "xorl %%edx, %%edx\n\t" "akoop1:\n\t" "movb $120,%%al \n\t" "akoop2:\n\t" "movb 1(%%esi),%%dl\n\t" "shl $16,%%edx\n\t" "movb (%%esi),%%dl\n\t" "movl %%edx,(%%edi)\n\t" "addl $2,%%esi\n\t" "addl $4,%%edi\n\t" "decb %%al\n\t" "jne akoop2\n\t" "addl $16,%%esi\n\t" "addl %%ecx,%%edi\n\t" "decb %%bl\n\t" "jne akoop1\n\t" : : "S" (XBuf+srendline*256+VNSCLIP), "D" (ScreenLoc+((240-totallines)/2)*pitch+(640-(VNSWID<<1))/2),"b" (totallines), "c" ((pitch-VNSWID)<<1) : "%al", "%edx", "%cc" ); } else { asm volatile( "xorl %%edx, %%edx\n\t" "koop1:\n\t" "movb $128,%%al \n\t" "koop2:\n\t" "movb 1(%%esi),%%dl\n\t" "shl $16,%%edx\n\t" "movb (%%esi),%%dl\n\t" "movl %%edx,(%%edi)\n\t" "addl $2,%%esi\n\t" "addl $4,%%edi\n\t" "decb %%al\n\t" "jne koop2\n\t" "addl %%ecx,%%edi\n\t" "decb %%bl\n\t" "jne koop1\n\t" : : "S" (XBuf+srendline*256), "D" (ScreenLoc+((240-totallines)/2)*pitch+(640-512)/2),"b" (totallines), "c" (pitch-512+pitch) : "%al", "%edx", "%cc" ); } } else if(vmod==4) { if(eoptions&EO_CLIPSIDES) { asm volatile( "ayoop1:\n\t" "movb $120,%%al \n\t" "ayoop2:\n\t" "movb 1(%%esi),%%dh\n\t" "movb %%dh,%%dl\n\t" "shl $16,%%edx\n\t" "movb (%%esi),%%dl\n\t" "movb %%dl,%%dh\n\t" // Ugh "movl %%edx,(%%edi)\n\t" "addl $2,%%esi\n\t" "addl $4,%%edi\n\t" "decb %%al\n\t" "jne ayoop2\n\t" "addl $16,%%esi\n\t" "addl %%ecx,%%edi\n\t" "decb %%bl\n\t" "jne ayoop1\n\t" : : "S" (XBuf+srendline*256+VNSCLIP), "D" (ScreenLoc+((240-totallines)/2)*pitch+(640-(VNSWID<<1))/2),"b" (totallines), "c" ((pitch-VNSWID)<<1) : "%al", "%edx", "%cc" ); } else { asm volatile( "yoop1:\n\t" "movb $128,%%al \n\t" "yoop2:\n\t" "movb 1(%%esi),%%dh\n\t" "movb %%dh,%%dl\n\t" "shl $16,%%edx\n\t" "movb (%%esi),%%dl\n\t" "movb %%dl,%%dh\n\t" // Ugh "movl %%edx,(%%edi)\n\t" "addl $2,%%esi\n\t" "addl $4,%%edi\n\t" "decb %%al\n\t" "jne yoop2\n\t" "addl %%ecx,%%edi\n\t" "decb %%bl\n\t" "jne yoop1\n\t" : : "S" (XBuf+srendline*256), "D" (ScreenLoc+((240-totallines)/2)*pitch+(640-512)/2),"b" (totallines), "c" (pitch-512+pitch) : "%al", "%edx", "%cc" ); } } else #endif //mbg 6/29/06 merge { if(!(vmodes[vmod].flags&VMDF_DXBLT)) { if(vmodes[vmod].special) ScreenLoc += (vmodes[vmod].drect.left*(bpp>>3)) + ((vmodes[vmod].drect.top)*pitch); else ScreenLoc+=((vmodes[vmod].x-VNSWID)>>1)*(bpp>>3)+(((vmodes[vmod].y-totallines)>>1))*pitch; } if(bpp>=16) { Blit8ToHigh(XBuf+srendline*256+VNSCLIP,(uint8*)ScreenLoc, VNSWID, totallines, pitch,specmul,specmul); //mbg merge 7/17/06 added cast } else { XBuf+=srendline*256+VNSCLIP; if(vmodes[vmod].special) Blit8To8(XBuf,(uint8*)ScreenLoc, VNSWID, totallines, pitch,vmodes[vmod].xscale,vmodes[vmod].yscale,0,vmodes[vmod].special); //mbg merge 7/17/06 added cast else Blit8To8(XBuf,(uint8*)ScreenLoc, VNSWID, totallines, pitch,1,1,0,0); //mbg merge 7/17/06 added cast } } if(vmodes[vmod].flags&VMDF_DXBLT) { IDirectDrawSurface7_Unlock(lpDDSBack, NULL); if(veflags&2) { if(IDirectDrawSurface7_Lock(lpDDSVPrimary,NULL,&ddsd, 0, NULL)==DD_OK) { memset(ddsd.lpSurface,0,ddsd.lPitch*vmodes[vmod].y); //mbg merge 7/17/06 removing dummyunion stuff IDirectDrawSurface7_Unlock(lpDDSVPrimary, NULL); veflags&=~2; } } if(IDirectDrawSurface7_Blt(lpDDSVPrimary, &drect,lpDDSBack,&srect,DDBLT_ASYNC,0)!=DD_OK) { ddrval=IDirectDrawSurface7_Blt(lpDDSVPrimary, &drect,lpDDSBack,&srect,DDBLT_WAIT,0); if(ddrval!=DD_OK) { if(ddrval==DDERR_SURFACELOST) { RestoreDD(0); RestoreDD(1); } return; } } } else IDirectDrawSurface7_Unlock(lpDDSVPrimary, NULL); if(fssync==3) { IDirectDrawSurface7_Flip(lpDDSPrimary,0,0); } } void ResetVideo(void) { ShowCursorAbs(1); KillBlitToHigh(); if(lpDD7) if(mustrestore) {IDirectDraw7_RestoreDisplayMode(lpDD7);mustrestore=0;} if(lpddpal) {IDirectDrawPalette_Release(lpddpal); lpddpal = 0;} if(lpDDSBack) {IDirectDrawSurface7_Release(lpDDSBack);lpDDSBack=0;} if(lpDDSPrimary) {IDirectDrawSurface7_Release(lpDDSPrimary);lpDDSPrimary=0;} if(lpClipper) {IDirectDrawClipper_Release(lpClipper);lpClipper=0;} if(lpDD7) { IDirectDraw_Release(lpDD7); lpDD7 = NULL; } } int specialmlut[5] = {1,2,2,3,3}; static int RecalcCustom(void) { vmdef *cmode = &vmodes[0]; cmode->flags&=~VMDF_DXBLT; if(cmode->flags&VMDF_STRFS) { cmode->flags|=VMDF_DXBLT; } else if(cmode->xscale!=1 || cmode->yscale!=1 || cmode->special) { if(cmode->special) { int mult = specialmlut[cmode->special]; if(cmode->xscale < mult) cmode->xscale = mult; if(cmode->yscale < mult) cmode->yscale = mult; if(cmode->xscale != mult || cmode->yscale != mult) cmode->flags|=VMDF_DXBLT; } else cmode->flags|=VMDF_DXBLT; if(VNSWID*cmode->xscale>cmode->x) { if(cmode->special) { FCEUD_PrintError("Scaled width is out of range."); return(0); } else { FCEUD_PrintError("Scaled width is out of range. Reverting to no horizontal scaling."); cmode->xscale=1; } } if(totallines*cmode->yscale>cmode->y) { if(cmode->special) { FCEUD_PrintError("Scaled height is out of range."); return(0); } else { FCEUD_PrintError("Scaled height is out of range. Reverting to no vertical scaling."); cmode->yscale=1; } } cmode->srect.left=VNSCLIP; cmode->srect.top=srendline; cmode->srect.right=256-VNSCLIP; cmode->srect.bottom=erendline+1; cmode->drect.top=(cmode->y-(totallines*cmode->yscale))>>1; cmode->drect.bottom=cmode->drect.top+totallines*cmode->yscale; cmode->drect.left=(cmode->x-(VNSWID*cmode->xscale))>>1; cmode->drect.right=cmode->drect.left+VNSWID*cmode->xscale; } if((cmode->special == 1 || cmode->special == 3) && cmode->bpp == 8) { cmode->bpp = 32; //FCEUD_PrintError("HQ2x/HQ3x requires 16bpp or 32bpp(best)."); //return(0); } if(cmode->xyflags&VMDF_STRFS)) { FCEUD_PrintError("Vertical resolution must not be less than the total number of drawn scanlines."); return(0); } return(1); } BOOL SetDlgItemDouble(HWND hDlg, int item, double value) { char buf[8]; sprintf(buf,"%.6f",value); return SetDlgItemText(hDlg, item, buf); //mbg merge 7/17/06 added this return value } double GetDlgItemDouble(HWND hDlg, int item) { char buf[8]; double ret = 0; GetDlgItemText(hDlg, item, buf, 8); sscanf(buf,"%lf",&ret); return(ret); } BOOL CALLBACK VideoConCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { static char *vmstr[11]={ "Custom", "320x240 Full Screen", "512x384 Centered", "640x480 Centered", "640x480 Scanlines", "640x480 \"4 per 1\"", "640x480 2x,2y", "1024x768 4x,3y", "1280x1024 5x,4y", "1600x1200 6x,5y", "800x600 Stretched" }; int x; switch(uMsg) { case WM_INITDIALOG: SetDlgItemText(hwndDlg,65454,"For the custom video mode settings to be in effect, the \"Custom\" video mode needs to be selected. If you select a sync method, and sound is disabled, you may want to disable speed throttling(in the \"Timing\" window). If you use \"wait for vblank\", you should use the \"lazy\" form.\x0AAllowing more than 8 sprites per scanline can cause graphics corruption in some games, including \"Solstice\"."); for(x=0;x<11;x++) SendDlgItemMessage(hwndDlg,100,CB_ADDSTRING,0,(LPARAM)(LPSTR)vmstr[x]); SendDlgItemMessage(hwndDlg,100,CB_SETCURSEL,vmod,(LPARAM)(LPSTR)0); SendDlgItemMessage(hwndDlg,202,CB_ADDSTRING,0,(LPARAM)(LPSTR)"8"); SendDlgItemMessage(hwndDlg,202,CB_ADDSTRING,0,(LPARAM)(LPSTR)"16"); SendDlgItemMessage(hwndDlg,202,CB_ADDSTRING,0,(LPARAM)(LPSTR)"24"); SendDlgItemMessage(hwndDlg,202,CB_ADDSTRING,0,(LPARAM)(LPSTR)"32"); SendDlgItemMessage(hwndDlg,202,CB_SETCURSEL,(vmodes[0].bpp>>3)-1,(LPARAM)(LPSTR)0); SetDlgItemInt(hwndDlg,200,vmodes[0].x,0); SetDlgItemInt(hwndDlg,201,vmodes[0].y,0); SetDlgItemInt(hwndDlg,302,vmodes[0].xscale,0); SetDlgItemInt(hwndDlg,303,vmodes[0].yscale,0); CheckRadioButton(hwndDlg,300,301,(vmodes[0].flags&VMDF_STRFS)?301:300); { char *str[]={"","hq2x","Scale2x","hq3x","Scale3x"}; int x; for(x=0;x<5;x++) { SendDlgItemMessage(hwndDlg,304,CB_ADDSTRING,0,(LPARAM)(LPSTR)str[x]); SendDlgItemMessage(hwndDlg,406,CB_ADDSTRING,0,(LPARAM)(LPSTR)str[x]); } } SendDlgItemMessage(hwndDlg,304,CB_SETCURSEL,vmodes[0].special,(LPARAM)(LPSTR)0); SendDlgItemMessage(hwndDlg,406,CB_SETCURSEL,winspecial,(LPARAM)(LPSTR)0); if(eoptions&EO_FSAFTERLOAD) CheckDlgButton(hwndDlg,102,BST_CHECKED); if(eoptions&EO_CLIPSIDES) CheckDlgButton(hwndDlg,106,BST_CHECKED); if(disvaccel&1) CheckDlgButton(hwndDlg,130,BST_CHECKED); if(disvaccel&2) CheckDlgButton(hwndDlg,131,BST_CHECKED); if(eoptions&EO_FORCEISCALE) CheckDlgButton(hwndDlg,402,BST_CHECKED); if(eoptions&EO_FORCEASPECT) CheckDlgButton(hwndDlg,403,BST_CHECKED); SetDlgItemInt(hwndDlg,500,srendlinen,0); SetDlgItemInt(hwndDlg,501,erendlinen,0); SetDlgItemInt(hwndDlg,502,srendlinep,0); SetDlgItemInt(hwndDlg,503,erendlinep,0); SetDlgItemDouble(hwndDlg, 400, winsizemulx); SetDlgItemDouble(hwndDlg, 401, winsizemuly); SetDlgItemDouble(hwndDlg, 404, saspectw); SetDlgItemDouble(hwndDlg, 405, saspecth); //SetDlgI temInt(hwndDlg,103,winsizemul,0); SendDlgItemMessage(hwndDlg,104,CB_ADDSTRING,0,(LPARAM)(LPSTR)""); SendDlgItemMessage(hwndDlg,105,CB_ADDSTRING,0,(LPARAM)(LPSTR)""); SendDlgItemMessage(hwndDlg,104,CB_ADDSTRING,0,(LPARAM)(LPSTR)"Wait for VBlank"); SendDlgItemMessage(hwndDlg,104,CB_ADDSTRING,0,(LPARAM)(LPSTR)"Lazy wait for VBlank"); SendDlgItemMessage(hwndDlg,105,CB_ADDSTRING,0,(LPARAM)(LPSTR)"Wait for VBlank"); SendDlgItemMessage(hwndDlg,105,CB_ADDSTRING,0,(LPARAM)(LPSTR)"Lazy wait for VBlank"); SendDlgItemMessage(hwndDlg,105,CB_ADDSTRING,0,(LPARAM)(LPSTR)"Double Buffering"); SendDlgItemMessage(hwndDlg,104,CB_SETCURSEL,winsync,(LPARAM)(LPSTR)0); SendDlgItemMessage(hwndDlg,105,CB_SETCURSEL,fssync,(LPARAM)(LPSTR)0); if(eoptions&EO_NOSPRLIM) CheckDlgButton(hwndDlg,600,BST_CHECKED); break; case WM_CLOSE: case WM_QUIT: goto gornk; case WM_COMMAND: if(!(wParam>>16)) switch(wParam&0xFFFF) { case 1: gornk: if(IsDlgButtonChecked(hwndDlg,106)==BST_CHECKED) eoptions|=EO_CLIPSIDES; else eoptions&=~EO_CLIPSIDES; if(IsDlgButtonChecked(hwndDlg,600)==BST_CHECKED) eoptions|=EO_NOSPRLIM; else eoptions&=~EO_NOSPRLIM; srendlinen=GetDlgItemInt(hwndDlg,500,0,0); erendlinen=GetDlgItemInt(hwndDlg,501,0,0); srendlinep=GetDlgItemInt(hwndDlg,502,0,0); erendlinep=GetDlgItemInt(hwndDlg,503,0,0); if(erendlinen>239) erendlinen=239; if(srendlinen>erendlinen) srendlinen=erendlinen; if(erendlinep>239) erendlinep=239; if(srendlinep>erendlinen) srendlinep=erendlinep; UpdateRendBounds(); if(IsDlgButtonChecked(hwndDlg,301)==BST_CHECKED) vmodes[0].flags|=VMDF_STRFS; else vmodes[0].flags&=~VMDF_STRFS; vmod=SendDlgItemMessage(hwndDlg,100,CB_GETCURSEL,0,(LPARAM)(LPSTR)0); vmodes[0].x=GetDlgItemInt(hwndDlg,200,0,0); vmodes[0].y=GetDlgItemInt(hwndDlg,201,0,0); vmodes[0].bpp=(SendDlgItemMessage(hwndDlg,202,CB_GETCURSEL,0,(LPARAM)(LPSTR)0)+1)<<3; vmodes[0].xscale=GetDlgItemInt(hwndDlg,302,0,0); vmodes[0].yscale=GetDlgItemInt(hwndDlg,303,0,0); vmodes[0].special=SendDlgItemMessage(hwndDlg,304,CB_GETCURSEL,0,(LPARAM)(LPSTR)0); winspecial = SendDlgItemMessage(hwndDlg,406,CB_GETCURSEL,0,(LPARAM)(LPSTR)0); disvaccel = 0; if(IsDlgButtonChecked(hwndDlg,130)==BST_CHECKED) disvaccel |= 1; if(IsDlgButtonChecked(hwndDlg,131)==BST_CHECKED) disvaccel |= 2; if(IsDlgButtonChecked(hwndDlg,101)==BST_CHECKED) fullscreen=1; else fullscreen=0; if(IsDlgButtonChecked(hwndDlg,102)==BST_CHECKED) eoptions|=EO_FSAFTERLOAD; else eoptions&=~EO_FSAFTERLOAD; eoptions &= ~(EO_FORCEISCALE | EO_FORCEASPECT); if(IsDlgButtonChecked(hwndDlg,402)==BST_CHECKED) eoptions|=EO_FORCEISCALE; if(IsDlgButtonChecked(hwndDlg,403)==BST_CHECKED) eoptions|=EO_FORCEASPECT; winsizemulx=GetDlgItemDouble(hwndDlg, 400); winsizemuly=GetDlgItemDouble(hwndDlg, 401); saspectw=GetDlgItemDouble(hwndDlg, 404); saspecth=GetDlgItemDouble(hwndDlg, 405); FixWXY(0); winsync=SendDlgItemMessage(hwndDlg,104,CB_GETCURSEL,0,(LPARAM)(LPSTR)0); fssync=SendDlgItemMessage(hwndDlg,105,CB_GETCURSEL,0,(LPARAM)(LPSTR)0); EndDialog(hwndDlg,0); break; } } return 0; } static void SetFSVideoMode(void) { changerecursive=1; if(!SetVideoMode(1)) SetVideoMode(0); changerecursive=0; } void DoVideoConfigFix(void) { FCEUI_DisableSpriteLimitation(eoptions&EO_NOSPRLIM); UpdateRendBounds(); } void ConfigVideo(void) { DialogBox(fceu_hInstance,"VIDEOCONFIG",hAppWnd,VideoConCallB); DoVideoConfigFix(); if(fullscreen) SetFSVideoMode(); else { changerecursive=1; SetVideoMode(0); changerecursive=0; } //SetMainWindowStuff(); }