1
0
mirror of https://github.com/narzoul/DDrawCompat synced 2024-12-30 08:55:36 +01:00
DDrawCompat/DDrawCompat/DDraw/DirectDrawSurface.cpp
narzoul 383ffd28b9 Fixed GetAttachedSurface when DDSCAPS_3DDEVICE is suppressed
Fixes a crash in Colin McRae Rally (#232).
2023-11-11 17:16:39 +01:00

108 lines
3.6 KiB
C++

#include <type_traits>
#include <Common/CompatVtable.h>
#include <DDraw/DirectDrawSurface.h>
#include <DDraw/ScopedThreadLock.h>
#include <DDraw/Surfaces/Surface.h>
#include <DDraw/Surfaces/SurfaceImpl.h>
#include <DDraw/Visitors/DirectDrawSurfaceVtblVisitor.h>
#define SET_COMPAT_METHOD(method) \
vtable.method = &callImpl<decltype(&DDraw::SurfaceImpl<TSurface>::method), &DDraw::SurfaceImpl<TSurface>::method, \
decltype(&Vtable::method), &Vtable::method>
namespace
{
template <typename Vtable> struct GetSurfaceType {};
template <> struct GetSurfaceType<IDirectDrawSurfaceVtbl> { typedef IDirectDrawSurface Type; };
template <> struct GetSurfaceType<IDirectDrawSurface2Vtbl> { typedef IDirectDrawSurface2 Type; };
template <> struct GetSurfaceType<IDirectDrawSurface3Vtbl> { typedef IDirectDrawSurface3 Type; };
template <> struct GetSurfaceType<IDirectDrawSurface4Vtbl> { typedef IDirectDrawSurface4 Type; };
template <> struct GetSurfaceType<IDirectDrawSurface7Vtbl> { typedef IDirectDrawSurface7 Type; };
struct AddAttachedSurfacesContext
{
IDirectDrawSurface7* rootSurface;
std::vector<CompatPtr<IDirectDrawSurface7>> surfaces;
};
HRESULT WINAPI addAttachedSurfaces(
LPDIRECTDRAWSURFACE7 lpDDSurface, LPDDSURFACEDESC2 /*lpDDSurfaceDesc*/, LPVOID lpContext)
{
CompatPtr<IDirectDrawSurface7> surface(lpDDSurface);
auto& context(*static_cast<AddAttachedSurfacesContext*>(lpContext));
if (surface == context.rootSurface)
{
return DD_OK;
}
context.surfaces.push_back(surface);
surface->EnumAttachedSurfaces(surface, &context, &addAttachedSurfaces);
return DD_OK;
}
template <typename CompatMethod, CompatMethod compatMethod,
typename OrigMethod, OrigMethod origMethod,
typename TSurface, typename... Params>
HRESULT STDMETHODCALLTYPE callImpl(TSurface* This, Params... params)
{
DDraw::Surface* surface = DDraw::Surface::getSurface(*This);
if (!surface || !(surface->getImpl<TSurface>()))
{
return (getOrigVtable(This).*origMethod)(This, params...);
}
return (surface->getImpl<TSurface>()->*compatMethod)(This, params...);
}
template <typename Vtable>
constexpr void setCompatVtable(Vtable& vtable)
{
typedef GetSurfaceType<Vtable>::Type TSurface;
SET_COMPAT_METHOD(Blt);
SET_COMPAT_METHOD(BltFast);
SET_COMPAT_METHOD(Flip);
SET_COMPAT_METHOD(GetAttachedSurface);
SET_COMPAT_METHOD(GetCaps);
SET_COMPAT_METHOD(GetDC);
SET_COMPAT_METHOD(GetPalette);
SET_COMPAT_METHOD(GetSurfaceDesc);
SET_COMPAT_METHOD(IsLost);
SET_COMPAT_METHOD(Lock);
SET_COMPAT_METHOD(QueryInterface);
SET_COMPAT_METHOD(ReleaseDC);
SET_COMPAT_METHOD(Restore);
SET_COMPAT_METHOD(SetClipper);
SET_COMPAT_METHOD(SetPalette);
SET_COMPAT_METHOD(Unlock);
if constexpr (!std::is_same_v<Vtable, IDirectDrawSurfaceVtbl> && !std::is_same_v<Vtable, IDirectDrawSurface2Vtbl>)
{
SET_COMPAT_METHOD(SetSurfaceDesc);
}
}
}
namespace DDraw
{
namespace DirectDrawSurface
{
std::vector<CompatPtr<IDirectDrawSurface7>> getAllAttachedSurfaces(CompatRef<IDirectDrawSurface7> surface)
{
AddAttachedSurfacesContext context = { &surface };
surface->EnumAttachedSurfaces(&surface, &context, &addAttachedSurfaces);
return context.surfaces;
}
template <typename Vtable>
void hookVtable(const Vtable& vtable)
{
CompatVtable<Vtable>::hookVtable<ScopedThreadLock>(vtable);
}
template void hookVtable(const IDirectDrawSurfaceVtbl&);
template void hookVtable(const IDirectDrawSurface2Vtbl&);
template void hookVtable(const IDirectDrawSurface3Vtbl&);
template void hookVtable(const IDirectDrawSurface4Vtbl&);
template void hookVtable(const IDirectDrawSurface7Vtbl&);
}
}