Skip to content

Commit

Permalink
Add basic support for windowed mode
Browse files Browse the repository at this point in the history
Related to #221 and #222
  • Loading branch information
elishacloud committed Aug 31, 2023
1 parent 58ff6e9 commit 84e47b5
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 47 deletions.
2 changes: 1 addition & 1 deletion Dllmain/BuildNo.rc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
#define BUILD_NUMBER 6783
#define BUILD_NUMBER 6784
2 changes: 1 addition & 1 deletion ddraw/IDirect3DDeviceX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1740,7 +1740,7 @@ HRESULT m_IDirect3DDeviceX::EndScene()
// Present surface after end scene
if (SUCCEEDED(hr))
{
hr = ddrawParent->Present();
hr = ddrawParent->Present(nullptr, nullptr);
}

return hr;
Expand Down
161 changes: 122 additions & 39 deletions ddraw/IDirectDrawSurfaceX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1311,6 +1311,23 @@ HRESULT m_IDirectDrawSurfaceX::Flip(LPDIRECTDRAWSURFACE7 lpDDSurfaceTargetOverri
pSurfaceX->ReleaseLockCriticalSection();
}

// Preset surface to window
if (!IsDirect3DEnabled)
{
RECT Rect = { 0, 0, (LONG)surfaceDesc2.dwWidth, (LONG)surfaceDesc2.dwHeight };

// Blt surface directly to GDI
if (Config.DdrawWriteToGDI)
{
CopyEmulatedSurfaceToGDI(Rect);
}
// Handle windowed mode
else if (IsUsingWindowedMode)
{
PresentWindowedSurface(Rect);
}
}

// Present surface
if (SUCCEEDED(hr))
{
Expand Down Expand Up @@ -2332,10 +2349,12 @@ HRESULT m_IDirectDrawSurfaceX::ReleaseDC(HDC hDC)
LOG_LIMIT(100, __FUNCTION__ << " Error: surface not using emulated DC!");
break;
}

// Restore DC
UnsetEmulationGameDC();

// Blt surface directly to GDI
if (Config.DdrawWriteToGDI && IsPrimaryOrBackBuffer() && !IsDirect3DEnabled)
if (Config.DdrawWriteToGDI && IsPrimarySurface() && !IsDirect3DEnabled)
{
RECT Rect = { 0, 0, (LONG)surfaceDesc2.dwWidth, (LONG)surfaceDesc2.dwHeight };
CopyEmulatedSurfaceToGDI(Rect);
Expand Down Expand Up @@ -2371,6 +2390,13 @@ HRESULT m_IDirectDrawSurfaceX::ReleaseDC(HDC hDC)
break;
}

// Preset surface to window
if (IsUsingWindowedMode && IsPrimarySurface() && !Config.DdrawWriteToGDI && !IsDirect3DEnabled)
{
RECT Rect = { 0, 0, (LONG)surfaceDesc2.dwWidth, (LONG)surfaceDesc2.dwHeight };
PresentWindowedSurface(Rect);
}

// Reset DC flag
IsInDC = false;

Expand Down Expand Up @@ -2750,7 +2776,7 @@ HRESULT m_IDirectDrawSurfaceX::Unlock(LPRECT lpRect)
if (!LastLock.ReadOnly)
{
// Blt surface directly to GDI
if (Config.DdrawWriteToGDI && IsPrimaryOrBackBuffer() && !IsDirect3DEnabled)
if (Config.DdrawWriteToGDI && IsPrimarySurface() && !IsDirect3DEnabled)
{
CopyEmulatedSurfaceToGDI(LastLock.Rect);
}
Expand Down Expand Up @@ -2781,6 +2807,12 @@ HRESULT m_IDirectDrawSurfaceX::Unlock(LPRECT lpRect)
break;
}

// Preset surface to window
if (IsUsingWindowedMode && IsPrimarySurface() && !Config.DdrawWriteToGDI && !IsDirect3DEnabled)
{
PresentWindowedSurface(LastLock.Rect);
}

// Clear memory pointer
LastLock.LockedRect.pBits = nullptr;

Expand Down Expand Up @@ -3459,6 +3491,9 @@ HRESULT m_IDirectDrawSurfaceX::CheckInterface(char *FunctionName, bool CheckD3DD
ReleaseDCSurface();
}

// Check if using windowed mode
IsUsingWindowedMode = !ddrawParent->IsExclusiveMode();

