#include #include #include #include #include namespace DDraw { DDSURFACEDESC2 getDisplayMode(CompatRef dd) { DDSURFACEDESC2 dm = {}; dm.dwSize = sizeof(dm); dd->GetDisplayMode(&dd, &dm); return dm; } DDPIXELFORMAT getRgbPixelFormat(DWORD bpp) { DDPIXELFORMAT pf = {}; pf.dwSize = sizeof(pf); pf.dwFlags = DDPF_RGB; pf.dwRGBBitCount = bpp; switch (bpp) { case 1: pf.dwFlags |= DDPF_PALETTEINDEXED1; break; case 2: pf.dwFlags |= DDPF_PALETTEINDEXED2; break; case 4: pf.dwFlags |= DDPF_PALETTEINDEXED4; break; case 8: pf.dwFlags |= DDPF_PALETTEINDEXED8; break; case 16: pf.dwRBitMask = 0xF800; pf.dwGBitMask = 0x07E0; pf.dwBBitMask = 0x001F; break; case 24: case 32: pf.dwRBitMask = 0xFF0000; pf.dwGBitMask = 0x00FF00; pf.dwBBitMask = 0x0000FF; break; } return pf; } void logComInstantiation() { LOG_ONCE("COM instantiation of DirectDraw detected"); } void suppressEmulatedDirectDraw(GUID*& guid) { if (reinterpret_cast(DDCREATE_EMULATIONONLY) == guid) { LOG_ONCE("Suppressed a request to create an emulated DirectDraw object"); guid = nullptr; } } template void DirectDraw::setCompatVtable(Vtable& vtable) { vtable.CreateSurface = &CreateSurface; vtable.FlipToGDISurface = &FlipToGDISurface; vtable.GetGDISurface = &GetGDISurface; vtable.WaitForVerticalBlank = &WaitForVerticalBlank; } template HRESULT STDMETHODCALLTYPE DirectDraw::CreateSurface( TDirectDraw* This, TSurfaceDesc* lpDDSurfaceDesc, TSurface** lplpDDSurface, IUnknown* pUnkOuter) { if (!This || !lpDDSurfaceDesc || !lplpDDSurface) { return s_origVtable.CreateSurface(This, lpDDSurfaceDesc, lplpDDSurface, pUnkOuter); } if (lpDDSurfaceDesc->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) { return PrimarySurface::create(*This, *lpDDSurfaceDesc, *lplpDDSurface); } else { return Surface::create(*This, *lpDDSurfaceDesc, *lplpDDSurface, std::make_unique()); } } template HRESULT STDMETHODCALLTYPE DirectDraw::FlipToGDISurface(TDirectDraw* /*This*/) { return PrimarySurface::flipToGdiSurface(); } template HRESULT STDMETHODCALLTYPE DirectDraw::GetGDISurface( TDirectDraw* /*This*/, TSurface** lplpGDIDDSSurface) { if (!lplpGDIDDSSurface) { return DDERR_INVALIDPARAMS; } auto gdiSurface(PrimarySurface::getGdiSurface()); if (!gdiSurface) { return DDERR_NOTFOUND; } *lplpGDIDDSSurface = CompatPtr::from(gdiSurface.get()).detach(); return DD_OK; } template HRESULT STDMETHODCALLTYPE DirectDraw::Initialize(TDirectDraw* This, GUID* lpGUID) { logComInstantiation(); suppressEmulatedDirectDraw(lpGUID); return s_origVtable.Initialize(This, lpGUID); } template HRESULT STDMETHODCALLTYPE DirectDraw::WaitForVerticalBlank( TDirectDraw* This, DWORD dwFlags, HANDLE hEvent) { if (!This || (DDWAITVB_BLOCKBEGIN != dwFlags && DDWAITVB_BLOCKEND != dwFlags)) { return s_origVtable.WaitForVerticalBlank(This, dwFlags, hEvent); } DWORD scanLine = 0; if (DDERR_VERTICALBLANKINPROGRESS != s_origVtable.GetScanLine(This, &scanLine)) { D3dDdi::KernelModeThunks::waitForVerticalBlank(); } if (DDWAITVB_BLOCKEND == dwFlags) { while (DDERR_VERTICALBLANKINPROGRESS == s_origVtable.GetScanLine(This, &scanLine)); } return DD_OK; } template DirectDraw; template DirectDraw; template DirectDraw; template DirectDraw; }