Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
917d6d6
dkollmann May 14, 2023
e8ff88d
dkollmann May 16, 2023
17ba9b6
Fix comments from pull request
elishacloud May 17, 2023
dbc8e10
Don't override matrix memory, just the pointer
elishacloud May 17, 2023
14632ef
Fix disable lighting and a couple typos
elishacloud May 17, 2023
de8fcbc
Set transform if not set by game
elishacloud May 17, 2023
a0ddc3d
Remove RenderData
elishacloud May 17, 2023
c715c61
Fix default settings
elishacloud May 17, 2023
d7dff14
Fixed that DdrawConvertHomogeneousToWorldUseGameCamera did not actual…
dkollmann May 17, 2023
575bd6f
Remove unneeded matrix assignment
elishacloud May 18, 2023
44d4338
Fix DdrawConvertHomogeneousToWorldUseGameCamera
elishacloud May 18, 2023
f823ec3
Move matrix override code to the end
elishacloud May 18, 2023
e79c204
Fix DdrawConvertHomogeneousToWorldUseGameCamera
elishacloud Jun 6, 2023
153287c
Merge branch 'master' into reverse_xyzrhw_new
elishacloud Jun 20, 2023
1a8607e
Fix merge conflict with main
elishacloud Jun 20, 2023
f82ae80
Minor update
elishacloud Jun 20, 2023
80b12b0
Merge branch 'master' into reverse_xyzrhw_new
elishacloud Jun 26, 2023
fac874b
Fix formatting
elishacloud Jun 26, 2023
8b54596
Fix defaults
elishacloud Jun 26, 2023
48bdfec
Merge remote-tracking branch 'origin/master' into pr/199
elishacloud Jul 13, 2023
3ee34d4
Fix PR to work with master branch changes
elishacloud Jul 13, 2023
5e3d5e4
Merge remote-tracking branch 'origin/master' into pr/199
elishacloud Jul 13, 2023
0d9bb50
Update to make it match master branch
elishacloud Jul 13, 2023
58812be
Merge remote-tracking branch 'origin/master' into pr/199
elishacloud Jul 15, 2023
f5b307d
Merge remote-tracking branch 'origin/master' into pr/199
elishacloud Aug 14, 2023
1ab9a42
Merge branch 'master' into reverse_xyzrhw_new
elishacloud Dec 2, 2023
80dfe72
Include DirectXMath
elishacloud Mar 2, 2024
11e1db3
Merge branch 'master' into reverse_xyzrhw_new
elishacloud Mar 2, 2024
5dec4b8
Merge branch 'master' into reverse_xyzrhw_new
elishacloud Apr 4, 2024
9b92264
Merge branch 'master' into reverse_xyzrhw_new
elishacloud Apr 7, 2024
bf79a6a
Merge branch 'master' into reverse_xyzrhw_new
elishacloud Aug 22, 2024
e84f19c
Merge branch 'master' into reverse_xyzrhw_new
elishacloud Sep 17, 2024
917946e
Merge branch 'master' into reverse_xyzrhw_new
elishacloud Jan 16, 2025
e4bf42c
Merge branch 'master' into reverse_xyzrhw_new
elishacloud Feb 18, 2025
1ff2bc0
Fix issue with merging master branch
elishacloud Mar 4, 2025
6fe14d6
Merge remote-tracking branch 'origin/master' into pr/199
elishacloud Mar 31, 2025
5421628
Merge branch 'master' into reverse_xyzrhw_new
elishacloud Mar 31, 2025
9864712
Fix build merge issues
elishacloud Mar 31, 2025
69e9ae3
Merge branch 'master' into reverse_xyzrhw_new
elishacloud Jun 11, 2025
7c890df
Fix build issue
elishacloud Jun 11, 2025
0c8fb96
Merge branch 'master' into reverse_xyzrhw_new
elishacloud Jul 20, 2025
0c15505
Merge branch 'master' into reverse_xyzrhw_new
elishacloud Sep 29, 2025
e34127f
Fix build issue
elishacloud Sep 29, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Settings/AllSettings.ini
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,14 @@ DdrawOverrideHeight = 0
DdrawOverrideStencilFormat = 0
DdrawIntegerScalingClamp = 0
DdrawMaintainAspectRatio = 0
DdrawDisableLighting = 0
DdrawConvertHomogeneousW = 0
DdrawConvertHomogeneousToWorld = 0
DdrawConvertHomogeneousToWorldUseGameCamera = 0
DdrawConvertHomogeneousToWorldFOV = 90.0
DdrawConvertHomogeneousToWorldNearPlane = 1.0
DdrawConvertHomogeneousToWorldFarPlane = 1000.0
DdrawConvertHomogeneousToWorldDepthOffset = 0.0

