2018-11-15 23:31:39 +00:00
|
|
|
/*****************************************************************************\
|
|
|
|
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
|
|
|
|
This file is licensed under the Snes9x License.
|
|
|
|
For further information, consult the LICENSE file in the root directory.
|
|
|
|
\*****************************************************************************/
|
2010-09-25 15:46:12 +00:00
|
|
|
|
2017-04-17 11:45:43 +00:00
|
|
|
#if DIRECTDRAW_SUPPORT
|
2018-06-24 11:12:59 +00:00
|
|
|
|
|
|
|
#ifdef _WIN64
|
|
|
|
#pragma comment( lib, "ddraw/ddraw_x64" )
|
|
|
|
#else
|
|
|
|
#pragma comment( lib, "ddraw/ddraw_x86" )
|
|
|
|
#endif
|
2010-09-25 15:46:12 +00:00
|
|
|
|
|
|
|
// CDirectDraw.cpp: implementation of the CDirectDraw class.
|
|
|
|
//
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
#include "wsnes9x.h"
|
|
|
|
#include "../snes9x.h"
|
|
|
|
#include "../gfx.h"
|
|
|
|
#include "CDirectDraw.h"
|
|
|
|
#include "win32_display.h"
|
|
|
|
|
|
|
|
#include "../filter/hq2x.h"
|
|
|
|
#include "../filter/2xsai.h"
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Construction/Destruction
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
CDirectDraw::CDirectDraw()
|
|
|
|
{
|
|
|
|
lpDD = NULL;
|
|
|
|
lpDDClipper = NULL;
|
|
|
|
lpDDPalette = NULL;
|
|
|
|
|
|
|
|
lpDDSPrimary2 = NULL;
|
|
|
|
lpDDSOffScreen2 = NULL;
|
|
|
|
|
|
|
|
width = height = -1;
|
|
|
|
depth = -1;
|
|
|
|
doubleBuffered = false;
|
|
|
|
dDinitialized = false;
|
2010-09-25 17:35:19 +00:00
|
|
|
convertBuffer = NULL;
|
|
|
|
filterScale = 0;
|
2010-09-25 15:46:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CDirectDraw::~CDirectDraw()
|
|
|
|
{
|
|
|
|
DeInitialize();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CDirectDraw::Initialize (HWND hWnd)
|
|
|
|
{
|
|
|
|
if(dDinitialized)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
dErr = DirectDrawCreate (NULL, &lpDD, NULL);
|
|
|
|
if(FAILED(dErr))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
dErr = lpDD -> CreateClipper (0, &lpDDClipper, NULL);
|
|
|
|
if(FAILED(dErr))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
dErr = lpDDClipper->SetHWnd (0, hWnd);
|
|
|
|
if(FAILED(dErr))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!SetDisplayMode (GUI.FullscreenMode.width, GUI.FullscreenMode.height, max(GetFilterScale(GUI.Scale), GetFilterScale(GUI.ScaleHiRes)), GUI.FullscreenMode.depth, GUI.FullscreenMode.rate,
|
|
|
|
TRUE, GUI.DoubleBuffered))
|
|
|
|
{
|
2019-02-18 21:15:28 +00:00
|
|
|
MessageBox( GUI.hWnd, Languages[ GUI.Language].errModeDD, TEXT("Snes9x - DirectDraw(7)"), MB_OK | MB_ICONSTOP);
|
2010-09-25 15:46:12 +00:00
|
|
|
return (false);
|
|
|
|
}
|
|
|
|
|
|
|
|
dDinitialized = true;
|
|
|
|
|
|
|
|
return (true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CDirectDraw::DeInitialize()
|
|
|
|
{
|
|
|
|
if (lpDD != NULL)
|
|
|
|
{
|
|
|
|
if (lpDDSPrimary2 != NULL)
|
|
|
|
{
|
|
|
|
lpDDSPrimary2->Release();
|
|
|
|
lpDDSPrimary2 = NULL;
|
|
|
|
}
|
|
|
|
if (lpDDSOffScreen2 != NULL)
|
|
|
|
{
|
|
|
|
lpDDSOffScreen2->PageUnlock(0);
|
|
|
|
lpDDSOffScreen2->Release();
|
|
|
|
lpDDSOffScreen2 = NULL;
|
|
|
|
}
|
|
|
|
if (lpDDClipper != NULL)
|
|
|
|
{
|
|
|
|
lpDDClipper->Release();
|
|
|
|
lpDDClipper = NULL;
|
|
|
|
}
|
|
|
|
if (lpDDPalette != NULL)
|
|
|
|
{
|
|
|
|
lpDDPalette->Release();
|
|
|
|
lpDDPalette = NULL;
|
|
|
|
}
|
|
|
|
lpDD->Release();
|
|
|
|
lpDD = NULL;
|
|
|
|
}
|
2010-09-25 17:35:19 +00:00
|
|
|
if(convertBuffer) {
|
|
|
|
delete [] convertBuffer;
|
|
|
|
convertBuffer = NULL;
|
|
|
|
}
|
|
|
|
filterScale = 0;
|
2010-09-25 15:46:12 +00:00
|
|
|
dDinitialized = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CDirectDraw::SetDisplayMode(
|
|
|
|
int pWidth, int pHeight, int pScale,
|
|
|
|
char pDepth, int pRefreshRate, bool pWindowed, bool pDoubleBuffered)
|
|
|
|
{
|
|
|
|
if(pScale < 2) pScale = 2;
|
|
|
|
|
|
|
|
static bool BLOCK = false;
|
|
|
|
DDSURFACEDESC ddsd;
|
|
|
|
PALETTEENTRY PaletteEntries [256];
|
|
|
|
|
|
|
|
if (BLOCK)
|
|
|
|
return (false);
|
|
|
|
|
|
|
|
BLOCK = true;
|
|
|
|
|
|
|
|
if (pWindowed)
|
|
|
|
pDoubleBuffered = false;
|
|
|
|
|
|
|
|
if (pDepth == 0)
|
|
|
|
pDepth = depth;
|
|
|
|
|
|
|
|
if (lpDDSPrimary2 != NULL)
|
|
|
|
{
|
|
|
|
lpDDSPrimary2->Release();
|
|
|
|
lpDDSPrimary2 = NULL;
|
|
|
|
}
|
|
|
|
if (lpDDSOffScreen2 != NULL)
|
|
|
|
{
|
|
|
|
lpDDSOffScreen2->PageUnlock(0);
|
|
|
|
lpDDSOffScreen2->Release();
|
|
|
|
lpDDSOffScreen2 = NULL;
|
|
|
|
}
|
|
|
|
if( lpDDPalette != NULL)
|
|
|
|
{
|
|
|
|
lpDDPalette->Release();
|
|
|
|
lpDDPalette = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
lpDD->FlipToGDISurface();
|
|
|
|
|
|
|
|
if (pWindowed)
|
|
|
|
{
|
|
|
|
lpDD->RestoreDisplayMode();
|
|
|
|
|
|
|
|
ZeroMemory (&ddsd, sizeof (ddsd));
|
|
|
|
|
|
|
|
ddsd.dwSize = sizeof (ddsd);
|
|
|
|
ddsd.dwFlags = DDSD_PIXELFORMAT;
|
|
|
|
dErr = lpDD->GetDisplayMode (&ddsd);
|
|
|
|
if (FAILED(dErr))
|
|
|
|
pDepth = 8;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (ddsd.ddpfPixelFormat.dwFlags&DDPF_RGB)
|
|
|
|
pDepth = (char) ddsd.ddpfPixelFormat.dwRGBBitCount;
|
|
|
|
else
|
|
|
|
pDepth = 8;
|
|
|
|
}
|
|
|
|
if (pDepth == 8)
|
|
|
|
dErr = lpDD->SetCooperativeLevel (GUI.hWnd, DDSCL_FULLSCREEN|
|
|
|
|
DDSCL_EXCLUSIVE|DDSCL_ALLOWREBOOT);
|
|
|
|
else
|
|
|
|
dErr = lpDD->SetCooperativeLevel (GUI.hWnd, DDSCL_NORMAL|DDSCL_ALLOWREBOOT);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dErr = lpDD->SetCooperativeLevel (GUI.hWnd, DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN|DDSCL_ALLOWREBOOT);
|
|
|
|
// XXX: TODO: use pRefreshRate!
|
|
|
|
dErr = lpDD->SetDisplayMode (pWidth, pHeight, pDepth);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (FAILED(dErr))
|
|
|
|
{
|
|
|
|
BLOCK = false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
ZeroMemory (&ddsd, sizeof (ddsd));
|
|
|
|
ddsd.dwSize = sizeof (ddsd);
|
|
|
|
ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
|
2018-05-20 16:01:03 +00:00
|
|
|
if(Settings.BilinearFilter)
|
2010-09-25 15:46:12 +00:00
|
|
|
{
|
|
|
|
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY | (GUI.LocalVidMem ? DDSCAPS_LOCALVIDMEM : DDSCAPS_NONLOCALVIDMEM);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
|
|
|
|
}
|
|
|
|
ddsd.dwWidth = SNES_WIDTH * pScale;
|
|
|
|
ddsd.dwHeight = SNES_HEIGHT_EXTENDED * pScale;
|
|
|
|
|
|
|
|
LPDIRECTDRAWSURFACE lpDDSOffScreen;
|
|
|
|
if (FAILED(lpDD->CreateSurface (&ddsd, &lpDDSOffScreen, NULL)))
|
|
|
|
{
|
|
|
|
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY | (GUI.LocalVidMem ? DDSCAPS_NONLOCALVIDMEM : DDSCAPS_LOCALVIDMEM);
|
2018-05-20 16:01:03 +00:00
|
|
|
if(!Settings.BilinearFilter || FAILED(lpDD->CreateSurface (&ddsd, &lpDDSOffScreen, NULL)))
|
2010-09-25 15:46:12 +00:00
|
|
|
{
|
|
|
|
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
|
2018-05-20 16:01:03 +00:00
|
|
|
if(!Settings.BilinearFilter || FAILED(lpDD->CreateSurface (&ddsd, &lpDDSOffScreen, NULL)))
|
2010-09-25 15:46:12 +00:00
|
|
|
{
|
|
|
|
BLOCK = false;
|
|
|
|
return (false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (FAILED (lpDDSOffScreen->QueryInterface (IID_IDirectDrawSurface2,
|
|
|
|
(void **)&lpDDSOffScreen2)))
|
|
|
|
{
|
|
|
|
lpDDSOffScreen->Release();
|
|
|
|
BLOCK = false;
|
|
|
|
return (false);
|
|
|
|
}
|
|
|
|
lpDDSOffScreen2->PageLock(0);
|
|
|
|
lpDDSOffScreen->Release();
|
|
|
|
|
|
|
|
ZeroMemory (&ddsd, sizeof (ddsd));
|
|
|
|
if (pDoubleBuffered)
|
|
|
|
{
|
|
|
|
ddsd.dwSize = sizeof( ddsd);
|
|
|
|
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
|
|
|
|
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;
|
|
|
|
GUI.NumFlipFrames = 3;
|
|
|
|
ddsd.dwBackBufferCount = 2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
GUI.NumFlipFrames = 1;
|
|
|
|
ddsd.dwSize = sizeof (ddsd);
|
|
|
|
ddsd.dwFlags = DDSD_CAPS;
|
|
|
|
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
|
|
|
|
}
|
|
|
|
|
|
|
|
LPDIRECTDRAWSURFACE lpDDSPrimary;
|
|
|
|
|
|
|
|
dErr = lpDD->CreateSurface (&ddsd, &lpDDSPrimary, NULL);
|
|
|
|
if( FAILED(dErr) )
|
|
|
|
{
|
|
|
|
if (pDoubleBuffered)
|
|
|
|
{
|
|
|
|
ddsd.dwBackBufferCount = 1;
|
|
|
|
GUI.NumFlipFrames = 2;
|
|
|
|
if (FAILED(dErr = lpDD->CreateSurface (&ddsd, &lpDDSPrimary, NULL)))
|
|
|
|
{
|
|
|
|
ddsd.dwFlags = DDSD_CAPS;
|
|
|
|
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
|
|
|
|
|
|
|
|
pDoubleBuffered = false;
|
|
|
|
GUI.NumFlipFrames = 1;
|
|
|
|
dErr = lpDD->CreateSurface (&ddsd, &lpDDSPrimary, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (FAILED(dErr))
|
|
|
|
{
|
|
|
|
BLOCK = false;
|
|
|
|
lpDDSOffScreen2->PageUnlock(0);
|
|
|
|
lpDDSOffScreen2->Release();
|
|
|
|
lpDDSOffScreen2 = NULL;
|
|
|
|
|
|
|
|
return (false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ZeroMemory (&DDPixelFormat, sizeof (DDPixelFormat));
|
|
|
|
DDPixelFormat.dwSize = sizeof (DDPixelFormat);
|
|
|
|
lpDDSPrimary->GetPixelFormat (&DDPixelFormat);
|
|
|
|
|
|
|
|
clipped = true;
|
|
|
|
if((!pWindowed && pDoubleBuffered) || FAILED(lpDDSPrimary->SetClipper( lpDDClipper)))
|
|
|
|
clipped = false;
|
|
|
|
|
|
|
|
if (FAILED (lpDDSPrimary->QueryInterface (IID_IDirectDrawSurface2, (void **)&lpDDSPrimary2)))
|
|
|
|
{
|
|
|
|
BLOCK = false;
|
|
|
|
lpDDSPrimary->Release();
|
|
|
|
lpDDSPrimary = NULL;
|
|
|
|
|
|
|
|
return (FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
lpDDSPrimary->Release();
|
|
|
|
lpDDSPrimary = NULL;
|
|
|
|
|
|
|
|
if((!pWindowed && pDoubleBuffered) || FAILED(lpDDSPrimary2->SetClipper( lpDDClipper)))
|
|
|
|
clipped = false;
|
|
|
|
|
|
|
|
if (pDepth == 8)
|
|
|
|
{
|
|
|
|
dErr = lpDD->CreatePalette (DDPCAPS_8BIT | DDPCAPS_ALLOW256,
|
|
|
|
PaletteEntries, &lpDDPalette, NULL);
|
|
|
|
if( FAILED(dErr))
|
|
|
|
{
|
|
|
|
lpDDPalette = NULL;
|
|
|
|
BLOCK = false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
depth = pDepth;
|
|
|
|
height = pHeight;
|
|
|
|
width = pWidth;
|
|
|
|
doubleBuffered = pDoubleBuffered;
|
|
|
|
BLOCK = false;
|
|
|
|
|
|
|
|
return (true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CDirectDraw::GetPixelFormat ()
|
|
|
|
{
|
|
|
|
if (lpDDSPrimary2)
|
|
|
|
{
|
|
|
|
ZeroMemory (&DDPixelFormat, sizeof (DDPixelFormat));
|
|
|
|
DDPixelFormat.dwSize = sizeof (DDPixelFormat);
|
|
|
|
lpDDSPrimary2->GetPixelFormat (&DDPixelFormat);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool LockSurface2 (LPDIRECTDRAWSURFACE2 lpDDSurface, SSurface *lpSurface)
|
|
|
|
{
|
|
|
|
DDSURFACEDESC ddsd;
|
|
|
|
HRESULT hResult;
|
|
|
|
int retry;
|
|
|
|
|
|
|
|
ddsd.dwSize = sizeof (ddsd);
|
|
|
|
|
|
|
|
retry = 0;
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
hResult = lpDDSurface->Lock( NULL, &ddsd, DDLOCK_WAIT, NULL);
|
|
|
|
|
|
|
|
if( hResult == DD_OK)
|
|
|
|
{
|
|
|
|
lpSurface->Width = ddsd.dwWidth;
|
|
|
|
lpSurface->Height = ddsd.dwHeight;
|
|
|
|
lpSurface->Pitch = ddsd.lPitch;
|
|
|
|
lpSurface->Surface = (unsigned char *)ddsd.lpSurface;
|
|
|
|
return (true);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hResult == DDERR_SURFACELOST)
|
|
|
|
{
|
|
|
|
retry++;
|
|
|
|
if (retry > 5)
|
|
|
|
return (false);
|
|
|
|
|
|
|
|
hResult = lpDDSurface->Restore();
|
|
|
|
if (hResult != DD_OK)
|
|
|
|
return (false);
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hResult != DDERR_WASSTILLDRAWING)
|
|
|
|
return (false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CDirectDraw::Render(SSurface Src)
|
|
|
|
{
|
|
|
|
LPDIRECTDRAWSURFACE2 lpDDSurface2 = NULL;
|
|
|
|
LPDIRECTDRAWSURFACE2 pDDSurface = NULL;
|
|
|
|
SSurface Dst;
|
|
|
|
RECT srcRect;
|
|
|
|
|
|
|
|
RECT dstRect = { 0, 512, 0, 448 };
|
|
|
|
|
|
|
|
DDSCAPS caps;
|
|
|
|
|
2010-09-25 17:35:19 +00:00
|
|
|
unsigned int newFilterScale;
|
|
|
|
|
2010-10-04 15:30:03 +00:00
|
|
|
if(!dDinitialized) return;
|
|
|
|
|
2012-01-23 17:12:47 +00:00
|
|
|
memset(&caps, 0,sizeof(DDSCAPS));
|
2010-09-25 15:46:12 +00:00
|
|
|
caps.dwCaps = DDSCAPS_BACKBUFFER;
|
|
|
|
|
|
|
|
if (lpDDSPrimary2->GetAttachedSurface (&caps, &pDDSurface) != DD_OK ||
|
|
|
|
pDDSurface == NULL)
|
|
|
|
{
|
|
|
|
lpDDSurface2 = lpDDSPrimary2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
lpDDSurface2 = pDDSurface;
|
|
|
|
|
|
|
|
lpDDSurface2 = lpDDSOffScreen2;
|
|
|
|
if (!LockSurface2 (lpDDSurface2, &Dst))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!GUI.DepthConverted)
|
|
|
|
{
|
|
|
|
SSurface tmp;
|
2010-09-25 17:35:19 +00:00
|
|
|
|
|
|
|
newFilterScale = max(2,max(GetFilterScale(GUI.ScaleHiRes),GetFilterScale(GUI.Scale)));
|
|
|
|
|
|
|
|
if(newFilterScale!=filterScale) {
|
|
|
|
if(convertBuffer)
|
|
|
|
delete [] convertBuffer;
|
|
|
|
filterScale = newFilterScale;
|
|
|
|
convertBuffer = new unsigned char[SNES_WIDTH * sizeof(uint16) * SNES_HEIGHT_EXTENDED * sizeof(uint16) *filterScale*filterScale]();
|
|
|
|
}
|
2010-09-25 15:46:12 +00:00
|
|
|
|
2010-09-25 17:35:19 +00:00
|
|
|
tmp.Surface = convertBuffer;
|
2010-09-25 15:46:12 +00:00
|
|
|
|
2010-09-25 15:52:32 +00:00
|
|
|
if(CurrentScale == FILTER_NONE) {
|
2010-09-25 15:46:12 +00:00
|
|
|
tmp.Pitch = Src.Pitch;
|
|
|
|
tmp.Width = Src.Width;
|
|
|
|
tmp.Height = Src.Height;
|
|
|
|
} else {
|
|
|
|
tmp.Pitch = Dst.Pitch;
|
|
|
|
tmp.Width = Dst.Width;
|
|
|
|
tmp.Height = Dst.Height;
|
|
|
|
}
|
|
|
|
RenderMethod (Src, tmp, &srcRect);
|
|
|
|
ConvertDepth (&tmp, &Dst, &srcRect);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
RenderMethod (Src, Dst, &srcRect);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!Settings.AutoDisplayMessages) {
|
2010-09-25 15:52:32 +00:00
|
|
|
WinSetCustomDisplaySurface((void *)Dst.Surface, (Dst.Pitch*8/GUI.ScreenDepth), srcRect.right-srcRect.left, srcRect.bottom-srcRect.top, GetFilterScale(CurrentScale));
|
|
|
|
S9xDisplayMessages ((uint16*)Dst.Surface, Dst.Pitch/2, srcRect.right-srcRect.left, srcRect.bottom-srcRect.top, GetFilterScale(CurrentScale));
|
2010-09-25 15:46:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
RECT lastRect = SizeHistory [GUI.FlipCounter % GUI.NumFlipFrames];
|
|
|
|
POINT p;
|
|
|
|
|
|
|
|
if (GUI.Stretch)
|
|
|
|
{
|
|
|
|
p.x = p.y = 0;
|
|
|
|
ClientToScreen (GUI.hWnd, &p);
|
|
|
|
GetClientRect (GUI.hWnd, &dstRect);
|
|
|
|
// dstRect.bottom = int(double(dstRect.bottom) * double(239.0 / 240.0));
|
|
|
|
|
|
|
|
if(GUI.AspectRatio)
|
|
|
|
{
|
|
|
|
int width = dstRect.right - dstRect.left;
|
|
|
|
int height = dstRect.bottom - dstRect.top;
|
|
|
|
|
|
|
|
int oldWidth = GUI.AspectWidth;
|
|
|
|
int oldHeight = GUI.HeightExtend ? SNES_HEIGHT_EXTENDED : SNES_HEIGHT;
|
|
|
|
int newWidth, newHeight;
|
|
|
|
|
|
|
|
if(oldWidth * height > oldHeight * width)
|
|
|
|
{
|
|
|
|
newWidth = width;
|
|
|
|
newHeight = oldHeight*width/oldWidth;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
newWidth = oldWidth*height/oldHeight;
|
|
|
|
newHeight = height;
|
|
|
|
}
|
|
|
|
int xOffset = (width - newWidth)/2;
|
|
|
|
int yOffset = (height - newHeight)/2;
|
|
|
|
|
|
|
|
dstRect.right = dstRect.left + newWidth;
|
|
|
|
dstRect.bottom = dstRect.top + newHeight;
|
|
|
|
|
|
|
|
OffsetRect(&dstRect, p.x + xOffset, p.y + yOffset);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
OffsetRect(&dstRect, p.x, p.y);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
GetClientRect (GUI.hWnd, &dstRect);
|
|
|
|
int width = srcRect.right - srcRect.left;
|
|
|
|
int height = srcRect.bottom - srcRect.top;
|
|
|
|
|
|
|
|
//if (GUI.Scale == 1)
|
|
|
|
//{
|
|
|
|
// width = MAX_SNES_WIDTH;
|
|
|
|
// if (height < 240)
|
|
|
|
// height *= 2;
|
|
|
|
//}
|
|
|
|
p.x = ((dstRect.right - dstRect.left) - width) >> 1;
|
|
|
|
p.y = ((dstRect.bottom - dstRect.top) - height) >> 1;
|
|
|
|
|
|
|
|
if(p.y < 0) p.y = 0;
|
|
|
|
if(p.x < 0) p.x = 0;
|
|
|
|
|
|
|
|
ClientToScreen (GUI.hWnd, &p);
|
|
|
|
|
|
|
|
dstRect.top = p.y;
|
|
|
|
dstRect.left = p.x;
|
|
|
|
dstRect.bottom = dstRect.top + height;
|
|
|
|
dstRect.right = dstRect.left + width;
|
|
|
|
}
|
|
|
|
|
|
|
|
lpDDSurface2->Unlock (Dst.Surface);
|
|
|
|
|
2012-01-23 17:12:47 +00:00
|
|
|
memset(&caps, 0,sizeof(DDSCAPS));
|
2010-09-25 15:46:12 +00:00
|
|
|
caps.dwCaps = DDSCAPS_BACKBUFFER;
|
|
|
|
|
|
|
|
if (lpDDSPrimary2->GetAttachedSurface (&caps, &pDDSurface) != DD_OK ||
|
|
|
|
pDDSurface == NULL)
|
|
|
|
{
|
|
|
|
lpDDSurface2 = lpDDSPrimary2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
lpDDSurface2 = pDDSurface;
|
|
|
|
|
|
|
|
// actually draw it onto the screen (unless in fullscreen mode; see UpdateBackBuffer() for that)
|
|
|
|
while (lpDDSurface2->Blt (&dstRect, lpDDSOffScreen2, &srcRect, DDBLT_WAIT, NULL) == DDERR_SURFACELOST)
|
|
|
|
lpDDSurface2->Restore ();
|
|
|
|
|
|
|
|
|
|
|
|
RECT rect;
|
|
|
|
DDBLTFX fx;
|
|
|
|
|
|
|
|
memset (&fx, 0, sizeof (fx));
|
|
|
|
fx.dwSize = sizeof (fx);
|
|
|
|
|
|
|
|
if (GUI.FlipCounter >= GUI.NumFlipFrames)
|
|
|
|
{
|
|
|
|
if (lastRect.top < dstRect.top)
|
|
|
|
{
|
|
|
|
rect.top = lastRect.top;
|
|
|
|
rect.bottom = dstRect.top;
|
|
|
|
rect.left = min(lastRect.left, dstRect.left);
|
|
|
|
rect.right = max(lastRect.right, dstRect.right);
|
|
|
|
lpDDSurface2->Blt (&rect, NULL, &rect,
|
|
|
|
DDBLT_WAIT | DDBLT_COLORFILL, &fx);
|
|
|
|
}
|
|
|
|
if (lastRect.bottom > dstRect.bottom)
|
|
|
|
{
|
|
|
|
rect.left = min(lastRect.left, dstRect.left);
|
|
|
|
rect.right = max(lastRect.right, dstRect.right);
|
|
|
|
rect.top = dstRect.bottom;
|
|
|
|
rect.bottom = lastRect.bottom;
|
|
|
|
lpDDSurface2->Blt (&rect, NULL, &rect,
|
|
|
|
DDBLT_WAIT | DDBLT_COLORFILL, &fx);
|
|
|
|
}
|
|
|
|
if (lastRect.left < dstRect.left)
|
|
|
|
{
|
|
|
|
rect.left = lastRect.left;
|
|
|
|
rect.right = dstRect.left;
|
|
|
|
rect.top = dstRect.top;
|
|
|
|
rect.bottom = dstRect.bottom;
|
|
|
|
lpDDSurface2->Blt (&rect, NULL, &rect,
|
|
|
|
DDBLT_WAIT | DDBLT_COLORFILL, &fx);
|
|
|
|
}
|
|
|
|
if (lastRect.right > dstRect.right)
|
|
|
|
{
|
|
|
|
rect.left = dstRect.right;
|
|
|
|
rect.right = lastRect.right;
|
|
|
|
rect.top = dstRect.top;
|
|
|
|
rect.bottom = dstRect.bottom;
|
|
|
|
lpDDSurface2->Blt (&rect, NULL, &rect,
|
|
|
|
DDBLT_WAIT | DDBLT_COLORFILL, &fx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-25 17:35:19 +00:00
|
|
|
if(GUI.Vsync) {
|
|
|
|
lpDD->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN,NULL);
|
|
|
|
}
|
|
|
|
|
2010-09-25 15:46:12 +00:00
|
|
|
lpDDSPrimary2->Flip (NULL, GUI.Vsync?DDFLIP_WAIT:DDFLIP_NOVSYNC);
|
|
|
|
|
|
|
|
SizeHistory [GUI.FlipCounter % GUI.NumFlipFrames] = dstRect;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CDirectDraw::ApplyDisplayChanges(void)
|
|
|
|
{
|
2010-12-02 19:22:18 +00:00
|
|
|
return SetDisplayMode (GUI.FullscreenMode.width, GUI.FullscreenMode.height, max(GetFilterScale(GUI.Scale), GetFilterScale(GUI.ScaleHiRes)), GUI.FullscreenMode.depth, GUI.FullscreenMode.rate,
|
2010-12-30 00:23:13 +00:00
|
|
|
!GUI.FullScreen, GUI.DoubleBuffered);
|
2010-09-25 15:46:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool CDirectDraw::ChangeRenderSize(unsigned int newWidth, unsigned int newHeight)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CDirectDraw::SetFullscreen(bool fullscreen)
|
|
|
|
{
|
|
|
|
if (!SetDisplayMode (GUI.FullscreenMode.width, GUI.FullscreenMode.height, max(GetFilterScale(GUI.Scale), GetFilterScale(GUI.ScaleHiRes)), GUI.FullscreenMode.depth, GUI.FullscreenMode.rate, !fullscreen, GUI.DoubleBuffered))
|
|
|
|
{
|
2019-02-18 21:15:28 +00:00
|
|
|
MessageBox( GUI.hWnd, Languages[ GUI.Language].errModeDD, TEXT("Snes9x - DirectDraw(2)"), MB_OK | MB_ICONSTOP);
|
2010-09-25 15:46:12 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ffs (uint32 mask)
|
|
|
|
{
|
|
|
|
int m = 0;
|
|
|
|
if (mask)
|
|
|
|
{
|
|
|
|
while (!(mask & (1 << m)))
|
|
|
|
m++;
|
|
|
|
|
|
|
|
return (m);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CDirectDraw::SetSnes9xColorFormat()
|
|
|
|
{
|
|
|
|
GUI.ScreenDepth = DDPixelFormat.dwRGBBitCount;
|
|
|
|
if (GUI.ScreenDepth == 15)
|
|
|
|
GUI.ScreenDepth = 16;
|
|
|
|
|
|
|
|
GUI.RedShift = ffs (DDPixelFormat.dwRBitMask);
|
|
|
|
GUI.GreenShift = ffs (DDPixelFormat.dwGBitMask);
|
|
|
|
GUI.BlueShift = ffs (DDPixelFormat.dwBBitMask);
|
|
|
|
|
|
|
|
if((DDPixelFormat.dwFlags&DDPF_RGB) != 0 &&
|
|
|
|
GUI.ScreenDepth == 16 &&
|
|
|
|
DDPixelFormat.dwRBitMask == 0xF800 &&
|
|
|
|
DDPixelFormat.dwGBitMask == 0x07E0 &&
|
|
|
|
DDPixelFormat.dwBBitMask == 0x001F)
|
|
|
|
{
|
|
|
|
S9xSetRenderPixelFormat (RGB565);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if( (DDPixelFormat.dwFlags&DDPF_RGB) != 0 &&
|
|
|
|
GUI.ScreenDepth == 16 &&
|
|
|
|
DDPixelFormat.dwRBitMask == 0x7C00 &&
|
|
|
|
DDPixelFormat.dwGBitMask == 0x03E0 &&
|
|
|
|
DDPixelFormat.dwBBitMask == 0x001F)
|
|
|
|
{
|
|
|
|
S9xSetRenderPixelFormat (RGB555);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if((DDPixelFormat.dwFlags&DDPF_RGB) != 0 &&
|
|
|
|
GUI.ScreenDepth == 16 &&
|
|
|
|
DDPixelFormat.dwRBitMask == 0x001F &&
|
|
|
|
DDPixelFormat.dwGBitMask == 0x07E0 &&
|
|
|
|
DDPixelFormat.dwBBitMask == 0xF800)
|
|
|
|
{
|
|
|
|
S9xSetRenderPixelFormat (BGR565);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if( (DDPixelFormat.dwFlags&DDPF_RGB) != 0 &&
|
|
|
|
GUI.ScreenDepth == 16 &&
|
|
|
|
DDPixelFormat.dwRBitMask == 0x001F &&
|
|
|
|
DDPixelFormat.dwGBitMask == 0x03E0 &&
|
|
|
|
DDPixelFormat.dwBBitMask == 0x7C00)
|
|
|
|
{
|
|
|
|
S9xSetRenderPixelFormat (BGR555);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (DDPixelFormat.dwRGBBitCount == 8 ||
|
|
|
|
DDPixelFormat.dwRGBBitCount == 24 ||
|
|
|
|
DDPixelFormat.dwRGBBitCount == 32)
|
|
|
|
{
|
|
|
|
S9xSetRenderPixelFormat (RGB565);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((GUI.ScreenDepth == 24 || GUI.ScreenDepth == 32))
|
|
|
|
GUI.NeedDepthConvert = TRUE;
|
|
|
|
|
|
|
|
GUI.DepthConverted = !GUI.NeedDepthConvert;
|
|
|
|
|
|
|
|
if ((GUI.ScreenDepth == 24 || GUI.ScreenDepth == 32))
|
|
|
|
{
|
|
|
|
GUI.RedShift += 3;
|
|
|
|
GUI.GreenShift += 3;
|
|
|
|
GUI.BlueShift += 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
S9xBlit2xSaIFilterInit();
|
|
|
|
S9xBlitHQ2xFilterInit();
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT CALLBACK EnumModesCallback( LPDDSURFACEDESC lpDDSurfaceDesc, LPVOID lpContext)
|
|
|
|
{
|
|
|
|
dMode curmode;
|
|
|
|
std::vector<dMode> *modeVector=(std::vector<dMode> *)lpContext;
|
|
|
|
HWND hDlg = (HWND)lpContext;
|
|
|
|
|
|
|
|
if((lpDDSurfaceDesc->ddpfPixelFormat.dwRGBBitCount != 15 &&
|
|
|
|
lpDDSurfaceDesc->ddpfPixelFormat.dwRGBBitCount != 16 &&
|
|
|
|
lpDDSurfaceDesc->ddpfPixelFormat.dwRGBBitCount != 32) ||
|
|
|
|
(lpDDSurfaceDesc->dwWidth < SNES_WIDTH ||
|
|
|
|
lpDDSurfaceDesc->dwHeight < SNES_HEIGHT_EXTENDED))
|
|
|
|
{
|
|
|
|
// let them muck with the .cfg file if they really want to set such a poor display mode
|
|
|
|
return DDENUMRET_OK; // keep going without adding mode to list
|
|
|
|
}
|
|
|
|
|
|
|
|
curmode.width=lpDDSurfaceDesc->dwWidth;
|
|
|
|
curmode.height=lpDDSurfaceDesc->dwHeight;
|
|
|
|
curmode.depth=lpDDSurfaceDesc->ddpfPixelFormat.dwRGBBitCount;
|
|
|
|
curmode.rate=lpDDSurfaceDesc->dwRefreshRate;
|
|
|
|
|
|
|
|
modeVector->push_back(curmode);
|
|
|
|
|
|
|
|
return DDENUMRET_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CDirectDraw::EnumModes(std::vector<dMode> *modeVector)
|
|
|
|
{
|
2010-10-04 15:30:03 +00:00
|
|
|
if(!dDinitialized)
|
|
|
|
return;
|
2010-09-25 15:46:12 +00:00
|
|
|
lpDD->EnumDisplayModes(DDEDM_REFRESHRATES,NULL,(void *)modeVector,(LPDDENUMMODESCALLBACK)EnumModesCallback);
|
|
|
|
}
|
|
|
|
|
2017-04-02 23:12:55 +00:00
|
|
|
#endif
|