// Check if device is lost
if (!IsUsingEmulation() && CheckD3DDevice)
{
Expand Down Expand Up @@ -4421,7 +4456,7 @@ HRESULT m_IDirectDrawSurfaceX::PresentSurface(bool IsSkipScene)
}

// Check if is not primary surface or if scene should be skipped
if (Config.DdrawWriteToGDI || IsDirect3DEnabled)
if (Config.DdrawWriteToGDI || IsUsingWindowedMode || IsDirect3DEnabled)
{
// Never present when using Direct3D or when writing to GDI
return DD_OK;
Expand Down Expand Up @@ -4486,7 +4521,7 @@ HRESULT m_IDirectDrawSurfaceX::PresentSurface(bool IsSkipScene)
}

// Present to d3d9
if (FAILED(ddrawParent->Present()))
if (FAILED(ddrawParent->Present(nullptr, nullptr)))
{
LOG_LIMIT(100, __FUNCTION__ << " Error: failed to present 2D scene!");
hr = DDERR_GENERIC;
Expand Down Expand Up @@ -5155,7 +5190,7 @@ HRESULT m_IDirectDrawSurfaceX::ColorFill(RECT* pRect, D3DCOLOR dwFillColor)
}

// Blt surface directly to GDI
if (Config.DdrawWriteToGDI && IsPrimaryOrBackBuffer() && !IsDirect3DEnabled)
if (Config.DdrawWriteToGDI && IsPrimarySurface() && !IsDirect3DEnabled)
{
CopyEmulatedSurfaceToGDI(DestRect);
}
Expand All @@ -5166,6 +5201,12 @@ HRESULT m_IDirectDrawSurfaceX::ColorFill(RECT* pRect, D3DCOLOR dwFillColor)
}
}

// Preset surface to window
if (IsUsingWindowedMode && IsPrimarySurface() && !Config.DdrawWriteToGDI && !IsDirect3DEnabled)
{
PresentWindowedSurface(DestRect);
}

return DD_OK;
}

Expand Down Expand Up @@ -5693,17 +5734,26 @@ HRESULT m_IDirectDrawSurfaceX::CopySurface(m_IDirectDrawSurfaceX* pSourceSurface
}

// Update for emulated surface
if (SUCCEEDED(hr) && IsUsingEmulation())
if (SUCCEEDED(hr))
{
// Blt surface directly to GDI
if (Config.DdrawWriteToGDI && IsPrimaryOrBackBuffer() && !IsDirect3DEnabled)
if (IsUsingEmulation())
{
CopyEmulatedSurfaceToGDI(DestRect);
// Blt surface directly to GDI
if (Config.DdrawWriteToGDI && IsPrimarySurface() && !IsDirect3DEnabled)
{
CopyEmulatedSurfaceToGDI(DestRect);
}
// Copy emulated surface to real texture
else
{
CopyFromEmulatedSurface(&DestRect);
}
}
// Copy emulated surface to real texture
else

// Preset surface to window
if (IsUsingWindowedMode && IsPrimarySurface() && !Config.DdrawWriteToGDI && !IsDirect3DEnabled)
{
CopyFromEmulatedSurface(&DestRect);
PresentWindowedSurface(DestRect);
}
}

Expand Down Expand Up @@ -5993,34 +6043,27 @@ HRESULT m_IDirectDrawSurfaceX::CopyEmulatedSurfaceFromGDI(RECT Rect)
HWND hWnd = (UsingForgroundWindow) ? Forground_hWnd : DDraw_hWnd;
if (!hWnd)
{
Logging::Log() << __FUNCTION__ << " Error: Cannot get window handle!";
LOG_LIMIT(100, __FUNCTION__ << " Error: Cannot get window handle!");
return DDERR_GENERIC;
}

// Get rect size
RECT WindowRect = {};
GetClientRect(hWnd, &WindowRect);
MapWindowPoints(hWnd, HWND_DESKTOP, (LPPOINT)&WindowRect, 2);
LONG XOffset = WindowRect.left;
LONG YOffset = WindowRect.top;
LONG Left = Rect.left + XOffset;
LONG Top = Rect.top + YOffset;
LONG Width = Rect.right - Rect.left;
LONG Height = Rect.bottom - Rect.top;
RECT MapRect = Rect;
MapWindowPoints(hWnd, HWND_DESKTOP, (LPPOINT)&MapRect, 2);