[d3d9]
AnisotropicFiltering = 0
Expand Down
3 changes: 3 additions & 0 deletions Settings/Settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,9 @@ void Settings::SetDefaultConfigSettings()
Config.PrimaryBufferSamples = 44100;
Config.PrimaryBufferChannels = 2;
Config.AudioFadeOutDelayMS = 20;
Config.DdrawConvertHomogeneousToWorldFOV = 90.0f;
Config.DdrawConvertHomogeneousToWorldNearPlane = 1.0f;
Config.DdrawConvertHomogeneousToWorldFarPlane = 1000.0f;
SetValue("ExcludeProcess", "dxwnd.exe", &Config.ExcludeProcess);
SetValue("ExcludeProcess", "dgVoodooSetup.exe", &Config.ExcludeProcess);
}
Expand Down
16 changes: 16 additions & 0 deletions Settings/Settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,17 @@
visit(DdrawOverrideHeight) \
visit(DdrawOverrideStencilFormat) \
visit(DdrawResolutionHack) \
visit(DdrawConvertHomogeneousW) \
visit(DdrawConvertHomogeneousToWorld) \
visit(DdrawConvertHomogeneousToWorldUseGameCamera) \
visit(DdrawConvertHomogeneousToWorldFOV) \
visit(DdrawConvertHomogeneousToWorldNearPlane) \
visit(DdrawConvertHomogeneousToWorldFarPlane) \
visit(DdrawConvertHomogeneousToWorldDepthOffset) \
visit(DdrawUseDirect3D9Caps) \
visit(DdrawUseNativeResolution) \
visit(DdrawEnableMouseHook) \
visit(DdrawDisableLighting) \
visit(DdrawHookSystem32) \
visit(D3d8HookSystem32) \
visit(D3d9HookSystem32) \
Expand Down Expand Up @@ -251,6 +259,13 @@ struct CONFIG
bool DdrawWriteToGDI = false; // Blt surface directly to GDI rather than Direct3D9
bool DdrawIntegerScalingClamp = false; // Scales the screen by an integer value to help preserve video quality
bool DdrawMaintainAspectRatio = false; // Keeps the current DirectDraw aspect ratio when overriding the game's resolution
bool DdrawConvertHomogeneousW = false; // Convert primites using D3DFVF_XYZRHW to D3DFVF_XYZW.
bool DdrawConvertHomogeneousToWorld = false; // Convert primitives back into a world space. Needed for RTX.
bool DdrawConvertHomogeneousToWorldUseGameCamera = false; // Use the game's view matrix instead of replacing it with our own.
float DdrawConvertHomogeneousToWorldFOV = 0.0f; // The field of view of the camera used to reconstruct the original 3D world.
float DdrawConvertHomogeneousToWorldNearPlane = 0.0f; // The near plane of the camera used to reconstruct the original 3D world.
float DdrawConvertHomogeneousToWorldFarPlane = 0.0f; // The far plane of the camera used to reconstruct the original 3D world.
float DdrawConvertHomogeneousToWorldDepthOffset = 0.0f; // The offset to add to the geometry so it does not clip into the near plane.
bool DdrawUseDirect3D9Caps = false; // Use Direct3D9 (Dd7to9) for GetCaps
bool DdrawUseNativeResolution = false; // Uses the current screen resolution for Dd7to9
DWORD DdrawClippedWidth = 0; // Used to scaled Direct3d9 to use this width when using Dd7to9
Expand All @@ -269,6 +284,7 @@ struct CONFIG
DWORD DdrawFlipFillColor = 0; // Color used to fill the primary surface before flipping
bool DdrawForceMipMapAutoGen = false; // Force Direct3d9 to use this AutoStencilFormat when using Dd7to9
bool DdrawEnableMouseHook = false; // Allow to hook into mouse to limit it to the chosen resolution
bool DdrawDisableLighting = false; // Allow to disable lighting
DWORD DdrawHookSystem32 = 0; // Hooks the ddraw.dll file in the Windows System32 folder
DWORD D3d8HookSystem32 = 0; // Hooks the d3d8.dll file in the Windows System32 folder
DWORD D3d9HookSystem32 = 0; // Hooks the d3d9.dll file in the Windows System32 folder
Expand Down
229 changes: 222 additions & 7 deletions ddraw/IDirect3DDeviceX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2340,6 +2340,12 @@ HRESULT m_IDirect3DDeviceX::SetRenderState(D3DRENDERSTATETYPE dwRenderStateType,
LOG_LIMIT(100, __FUNCTION__ << " Warning: 'D3DRENDERSTATE_STIPPLEPATTERN00' not implemented! " << dwRenderState);
}
return D3D_OK;
case D3DRENDERSTATE_LIGHTING: // 137
if (Config.DdrawDisableLighting)
{
dwRenderState = FALSE;
}
break;
case D3DRENDERSTATE_EXTENTS: // 138
// ToDo: use this to enable/disable clip plane extents set by SetClipStatus()
DeviceStates.RenderState[dwRenderStateType].State = dwRenderState;
Expand Down Expand Up @@ -2559,17 +2565,122 @@ HRESULT m_IDirect3DDeviceX::SetTransform(D3DTRANSFORMSTATETYPE dtstTransformStat
break;
}

