mirror of
https://github.com/narzoul/DDrawCompat
synced 2024-12-30 08:55:36 +01:00
252 lines
6.7 KiB
C++
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>;
|
|
}
|