1
0
mirror of https://github.com/narzoul/DDrawCompat synced 2024-12-30 08:55:36 +01:00
DDrawCompat/DDrawCompat/DDraw/Surfaces/PrimarySurfaceImpl.cpp
narzoul 947bb41bf3 Emulate flip when the primary surface is requested in system memory
When the primary surface chain is requested to be created in system memory,
flip should be emulated (copy from back buffer to front buffer) to be
consistent with legacy DirectDraw behavior.

Fixes flashing graphical artifacts in Carmageddon (Win95 version) menus
when exiting from a race, mentioned in issue #3.
2017-07-25 21:27:40 +02:00

248 lines
6.0 KiB
C++

#include "DDraw/DirectDrawPalette.h"
#include "DDraw/RealPrimarySurface.h"
#include "DDraw/Surfaces/PrimarySurface.h"
#include "DDraw/Surfaces/PrimarySurfaceImpl.h"
#include "Gdi/Gdi.h"
namespace
{
void restorePrimaryCaps(DWORD& caps)
{
caps &= ~DDSCAPS_OFFSCREENPLAIN;
caps |= DDSCAPS_PRIMARYSURFACE | DDSCAPS_VISIBLE;
}
}
namespace DDraw
{
template <typename TSurface>
PrimarySurfaceImpl<TSurface>::PrimarySurfaceImpl(SurfaceImpl& impl) : m_impl(impl)
{
}
template <typename TSurface>
HRESULT PrimarySurfaceImpl<TSurface>::Blt(
TSurface* This, LPRECT lpDestRect, TSurface* lpDDSrcSurface, LPRECT lpSrcRect,
DWORD dwFlags, LPDDBLTFX lpDDBltFx)
{
if (RealPrimarySurface::isLost())
{
return DDERR_SURFACELOST;
}
HRESULT result = m_impl.Blt(This, lpDestRect, lpDDSrcSurface, lpSrcRect, dwFlags, lpDDBltFx);
if (SUCCEEDED(result))
{
RealPrimarySurface::update();
}
return result;
}
template <typename TSurface>
HRESULT PrimarySurfaceImpl<TSurface>::BltFast(
TSurface* This, DWORD dwX, DWORD dwY, TSurface* lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwTrans)
{
if (RealPrimarySurface::isLost())
{
return DDERR_SURFACELOST;
}
HRESULT result = m_impl.BltFast(This, dwX, dwY, lpDDSrcSurface, lpSrcRect, dwTrans);
if (SUCCEEDED(result))
{
const LONG x = dwX;
const LONG y = dwY;
RECT destRect = { x, y, x, y };
if (lpSrcRect)
{
destRect.right += lpSrcRect->right - lpSrcRect->left;
destRect.bottom += lpSrcRect->bottom - lpSrcRect->top;
}
else
{
TSurfaceDesc desc = {};
desc.dwSize = sizeof(desc);
CompatVtable<Vtable<TSurface>>::s_origVtable.GetSurfaceDesc(lpDDSrcSurface, &desc);
destRect.right += desc.dwWidth;
destRect.bottom += desc.dwHeight;
}
RealPrimarySurface::update();
}
return result;
}
template <typename TSurface>
HRESULT PrimarySurfaceImpl<TSurface>::Flip(TSurface* This, TSurface* lpDDSurfaceTargetOverride, DWORD dwFlags)
{
if (RealPrimarySurface::isLost())
{
return DDERR_SURFACELOST;
}
HRESULT result = m_impl.Flip(This, lpDDSurfaceTargetOverride, dwFlags);
if (FAILED(result))
{
return result;
}
result = RealPrimarySurface::flip(dwFlags);
if (SUCCEEDED(result) && !PrimarySurface::isFlipEmulated())
{
static_cast<PrimarySurface*>(m_data)->updateGdiSurfacePtr(
CompatPtr<IDirectDrawSurface>::from(lpDDSurfaceTargetOverride));
return DD_OK;
}
undoFlip(This, lpDDSurfaceTargetOverride);
if (SUCCEEDED(result) && PrimarySurface::isFlipEmulated())
{
if (lpDDSurfaceTargetOverride)
{
s_origVtable.BltFast(This, 0, 0, lpDDSurfaceTargetOverride, nullptr, DDBLTFAST_WAIT);
}
else
{
TDdsCaps caps = {};
caps.dwCaps = DDSCAPS_BACKBUFFER;
CompatPtr<TSurface> backBuffer;
s_origVtable.GetAttachedSurface(This, &caps, &backBuffer.getRef());
s_origVtable.BltFast(This, 0, 0, backBuffer, nullptr, DDBLTFAST_WAIT);
}
}
return result;
}
template <typename TSurface>
HRESULT PrimarySurfaceImpl<TSurface>::GetCaps(TSurface* This, TDdsCaps* lpDDSCaps)
{
HRESULT result = m_impl.GetCaps(This, lpDDSCaps);
if (SUCCEEDED(result))
{
restorePrimaryCaps(lpDDSCaps->dwCaps);
}
return result;
}
template <typename TSurface>
HRESULT PrimarySurfaceImpl<TSurface>::GetSurfaceDesc(TSurface* This, TSurfaceDesc* lpDDSurfaceDesc)
{
HRESULT result = m_impl.GetSurfaceDesc(This, lpDDSurfaceDesc);
if (SUCCEEDED(result))
{
restorePrimaryCaps(lpDDSurfaceDesc->ddsCaps.dwCaps);
}
return result;
}
template <typename TSurface>
HRESULT PrimarySurfaceImpl<TSurface>::IsLost(TSurface* This)
{
HRESULT result = m_impl.IsLost(This);
if (SUCCEEDED(result))
{
result = RealPrimarySurface::isLost() ? DDERR_SURFACELOST : DD_OK;
}
return result;
}
template <typename TSurface>
HRESULT PrimarySurfaceImpl<TSurface>::Lock(
TSurface* This, LPRECT lpDestRect, TSurfaceDesc* lpDDSurfaceDesc,
DWORD dwFlags, HANDLE hEvent)
{
if (RealPrimarySurface::isLost())
{
return DDERR_SURFACELOST;
}
HRESULT result = m_impl.Lock(This, lpDestRect, lpDDSurfaceDesc, dwFlags, hEvent);
if (SUCCEEDED(result))
{
restorePrimaryCaps(lpDDSurfaceDesc->ddsCaps.dwCaps);
}
return result;
}
template <typename TSurface>
HRESULT PrimarySurfaceImpl<TSurface>::ReleaseDC(TSurface* This, HDC hDC)
{
HRESULT result = m_impl.ReleaseDC(This, hDC);
if (SUCCEEDED(result))
{
RealPrimarySurface::update();
}
return result;
}
template <typename TSurface>
HRESULT PrimarySurfaceImpl<TSurface>::Restore(TSurface* This)
{
HRESULT result = IsLost(This);
if (FAILED(result))
{
result = RealPrimarySurface::restore();
if (SUCCEEDED(result))
{
result = m_impl.Restore(This);
if (SUCCEEDED(result))
{
Gdi::redraw(nullptr);
}
}
}
return result;
}
template <typename TSurface>
HRESULT PrimarySurfaceImpl<TSurface>::SetClipper(TSurface* This, LPDIRECTDRAWCLIPPER lpDDClipper)
{
HRESULT result = m_impl.SetClipper(This, lpDDClipper);
if (SUCCEEDED(result))
{
RealPrimarySurface::setClipper(lpDDClipper);
}
return result;
}
template <typename TSurface>
HRESULT PrimarySurfaceImpl<TSurface>::SetPalette(TSurface* This, LPDIRECTDRAWPALETTE lpDDPalette)
{
if (lpDDPalette)
{
DirectDrawPalette::waitForNextUpdate();
}
if (lpDDPalette == PrimarySurface::s_palette)
{
return DD_OK;
}
HRESULT result = m_impl.SetPalette(This, lpDDPalette);
if (SUCCEEDED(result))
{
PrimarySurface::s_palette = lpDDPalette;
RealPrimarySurface::setPalette();
}
return result;
}
template <typename TSurface>
HRESULT PrimarySurfaceImpl<TSurface>::Unlock(TSurface* This, TUnlockParam lpRect)
{
HRESULT result = m_impl.Unlock(This, lpRect);
if (SUCCEEDED(result))
{
RealPrimarySurface::update();
}
return result;
}
template PrimarySurfaceImpl<IDirectDrawSurface>;
template PrimarySurfaceImpl<IDirectDrawSurface2>;
template PrimarySurfaceImpl<IDirectDrawSurface3>;
template PrimarySurfaceImpl<IDirectDrawSurface4>;
template PrimarySurfaceImpl<IDirectDrawSurface7>;
}