HRESULT hr = SetD9Transform(dtstTransformStateType, lpD3DMatrix);

if (SUCCEEDED(hr))
D3DMATRIX view;
if (Config.DdrawConvertHomogeneousW)
{
#ifdef ENABLE_DEBUGOVERLAY
if (Config.EnableImgui)
if (dtstTransformStateType == D3DTS_VIEW)
{
DOverlay.SetTransform(dtstTransformStateType, lpD3DMatrix);
D3DVIEWPORT9 Viewport9;
if (SUCCEEDED((*d3d9Device)->GetViewport(&Viewport9)))
{
const float width = (float)Viewport9.Width;
const float height = (float)Viewport9.Height;

// Replace the matrix with one that handles D3DFVF_XYZRHW geometry
ZeroMemory(&view, sizeof(D3DMATRIX));
view._11 = 2.0f / width;
view._22 = -2.0f / height;
view._33 = 1.0f;
view._41 = -1.0f; // translate X
view._42 = 1.0f; // translate Y
view._44 = 1.0f;

// Set flag
ConvertHomogeneous.IsTransformViewSet = true;

if (Config.DdrawConvertHomogeneousToWorld)
{
DirectX::XMVECTOR position, direction;
float depthOffset = 0.0f;
if (Config.DdrawConvertHomogeneousToWorldUseGameCamera)
{
// To reconstruct the 3D world, we need to know where the camera is and where it is looking
position = DirectX::XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f);

const float x = lpD3DMatrix->_11;
const float y = lpD3DMatrix->_12;
const float z = lpD3DMatrix->_13;

float pitch = std::atan2(y, z);
if (pitch < 0.0f && y * z > 0.0f) // check if y and z have the same sign
{
// handle flipping of the pitch. This is not because the camera is looking up.
pitch += DirectX::XM_PI;
}

float yaw = std::asin(x);
if (yaw < 0.0f)
{
yaw += DirectX::XM_2PI;
}

// mirror the transform
float pitchneg = -pitch;

float pitch_cos = std::cos(pitchneg);
float x2 = 0.0f; //std::cos(yaw) * pitch_cos;
float y2 = std::sin(pitchneg);
float z2 = /*std::sin(yaw) **/ pitch_cos;

direction = DirectX::XMVectorSet(x2, y2, z2, 0.0f);

depthOffset = Config.DdrawConvertHomogeneousToWorldDepthOffset;

ConvertHomogeneous.ToWorld_GameCameraYaw = yaw;
ConvertHomogeneous.ToWorld_GameCameraPitch = pitch;
}
else
{
position = DirectX::XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f);
direction = DirectX::XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f);
}

// Store the original matrix so it can be restored
ConvertHomogeneous.ToWorld_ViewMatrixOriginal = view;

// The Black & White matrix is an ortho camera, so create a perspective one matching the game
const float fov = Config.DdrawConvertHomogeneousToWorldFOV;
const float nearplane = Config.DdrawConvertHomogeneousToWorldNearPlane;
const float farplane = Config.DdrawConvertHomogeneousToWorldFarPlane;
const float ratio = width / height;
DirectX::XMMATRIX proj = DirectX::XMMatrixPerspectiveFovLH(fov * (3.14159265359f / 180.0f), ratio, nearplane, farplane);

DirectX::XMStoreFloat4x4((DirectX::XMFLOAT4X4*)&ConvertHomogeneous.ToWorld_ProjectionMatrix, proj);

DirectX::XMVECTOR upVector = DirectX::XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
DirectX::XMMATRIX viewMatrix = DirectX::XMMatrixLookToLH(position, direction, upVector);

// Store the 3D view matrix so it can be set later
DirectX::XMStoreFloat4x4((DirectX::XMFLOAT4X4*)&ConvertHomogeneous.ToWorld_ViewMatrix, viewMatrix);

// Store the view inverse matrix of the game, so we can transform the geometry with it
DirectX::XMMATRIX toViewSpace = DirectX::XMLoadFloat4x4((DirectX::XMFLOAT4X4*)&view);
DirectX::XMMATRIX vp = DirectX::XMMatrixMultiply(viewMatrix, proj);
DirectX::XMMATRIX vpinv = DirectX::XMMatrixInverse(nullptr, vp);

DirectX::XMMATRIX depthoffset = DirectX::XMMatrixTranslation(0.0f, 0.0f, depthOffset);

ConvertHomogeneous.ToWorld_ViewMatrixInverse = DirectX::XMMatrixMultiply(depthoffset, DirectX::XMMatrixMultiply(toViewSpace, vpinv));
}