// Get hdc
HDC hdc = (UsingForgroundWindow) ? ::GetDC(hWnd) : ddrawParent->GetDC();
if (!hdc)
{
Logging::Log() << __FUNCTION__ << " Error: Cannot get window DC!";
LOG_LIMIT(100, __FUNCTION__ << " Error: Cannot get window DC!");
return DDERR_GENERIC;
}

// Set new palette data
UpdatePaletteData();

// Blt to GDI
BitBlt(surface.emu->DC, Left, Top, Width, Height, hdc, Rect.left, Rect.top, SRCCOPY);
BitBlt(surface.emu->DC, MapRect.left, MapRect.top, MapRect.right - MapRect.left, MapRect.bottom - MapRect.top, hdc, Rect.left, Rect.top, SRCCOPY);

// Release DC
if (UsingForgroundWindow)
Expand Down Expand Up @@ -6048,37 +6091,27 @@ HRESULT m_IDirectDrawSurfaceX::CopyEmulatedSurfaceToGDI(RECT Rect)
HWND hWnd = (UsingForgroundWindow) ? Forground_hWnd : DDraw_hWnd;
if (!hWnd)
{
Logging::Log() << __FUNCTION__ << " Error: Cannot get window handle!";
LOG_LIMIT(100, __FUNCTION__ << " Error: Cannot get window handle!");
return DDERR_GENERIC;
}

// Get rect size
POINT WindowPoint = {};
if (MapWindowPoints(hWnd, HWND_DESKTOP, &WindowPoint, 1) == FALSE)
{
Logging::Log() << __FUNCTION__ << " Error: Cannot get window map points!";
return DDERR_GENERIC;
}
LONG XOffset = WindowPoint.x;
LONG YOffset = WindowPoint.y;
LONG Left = (Rect.left >= XOffset) ? Rect.left - XOffset : Rect.left;
LONG Top = (Rect.top >= YOffset) ? Rect.top - YOffset : Rect.top;
LONG Width = Rect.right - Rect.left;
LONG Height = Rect.bottom - Rect.top;
RECT MapRect = Rect;
MapWindowPoints(HWND_DESKTOP, hWnd, (LPPOINT)&MapRect, 2);

// Get hdc
HDC hdc = (UsingForgroundWindow) ? ::GetDC(hWnd) : ddrawParent->GetDC();
if (!hdc)
{
Logging::Log() << __FUNCTION__ << " Error: Cannot get window DC!";
LOG_LIMIT(100, __FUNCTION__ << " Error: Cannot get window DC!");
return DDERR_GENERIC;
}

// Set new palette data
UpdatePaletteData();

// Blt to GDI
BitBlt(hdc, Left, Top, Width, Height, surface.emu->DC, Rect.left, Rect.top, SRCCOPY);
BitBlt(hdc, MapRect.left, MapRect.top, MapRect.right - MapRect.left, MapRect.bottom - MapRect.top, surface.emu->DC, Rect.left, Rect.top, SRCCOPY);

// Release DC
if (UsingForgroundWindow)
Expand All @@ -6089,6 +6122,56 @@ HRESULT m_IDirectDrawSurfaceX::CopyEmulatedSurfaceToGDI(RECT Rect)
return DD_OK;
}

HRESULT m_IDirectDrawSurfaceX::PresentWindowedSurface(RECT Rect)
{
// Check for forground window
HWND DDraw_hWnd = ddrawParent->GetHwnd();
HWND Forground_hWnd = Utils::GetTopLevelWindowOfCurrentProcess();
bool UsingForgroundWindow = (DDraw_hWnd != Forground_hWnd) && Utils::IsWindowRectEqualOrLarger(Forground_hWnd, DDraw_hWnd);

// Get hWnd
HWND hWnd = (UsingForgroundWindow) ? Forground_hWnd : DDraw_hWnd;
if (!hWnd)
{
LOG_LIMIT(100, __FUNCTION__ << " Error: Cannot get window handle!");
return DDERR_GENERIC;
}

// Get rect size
RECT MapRect = Rect;
MapWindowPoints(HWND_DESKTOP, hWnd, (LPPOINT)&MapRect, 2);

// Begin scene
if (FAILED((*d3d9Device)->BeginScene()))
{
LOG_LIMIT(100, __FUNCTION__ << " Error: failed to begin scene!");
return DDERR_GENERIC;
}

// Draw 2D surface before presenting
if (FAILED(Draw2DSurface()))
{
LOG_LIMIT(100, __FUNCTION__ << " Error: failed to draw 2D surface!");
return DDERR_GENERIC;
}

// End scene
if (FAILED((*d3d9Device)->EndScene()))
{
LOG_LIMIT(100, __FUNCTION__ << " Error: failed to end scene!");
return DDERR_GENERIC;
}

// Present to d3d9
if (FAILED(ddrawParent->Present(&Rect, &MapRect)))
{
LOG_LIMIT(100, __FUNCTION__ << " Error: failed to present 2D scene!");
return DDERR_GENERIC;
}

return DD_OK;
}

