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 7068d282ff Improved palette handling
Fixes windowed-mode palette issues in SimCopter (issue #46)
2019-08-03 12:09:19 +02:00

252 lines
6.7 KiB
C++

#include "Common/CompatPtr.h"
#include "D3dDdi/KernelModeThunks.h"
#include "DDraw/DirectDrawClipper.h"
#include "DDraw/DirectDrawPalette.h"
#include "DDraw/DirectDrawSurface.h"
#include "DDraw/RealPrimarySurface.h"
#include "DDraw/Surfaces/PrimarySurface.h"
#include "DDraw/Surfaces/PrimarySurfaceImpl.h"
#include "Dll/Procs.h"
#include "Gdi/Gdi.h"
#include "Gdi/Region.h"
#include "Gdi/VirtualScreen.h"
namespace
{
template <typename TSurface>
void bltToGdi(TSurface* This, LPRECT lpDestRect, TSurface* lpDDSrcSurface, LPRECT lpSrcRect,
DWORD dwFlags, LPDDBLTFX lpDDBltFx)
{
if (!lpDestRect)
{
return;
}
CompatPtr<IDirectDrawClipper> clipper;
CompatVtable<Vtable<TSurface>>::s_origVtable.GetClipper(This, &clipper.getRef());
if (!clipper)
{
return;
}
Gdi::Region clipRgn(DDraw::DirectDrawClipper::getClipRgn(*clipper));
RECT monitorRect = D3dDdi::KernelModeThunks::getMonitorRect();
RECT virtualScreenBounds = Gdi::VirtualScreen::getBounds();
clipRgn.offset(monitorRect.left, monitorRect.top);
clipRgn &= virtualScreenBounds;
clipRgn -= monitorRect;
if (clipRgn.isEmpty())
{
return;
}
auto gdiSurface(Gdi::VirtualScreen::createSurface(virtualScreenBounds));
if (!gdiSurface)
{
return;
}
CompatPtr<IDirectDrawClipper> gdiClipper;
CALL_ORIG_PROC(DirectDrawCreateClipper)(0, &gdiClipper.getRef(), nullptr);
if (!gdiClipper)
{
return;
}
RECT dstRect = *lpDestRect;
OffsetRect(&dstRect, monitorRect.left - virtualScreenBounds.left, monitorRect.top - virtualScreenBounds.top);
clipRgn.offset(-virtualScreenBounds.left, -virtualScreenBounds.top);
DDraw::DirectDrawClipper::setClipRgn(*gdiClipper, clipRgn);
auto srcSurface(CompatPtr<IDirectDrawSurface7>::from(lpDDSrcSurface));
gdiSurface->SetClipper(gdiSurface, gdiClipper);
gdiSurface.get()->lpVtbl->Blt(gdiSurface, &dstRect, srcSurface, lpSrcRect, dwFlags, lpDDBltFx);
gdiSurface->SetClipper(gdiSurface, nullptr);
}
void restorePrimaryCaps(DWORD& caps)
{
caps &= ~DDSCAPS_OFFSCREENPLAIN;
caps |= DDSCAPS_PRIMARYSURFACE | DDSCAPS_VISIBLE;
}
}
namespace DDraw
{
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 = SurfaceImpl::Blt(This, lpDestRect, lpDDSrcSurface, lpSrcRect, dwFlags, lpDDBltFx);
if (SUCCEEDED(result))
{
bltToGdi(This, lpDestRect, lpDDSrcSurface, lpSrcRect, dwFlags, lpDDBltFx);
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 = SurfaceImpl::BltFast(This, dwX, dwY, lpDDSrcSurface, lpSrcRect, dwTrans);
if (SUCCEEDED(result))
{
RealPrimarySurface::update();
}
return result;
}
template <typename TSurface>
HRESULT PrimarySurfaceImpl<TSurface>::Flip(TSurface* This, TSurface* lpDDSurfaceTargetOverride, DWORD dwFlags)
{
const bool wait = (dwFlags & DDFLIP_WAIT) || !(dwFlags & DDFLIP_DONOTWAIT) &&
CompatVtable<IDirectDrawSurface7Vtbl>::s_origVtablePtr == static_cast<void*>(This->lpVtbl);
if (!DDraw::RealPrimarySurface::waitForFlip(Surface::getSurface(*This), wait))
{
return DDERR_WASSTILLDRAWING;
}
auto surfaceTargetOverride(CompatPtr<TSurface>::from(lpDDSurfaceTargetOverride));
const bool isFlipEmulated = 0 != (PrimarySurface::getOrigCaps() & DDSCAPS_SYSTEMMEMORY);
if (isFlipEmulated && !surfaceTargetOverride)
{
TDdsCaps caps = {};
caps.dwCaps = DDSCAPS_BACKBUFFER;
s_origVtable.GetAttachedSurface(This, &caps, &surfaceTargetOverride.getRef());
}
HRESULT result = SurfaceImpl::Flip(This, surfaceTargetOverride, DDFLIP_WAIT);
if (FAILED(result))
{
return result;
}
PrimarySurface::updateFrontResource();
return RealPrimarySurface::flip(surfaceTargetOverride, dwFlags);
}
template <typename TSurface>
HRESULT PrimarySurfaceImpl<TSurface>::GetCaps(TSurface* This, TDdsCaps* lpDDSCaps)
{
HRESULT result = SurfaceImpl::GetCaps(This, lpDDSCaps);
if (SUCCEEDED(result))
{
restorePrimaryCaps(lpDDSCaps->dwCaps);
}
return result;
}
template <typename TSurface>
HRESULT PrimarySurfaceImpl<TSurface>::GetSurfaceDesc(TSurface* This, TSurfaceDesc* lpDDSurfaceDesc)
{
HRESULT result = SurfaceImpl::GetSurfaceDesc(This, lpDDSurfaceDesc);
if (SUCCEEDED(result))
{
restorePrimaryCaps(lpDDSurfaceDesc->ddsCaps.dwCaps);
}
return result;
}
template <typename TSurface>
HRESULT PrimarySurfaceImpl<TSurface>::IsLost(TSurface* This)
{
HRESULT result = SurfaceImpl::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 = SurfaceImpl::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 = SurfaceImpl::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))
{
return SurfaceImpl::Restore(This);
}
}
return result;
}
template <typename TSurface>
HRESULT PrimarySurfaceImpl<TSurface>::SetPalette(TSurface* This, LPDIRECTDRAWPALETTE lpDDPalette)
{
if (lpDDPalette)
{
DirectDrawPalette::waitForNextUpdate();
}
HRESULT result = SurfaceImpl::SetPalette(This, lpDDPalette);
if (SUCCEEDED(result))
{
PrimarySurface::s_palette = lpDDPalette;
PrimarySurface::updatePalette();
}
return result;
}
template <typename TSurface>
HRESULT PrimarySurfaceImpl<TSurface>::Unlock(TSurface* This, TUnlockParam lpRect)
{
HRESULT result = SurfaceImpl::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>;
}