Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for transforming homogenous W geometry into world geomtry #199

Open
wants to merge 32 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
917d6d6
Added support for transforming homogenous W geometry into world geome…
dkollmann May 14, 2023
e8ff88d
Fixed incorrect game camera position and orientation. Added option to…
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
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
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,6 @@
[submodule "External/imgui"]
path = External/imgui
url = https://github.com/ocornut/imgui
[submodule "External/DirectXMath"]
path = External/DirectXMath
url = https://github.com/microsoft/DirectXMath
1 change: 1 addition & 0 deletions External/DirectXMath
Submodule DirectXMath added at d83757
8 changes: 8 additions & 0 deletions Settings/AllSettings.ini
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,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 @@ -470,6 +470,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 @@ -47,8 +47,16 @@
visit(DdrawOverrideStencilFormat) \
visit(DdrawResolutionHack) \
visit(DdrawUseDirect3D9Ex) \
visit(DdrawConvertHomogeneousW) \
visit(DdrawConvertHomogeneousToWorld) \
visit(DdrawConvertHomogeneousToWorldUseGameCamera) \
visit(DdrawConvertHomogeneousToWorldFOV) \
visit(DdrawConvertHomogeneousToWorldNearPlane) \
visit(DdrawConvertHomogeneousToWorldFarPlane) \
visit(DdrawConvertHomogeneousToWorldDepthOffset) \
visit(DdrawUseNativeResolution) \
visit(DdrawEnableMouseHook) \
visit(DdrawDisableLighting) \
visit(DdrawHookSystem32) \
visit(D3d8HookSystem32) \
visit(D3d9HookSystem32) \
Expand Down Expand Up @@ -224,6 +232,13 @@ struct CONFIG
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 DdrawUseDirect3D9Ex = false; // Use Direct3D9Ex extensions for Dd7to9
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 DdrawUseNativeResolution = false; // Uses the current screen resolution for Dd7to9
DWORD DdrawClippedWidth = 0; // Used to scaled Direct3d9 to use this width when using Dd7to9
DWORD DdrawClippedHeight = 0; // Used to scaled Direct3d9 to use this height when using Dd7to9
Expand All @@ -239,6 +254,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
244 changes: 241 additions & 3 deletions ddraw/IDirect3DDeviceX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -342,17 +342,129 @@ HRESULT m_IDirect3DDeviceX::SetTransform(D3DTRANSFORMSTATETYPE dtstTransformStat
break;
}

HRESULT hr = (*d3d9Device)->SetTransform(dtstTransformStateType, lpD3DMatrix);

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

if (dtstTransformStateType == D3DTS_VIEW)
{
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;
elishacloud marked this conversation as resolved.
Show resolved Hide resolved

// 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));
}
elishacloud marked this conversation as resolved.
Show resolved Hide resolved

// Override original matrix pointer
lpD3DMatrix = &view;
}
}
else
{
return D3D_OK;
elishacloud marked this conversation as resolved.
Show resolved Hide resolved
}
}

HRESULT hr = (*d3d9Device)->SetTransform(dtstTransformStateType, lpD3DMatrix);

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

return hr;
}
Expand Down Expand Up @@ -1836,6 +1948,11 @@ HRESULT m_IDirect3DDeviceX::BeginScene()

HRESULT hr = (*d3d9Device)->BeginScene();

if (Config.DdrawDisableLighting)
{
(*d3d9Device)->SetRenderState(D3DRS_LIGHTING, FALSE);
}

if (SUCCEEDED(hr))
{
IsInScene = true;
Expand Down Expand Up @@ -2969,6 +3086,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()
if (dwRenderState != FALSE)
Expand Down Expand Up @@ -3521,6 +3644,106 @@ HRESULT m_IDirect3DDeviceX::DrawIndexedPrimitive(D3DPRIMITIVETYPE dptPrimitiveTy

dwFlags = (dwFlags & D3DDP_FORCE_DWORD);

// 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);

elishacloud marked this conversation as resolved.
Show resolved Hide resolved
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), lpIndices, D3DFMT_INDEX16, lpVertices, targetStride);

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

// 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;
}
}

// Update vertices for Direct3D9 (needs to be first)
UpdateVertices(dwVertexTypeDesc, lpVertices, dwVertexCount);

Expand Down Expand Up @@ -4183,6 +4406,18 @@ void m_IDirect3DDeviceX::InitDevice(DWORD DirectXVersion)
}
}

if (Config.DdrawConvertHomogeneousW)
{
ZeroMemory(&ConvertHomogeneous.ToWorld_ViewMatrix, sizeof(D3DMATRIX));
ConvertHomogeneous.ToWorld_ViewMatrix._11 = 1.0f;
ConvertHomogeneous.ToWorld_ViewMatrix._22 = 1.0f;
ConvertHomogeneous.ToWorld_ViewMatrix._33 = 1.0f;
ConvertHomogeneous.ToWorld_ViewMatrix._44 = 1.0f;

ConvertHomogeneous.ToWorld_ProjectionMatrix = ConvertHomogeneous.ToWorld_ViewMatrix;
ConvertHomogeneous.ToWorld_ViewMatrixOriginal = ConvertHomogeneous.ToWorld_ViewMatrix;
}

AddRef(DirectXVersion);
}

Expand Down Expand Up @@ -4244,6 +4479,9 @@ void m_IDirect3DDeviceX::ResetDevice()

void m_IDirect3DDeviceX::SetDefaults()
{
// Reset flags
ConvertHomogeneous.IsTransformViewSet = false;

// Reset defaults flag
bSetDefaults = false;

Expand Down
16 changes: 16 additions & 0 deletions ddraw/IDirect3DDeviceX.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
#pragma once

#include <unordered_map>
#include "External\DirectXMath\Inc\DirectXMath.h"

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;
};

class m_IDirect3DDeviceX : public IUnknown, public AddressLookupTableDdrawObject
{
Expand Down Expand Up @@ -91,6 +104,9 @@ class m_IDirect3DDeviceX : public IUnknown, public AddressLookupTableDdrawObject
// Vector temporary buffer cache
std::vector<BYTE> VertexCache;

// The data used for rendering Homogeneous
CONVERTHOMOGENEOUS ConvertHomogeneous;

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

Expand Down
Loading
Loading