void m_IDirectDrawSurfaceX::RemoveClipper(m_IDirectDrawClipper* ClipperToRemove)
{
if (ClipperToRemove == attachedClipper)
Expand Down
2 changes: 2 additions & 0 deletions ddraw/IDirectDrawSurfaceX.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ class m_IDirectDrawSurfaceX : public IUnknown, public AddressLookupTableDdrawObj
DWORD Priority = 0;
DWORD MaxLOD = 0;

bool IsUsingWindowedMode = false;
bool Is3DRenderingTarget = false; // Surface used for Direct3D rendering target, called from m_IDirect3DX::CreateDevice()
bool IsDirect3DEnabled = false; // Direct3D is being used on top of DirectDraw
bool DCRequiresEmulation = false;
Expand Down Expand Up @@ -250,6 +251,7 @@ class m_IDirectDrawSurfaceX : public IUnknown, public AddressLookupTableDdrawObj
HRESULT CopyEmulatedPaletteSurface(LPRECT lpDestRect);
HRESULT CopyEmulatedSurfaceFromGDI(RECT Rect);
HRESULT CopyEmulatedSurfaceToGDI(RECT Rect);
HRESULT PresentWindowedSurface(RECT Rect);

// Surface functions
void ClearDirtyFlags();
Expand Down
10 changes: 5 additions & 5 deletions ddraw/IDirectDrawX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2625,7 +2625,7 @@ void m_IDirectDrawX::GetSurfaceDisplay(DWORD& Width, DWORD& Height, DWORD& BPP,
RefreshRate = DisplayMode.RefreshRate;
BPP = DisplayMode.BPP;
}
else if (d3d9Device && !(Device.IsWindowed && Config.DdrawWriteToGDI))
else if (d3d9Device)
{
Width = presParams.BackBufferWidth;
Height = presParams.BackBufferHeight;
Expand All @@ -2643,7 +2643,7 @@ void m_IDirectDrawX::GetSurfaceDisplay(DWORD& Width, DWORD& Height, DWORD& BPP,
Height = surfaceHeight;
BPP = Utils::GetBitCount(hWnd);
}
else if (Device.IsWindowed && IsWindow(hWnd) && !Config.DdrawWriteToGDI)
else if (Device.IsWindowed && IsWindow(hWnd))
{
RECT Rect = {};
GetClientRect(hWnd, &Rect);
Expand Down Expand Up @@ -3592,7 +3592,7 @@ DWORD WINAPI PresentThreadFunction(LPVOID)
}

// Do d3d9 Present
HRESULT m_IDirectDrawX::Present()
HRESULT m_IDirectDrawX::Present(RECT* pSourceRect, RECT* pDestRect)
{
Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";

Expand Down Expand Up @@ -3651,9 +3651,9 @@ HRESULT m_IDirectDrawX::Present()
// Present everthing, skip Preset when using DdrawWriteToGDI
HRESULT hr;
EnterCriticalSection(&PresentThread.ddpt);
if ((EnableWaitVsync && Config.EnableVSync) || !PresentThread.UsingMultpleCores)
if (pSourceRect || pDestRect || (EnableWaitVsync && Config.EnableVSync) || !PresentThread.UsingMultpleCores)
{
hr = d3d9Device->Present(nullptr, nullptr, nullptr, nullptr);
hr = d3d9Device->Present(pSourceRect, pDestRect, nullptr, nullptr);
EnableWaitVsync = (EnableWaitVsync && !Config.EnableVSync);
}
else
Expand Down
2 changes: 1 addition & 1 deletion ddraw/IDirectDrawX.h
Original file line number Diff line number Diff line change
Expand Up @@ -233,5 +233,5 @@ class m_IDirectDrawX : public IUnknown, public AddressLookupTableDdrawObject

// Begin & end scene
void SetVsync();
HRESULT Present();
HRESULT Present(RECT* pSourceRect, RECT* pDestRect);
};

0 comments on commit 84e47b5

Please sign in to comment.