fceux/drivers/win/video.cpp

1134 lines
33 KiB
C++

/* 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->x<VNSWID)
{
FCEUD_PrintError("Horizontal resolution is too low.");
return(0);
}
if(cmode->y<totallines && !(cmode->flags&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[9]; //mbg merge 7/19/06 changed to 9 to leave room for \0
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[]={"<none>","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)"<none>");
SendDlgItemMessage(hwndDlg,105,CB_ADDSTRING,0,(LPARAM)(LPSTR)"<none>");
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();
}