// Override original matrix pointer
lpD3DMatrix = &view;
}
}
#endif
else
{
return D3D_OK;
}
}

HRESULT hr = SetD9Transform(dtstTransformStateType, lpD3DMatrix);

#ifdef ENABLE_DEBUGOVERLAY
if (SUCCEEDED(hr) && !Config.DdrawConvertHomogeneousW)
{
DOverlay.SetTransform(dtstTransformStateType, lpD3DMatrix);
}
#endif

return hr;
}
Expand Down Expand Up @@ -2826,6 +2937,103 @@ HRESULT m_IDirect3DDeviceX::DrawIndexedPrimitive(D3DPRIMITIVETYPE dptPrimitiveTy
// Update vertices for Direct3D9 (needs to be first)
UpdateVertices(dwVertexTypeDesc, lpVertices, 0, dwVertexCount);

// Handle PositionT
if (Config.DdrawConvertHomogeneousW && (dwVertexTypeDesc & 0x0E) == D3DFVF_XYZRHW)
{
if (!ConvertHomogeneous.IsTransformViewSet)
{
D3DMATRIX Matrix = {};
GetTransform(D3DTS_VIEW, &Matrix);
SetTransform(D3DTS_VIEW, &Matrix);
}

if (!Config.DdrawConvertHomogeneousToWorld)
{
/*UINT8 *vertex = (UINT8*)lpVertices;
for (UINT x = 0; x < dwVertexCount; x++)
{
float *pos = (float*) vertex;
pos[3] = 1.0f;
vertex += stride;
}*/

// Update the FVF
dwVertexTypeDesc = (dwVertexTypeDesc & ~D3DFVF_XYZRHW) | D3DFVF_XYZW;
}
else
{
const UINT stride = GetVertexStride(dwVertexTypeDesc);

const UINT targetStride = stride - sizeof(float);
const UINT restSize = stride - sizeof(float) * 4;

ConvertHomogeneous.ToWorld_IntermediateGeometry.resize(targetStride * dwVertexCount);

UINT8* sourceVertex = (UINT8*)lpVertices;
UINT8* targetVertex = (UINT8*)ConvertHomogeneous.ToWorld_IntermediateGeometry.data();

lpVertices = targetVertex;

for (UINT x = 0; x < dwVertexCount; x++)
{
// Transform the vertices into world space
float* srcpos = (float*)sourceVertex;
float* trgtpos = (float*)targetVertex;

DirectX::XMVECTOR xpos = DirectX::XMVectorSet(srcpos[0], srcpos[1], srcpos[2], srcpos[3]);

DirectX::XMVECTOR xpos_global = DirectX::XMVector3TransformCoord(xpos, ConvertHomogeneous.ToWorld_ViewMatrixInverse);

xpos_global = DirectX::XMVectorDivide(xpos_global, DirectX::XMVectorSplatW(xpos_global));

trgtpos[0] = DirectX::XMVectorGetX(xpos_global);
trgtpos[1] = DirectX::XMVectorGetY(xpos_global);
trgtpos[2] = DirectX::XMVectorGetZ(xpos_global);

// Copy the rest
std::memcpy(targetVertex + sizeof(float) * 3, sourceVertex + sizeof(float) * 4, restSize);

// Move to next vertex
sourceVertex += stride;
targetVertex += targetStride;
}

// Set transform
(*d3d9Device)->SetTransform(D3DTS_VIEW, &ConvertHomogeneous.ToWorld_ViewMatrix);
(*d3d9Device)->SetTransform(D3DTS_PROJECTION, &ConvertHomogeneous.ToWorld_ProjectionMatrix);

// Update the FVF
const DWORD newVertexTypeDesc = (dwVertexTypeDesc & ~D3DFVF_XYZRHW) | D3DFVF_XYZ;

// Set fixed function vertex type
if (FAILED((*d3d9Device)->SetFVF(newVertexTypeDesc)))
{
LOG_LIMIT(100, __FUNCTION__ << " Error: invalid FVF type: " << Logging::hex(dwVertexTypeDesc));
return D3DERR_INVALIDVERTEXTYPE;
}

// Handle dwFlags
SetDrawStates(newVertexTypeDesc, dwFlags, DirectXVersion);

// Draw indexed primitive UP
HRESULT hr = (*d3d9Device)->DrawIndexedPrimitiveUP(dptPrimitiveType, 0, dwVertexCount, GetNumberOfPrimitives(dptPrimitiveType, dwIndexCount), lpwIndices, D3DFMT_INDEX16, lpVertices, targetStride);

// Handle dwFlags
RestoreDrawStates(newVertexTypeDesc, dwFlags);

// Restore transform
D3DMATRIX identityMatrix = {};
identityMatrix._11 = 1.0f;
identityMatrix._22 = 1.0f;
identityMatrix._33 = 1.0f;

(*d3d9Device)->SetTransform(D3DTS_VIEW, &ConvertHomogeneous.ToWorld_ViewMatrixOriginal);
(*d3d9Device)->SetTransform(D3DTS_PROJECTION, &identityMatrix);

return hr;
}
}

// Set fixed function vertex type
if (FAILED((*d3d9Device)->SetFVF(dwVertexTypeDesc)))
{
Expand Down Expand Up @@ -5972,6 +6180,10 @@ void m_IDirect3DDeviceX::PrepDevice()
{
(*d3d9Device)->SetTransform(entry.first, &entry.second);
}
if (Config.DdrawDisableLighting)
{
(*d3d9Device)->SetRenderState(D3DRS_LIGHTING, FALSE);
}
}
}

Expand Down Expand Up @@ -6095,6 +6307,9 @@ void m_IDirect3DDeviceX::SetDefaults()
bSetDefaults = false;
RequiresStateRestore = true;

// Reset Homogeneous flag
ConvertHomogeneous.IsTransformViewSet = false;

// Render states
if (ClientDirectXVersion > 1)
{
Expand Down
3 changes: 3 additions & 0 deletions ddraw/IDirect3DDeviceX.h
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,9 @@ class m_IDirect3DDeviceX : public IUnknown, public AddressLookupTableDdrawObject
// Vector temporary buffer cache
std::vector<BYTE, aligned_allocator<BYTE, 4>> VertexCache;

// The data used for rendering Homogeneous
CONVERTHOMOGENEOUS ConvertHomogeneous;

// Viewport array
std::vector<LPDIRECT3DVIEWPORT3> AttachedViewports;

Expand Down
12 changes: 12 additions & 0 deletions ddraw/IDirect3DTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,18 @@ typedef enum _D3DSURFACETYPE {
D3DTYPE_DEPTHSTENCIL = 4
} D3DSURFACETYPE;

struct CONVERTHOMOGENEOUS
{
bool IsTransformViewSet = false; // Remembers if game sets the view matrix
D3DMATRIX ToWorld_ProjectionMatrix; // Store the projection matrix used to transform the geometry on the gpu
D3DMATRIX ToWorld_ViewMatrix; // Store the view matrix used to transform the geometry on the gpu
D3DMATRIX ToWorld_ViewMatrixOriginal; // Store the original view matrix, so we can restore it
DirectX::XMMATRIX ToWorld_ViewMatrixInverse; // Store the inverse view matrix to transform the geometry on the cpu
std::vector<uint8_t> ToWorld_IntermediateGeometry; // Intermediate buffer for the geometry conversion
float ToWorld_GameCameraYaw = 0.0f;
float ToWorld_GameCameraPitch = 0.0f;
};

#define CLAMP(val,zmin,zmax) (max((zmin),min((zmax),(val))))

// Clamp rhw values
Expand Down
Loading