Skip to content

Commit 917d6d6

Browse files
committed
Added support for transforming homogenous W geometry into world geometry.
1 parent df92fd0 commit 917d6d6

File tree

8 files changed

+245
-9
lines changed

8 files changed

+245
-9
lines changed

Settings/Settings.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,13 @@
4343
visit(DdrawOverrideStencilFormat) \
4444
visit(DdrawResolutionHack) \
4545
visit(DdrawUseDirect3D9Ex) \
46+
visit(DdrawConvertHomogeneousW) \
47+
visit(DdrawConvertHomogeneousToWorld) \
48+
visit(DdrawConvertHomogeneousToWorldUseGameCamera) \
49+
visit(DdrawConvertHomogeneousToWorldFOV) \
50+
visit(DdrawConvertHomogeneousToWorldNearPlane) \
51+
visit(DdrawConvertHomogeneousToWorldFarPlane) \
52+
visit(DdrawConvertHomogeneousToWorldDepthOffset) \
4653
visit(DdrawUseNativeResolution) \
4754
visit(DdrawEnableMouseHook) \
4855
visit(DdrawHookSystem32) \
@@ -209,6 +216,13 @@ struct CONFIG
209216
bool DdrawIntegerScalingClamp = false; // Scales the screen by an integer value to help preserve video quality
210217
bool DdrawMaintainAspectRatio = false; // Keeps the current DirectDraw aspect ratio when overriding the game's resolution
211218
bool DdrawUseDirect3D9Ex = false; // Use Direct3D9Ex extensions for Dd7to9
219+
bool DdrawConvertHomogeneousW = false; // Convert primites using D3DFVF_XYZRHW to D3DFVF_XYZW.
220+
bool DdrawConvertHomogeneousToWorld = false; // Convert primitives back into a world space. Needed for RTX.
221+
bool DdrawConvertHomogeneousToWorldUseGameCamera = false; // Use the game's view matrix instead of replacing it with our own.
222+
float DdrawConvertHomogeneousToWorldFOV = 90.0f; // The field of view of the camera used to reconstruct the original 3D world.
223+
float DdrawConvertHomogeneousToWorldNearPlane = 1.0f; // The near plane of the camera used to reconstruct the original 3D world.
224+
float DdrawConvertHomogeneousToWorldFarPlane = 1000.0f; // The far plane of the camera used to reconstruct the original 3D world.
225+
float DdrawConvertHomogeneousToWorldDepthOffset = 0.0f; // The offset to add to the geometry so it does not clip into the near plane.
212226
bool DdrawUseNativeResolution = false; // Uses the current screen resolution for Dd7to9
213227
DWORD DdrawClippedWidth = 0; // Used to scaled Direct3d9 to use this width when using Dd7to9
214228
DWORD DdrawClippedHeight = 0; // Used to scaled Direct3d9 to use this height when using Dd7to9

ddraw/DebugOverlay.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616

1717
#include "DebugOverlay.h"
18+
#include "RenderData.h"
1819
#include <sstream>
1920

2021
#define IMGUI_DEFINE_MATH_OPERATORS
@@ -98,7 +99,7 @@ void DebugOverlay::BeginScene()
9899
ImGui::NewFrame();
99100
}
100101

101-
void DebugOverlay::EndScene()
102+
void DebugOverlay::EndScene(const RenderData &RenderData)
102103
{
103104
static bool ShowDebugUI = false;
104105
if (ImGui::IsKeyDown(ImGui::GetKeyIndex(ImGuiKey_LeftAlt)) &&

ddraw/DebugOverlay.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ class DebugOverlay
4848

4949
// Frame functions
5050
void BeginScene();
51-
void EndScene();
51+
void EndScene(const class RenderData &RenderData);
5252

5353
// Functions
5454
void SetTransform(D3DTRANSFORMSTATETYPE dtstTransformStateType, LPD3DMATRIX lpD3DMatrix);

ddraw/IDirect3DDeviceX.cpp

Lines changed: 182 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@
1616

1717
#include "ddraw.h"
1818
#include <d3dhal.h>
19+
#include <DirectXMath.h>
1920

2021
// Enable for testing only
21-
//#define ENABLE_DEBUGOVERLAY
22+
#define ENABLE_DEBUGOVERLAY
2223

2324
#ifdef ENABLE_DEBUGOVERLAY
2425
#include "DebugOverlay.h"
@@ -338,15 +339,103 @@ HRESULT m_IDirect3DDeviceX::SetTransform(D3DTRANSFORMSTATETYPE dtstTransformStat
338339
break;
339340
}
340341

341-
HRESULT hr = (*d3d9Device)->SetTransform(dtstTransformStateType, lpD3DMatrix);
342-
343-
if (SUCCEEDED(hr))
342+
if(Config.DdrawConvertHomogeneousW)
344343
{
345344
#ifdef ENABLE_DEBUGOVERLAY
345+
// Set the original matrix
346346
DOverlay.SetTransform(dtstTransformStateType, lpD3DMatrix);
347347
#endif
348+
349+
if(dtstTransformStateType == D3DTS_VIEW)
350+
{
351+
D3DVIEWPORT9 Viewport9;
352+
if(SUCCEEDED((*d3d9Device)->GetViewport(&Viewport9)))
353+
{
354+
const float width = (float)Viewport9.Width;
355+
const float height = (float)Viewport9.Height;
356+
const float ratio = width / height;
357+
358+
// Replace the matrix with one that handles D3DFVF_XYZRHW geometry
359+
_D3DMATRIX view;
360+
ZeroMemory(&view, sizeof(_D3DMATRIX));
361+
view._11 = 2.0f / width;
362+
view._22 = -2.0f / height;
363+
view._33 = 1.0f;
364+
view._41 = -1.0f; // translate X
365+
view._42 = 1.0f; // translate Y
366+
view._44 = 1.0f;
367+
368+
if(!Config.DdrawConvertHomogeneousToWorld)
369+
{
370+
// Override the original matrix
371+
std::memcpy(lpD3DMatrix, &view, sizeof(_D3DMATRIX));
372+
}
373+
else
374+
{
375+
// Override the original matrix
376+
std::memcpy(lpD3DMatrix, &view, sizeof(_D3DMATRIX));
377+
378+
// Store the original matrix so it can be restored
379+
std::memcpy(&RenderData.DdrawConvertHomogeneousToWorld_ViewMatrixOriginal, &view, sizeof(_D3DMATRIX));
380+
381+
// The Black & White matrix is an ortho camera, so create a perspective one matching the game
382+
const float fov = Config.DdrawConvertHomogeneousToWorldFOV;
383+
const float nearplane = Config.DdrawConvertHomogeneousToWorldNearPlane;
384+
const float farplane = Config.DdrawConvertHomogeneousToWorldFarPlane;
385+
DirectX::XMMATRIX proj = DirectX::XMMatrixPerspectiveFovLH(fov * (3.14159265359f / 180.0f), ratio, nearplane, farplane);
386+
387+
DirectX::XMStoreFloat4x4((DirectX::XMFLOAT4X4*)&RenderData.DdrawConvertHomogeneousToWorld_ProjectionMatrix, proj);
388+
389+
DirectX::XMVECTOR up = DirectX::XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
390+
391+
DirectX::XMMATRIX viewMatrix;
392+
if(Config.DdrawConvertHomogeneousToWorldUseGameCamera)
393+
{
394+
// To reconstruct the 3D world, we need to know where the camera is and where it is looking
395+
DirectX::XMVECTOR position = DirectX::XMVectorSet(lpD3DMatrix->_41, lpD3DMatrix->_42, lpD3DMatrix->_43, lpD3DMatrix->_44);
396+
DirectX::XMVECTOR direction = DirectX::XMVectorSet(lpD3DMatrix->_31, lpD3DMatrix->_32, lpD3DMatrix->_33, lpD3DMatrix->_34);
397+
398+
viewMatrix = DirectX::XMMatrixLookToLH(position, direction, up);
399+
}
400+
else
401+
{
402+
const float cameradir = 1.0f;
403+
404+
DirectX::XMVECTOR pos = DirectX::XMVectorSet(0.0f, 0.0f, -cameradir, 0.0f);
405+
DirectX::XMVECTOR direction = DirectX::XMVectorSet(0.0f, 0.0f, cameradir, 0.0f);
406+
407+
viewMatrix = DirectX::XMMatrixLookToLH(pos, direction, up);
408+
}
409+
410+
// Store the 3D view matrix so it can be set later
411+
DirectX::XMStoreFloat4x4((DirectX::XMFLOAT4X4*)&RenderData.DdrawConvertHomogeneousToWorld_ViewMatrix, viewMatrix);
412+
413+
// Store the view inverse matrix of the game, so we can transform the geometry with it
414+
DirectX::XMMATRIX toViewSpace = DirectX::XMLoadFloat4x4((DirectX::XMFLOAT4X4*)lpD3DMatrix);
415+
DirectX::XMMATRIX vp = DirectX::XMMatrixMultiply(viewMatrix, proj);
416+
DirectX::XMMATRIX vpinv = DirectX::XMMatrixInverse(nullptr, vp);
417+
418+
DirectX::XMMATRIX depthoffset = DirectX::XMMatrixTranslation(0.0f, 0.0f, Config.DdrawConvertHomogeneousToWorldDepthOffset);
419+
420+
RenderData.DdrawConvertHomogeneousToWorld_ViewMatrixInverse = DirectX::XMMatrixMultiply(depthoffset, DirectX::XMMatrixMultiply(toViewSpace, vpinv));
421+
}
422+
}
423+
}
424+
else
425+
{
426+
return D3D_OK;
427+
}
348428
}
349429

430+
HRESULT hr = (*d3d9Device)->SetTransform(dtstTransformStateType, lpD3DMatrix);
431+
432+
#ifdef ENABLE_DEBUGOVERLAY
433+
if (SUCCEEDED(hr) && !Config.DdrawConvertHomogeneousW)
434+
{
435+
DOverlay.SetTransform(dtstTransformStateType, lpD3DMatrix);
436+
}
437+
#endif
438+
350439
return hr;
351440
}
352441

@@ -1617,7 +1706,7 @@ HRESULT m_IDirect3DDeviceX::EndScene()
16171706
}
16181707

16191708
#ifdef ENABLE_DEBUGOVERLAY
1620-
DOverlay.EndScene();
1709+
DOverlay.EndScene(RenderData);
16211710
#endif
16221711

16231712
// The IDirect3DDevice7::EndScene method ends a scene that was begun by calling the IDirect3DDevice7::BeginScene method.
@@ -2453,11 +2542,98 @@ HRESULT m_IDirect3DDeviceX::DrawIndexedPrimitive(D3DPRIMITIVETYPE dptPrimitiveTy
24532542
}
24542543
else
24552544
{
2545+
const UINT stride = GetVertexStride(dwVertexTypeDesc);
2546+
2547+
// Handle PositionT
2548+
if((dwVertexTypeDesc & D3DFVF_XYZRHW) != 0 && Config.DdrawConvertHomogeneousW)
2549+
{
2550+
if(!Config.DdrawConvertHomogeneousToWorld)
2551+
{
2552+
UINT8 *vertex = (UINT8*)lpVertices;
2553+
2554+
for (UINT x = 0; x < dwVertexCount; x++)
2555+
{
2556+
float *pos = (float*) vertex;
2557+
2558+
pos[3] = 1.0f;
2559+
2560+
vertex += stride;
2561+
}
2562+
2563+
// Update the FVF
2564+
dwVertexTypeDesc = (dwVertexTypeDesc & ~D3DFVF_XYZRHW) | D3DFVF_XYZW;
2565+
}
2566+
else
2567+
{
2568+
const UINT newstride = stride - sizeof(float);
2569+
const UINT restSize = stride - sizeof(float) * 4;
2570+
2571+
RenderData.DdrawConvertHomogeneousToWorld_IntermediateGeometry.resize(newstride * dwVertexCount);
2572+
2573+
UINT8 *sourceVertex = (UINT8*)lpVertices;
2574+
UINT8 *targetVertex = (UINT8*)RenderData.DdrawConvertHomogeneousToWorld_IntermediateGeometry.data();
2575+
2576+
lpVertices = targetVertex;
2577+
2578+
for (UINT x = 0; x < dwVertexCount; x++)
2579+
{
2580+
// Transform the vertices into world space
2581+
float *srcpos = (float*) sourceVertex;
2582+
float *trgtpos = (float*) targetVertex;
2583+
2584+
DirectX::XMVECTOR xpos = DirectX::XMVectorSet(srcpos[0], srcpos[1], srcpos[2], srcpos[3]);
2585+
2586+
DirectX::XMVECTOR xpos_global = DirectX::XMVector3TransformCoord(xpos, RenderData.DdrawConvertHomogeneousToWorld_ViewMatrixInverse);
2587+
2588+
xpos_global = DirectX::XMVectorDivide(xpos_global, DirectX::XMVectorSplatW(xpos_global));
2589+
2590+
trgtpos[0] = DirectX::XMVectorGetX(xpos_global);
2591+
trgtpos[1] = DirectX::XMVectorGetY(xpos_global);
2592+
trgtpos[2] = DirectX::XMVectorGetZ(xpos_global);
2593+
2594+
// Copy the rest
2595+
std::memcpy(targetVertex + sizeof(float) * 3, sourceVertex + sizeof(float) * 4, restSize);
2596+
2597+
// Move to next vertex
2598+
sourceVertex += stride;
2599+
targetVertex += newstride;
2600+
}
2601+
2602+
// Set transform
2603+
(*d3d9Device)->SetTransform(D3DTS_VIEW, &RenderData.DdrawConvertHomogeneousToWorld_ViewMatrix);
2604+
(*d3d9Device)->SetTransform(D3DTS_PROJECTION, &RenderData.DdrawConvertHomogeneousToWorld_ProjectionMatrix);
2605+
2606+
// Update the FVF
2607+
const DWORD newVertexTypeDesc = (dwVertexTypeDesc & ~D3DFVF_XYZRHW) | D3DFVF_XYZ;
2608+
2609+
// Set fixed function vertex type
2610+
(*d3d9Device)->SetFVF(newVertexTypeDesc);
2611+
2612+
// Draw indexed primitive UP
2613+
hr = (*d3d9Device)->DrawIndexedPrimitiveUP(dptPrimitiveType, 0, dwVertexCount, GetNumberOfPrimitives(dptPrimitiveType, dwIndexCount), lpIndices, D3DFMT_INDEX16, lpVertices, newstride);
2614+
2615+
// Restore transform
2616+
_D3DMATRIX identityMatrix;
2617+
ZeroMemory(&identityMatrix, sizeof(_D3DMATRIX));
2618+
identityMatrix._11 = 1.0f;
2619+
identityMatrix._22 = 1.0f;
2620+
identityMatrix._33 = 1.0f;
2621+
2622+
(*d3d9Device)->SetTransform(D3DTS_VIEW, &RenderData.DdrawConvertHomogeneousToWorld_ViewMatrixOriginal);
2623+
(*d3d9Device)->SetTransform(D3DTS_PROJECTION, &identityMatrix);
2624+
2625+
// Handle dwFlags
2626+
UnSetDrawFlags(rsClipping, rsLighting, rsExtents, newVertexTypeDesc, dwFlags, DirectXVersion);
2627+
2628+
return hr;
2629+
}
2630+
}
2631+
24562632
// Set fixed function vertex type
24572633
(*d3d9Device)->SetFVF(dwVertexTypeDesc);
24582634

24592635
// Draw indexed primitive UP
2460-
hr = (*d3d9Device)->DrawIndexedPrimitiveUP(dptPrimitiveType, 0, dwVertexCount, GetNumberOfPrimitives(dptPrimitiveType, dwIndexCount), lpIndices, D3DFMT_INDEX16, lpVertices, GetVertexStride(dwVertexTypeDesc));
2636+
hr = (*d3d9Device)->DrawIndexedPrimitiveUP(dptPrimitiveType, 0, dwVertexCount, GetNumberOfPrimitives(dptPrimitiveType, dwIndexCount), lpIndices, D3DFMT_INDEX16, lpVertices, stride);
24612637
}
24622638

24632639
// Handle dwFlags

ddraw/IDirect3DDeviceX.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22

33
#include "IDirectDrawX.h"
4+
#include "RenderData.h"
45

56
class m_IDirect3DDeviceX : public IUnknown, public AddressLookupTableDdrawObject
67
{
@@ -27,6 +28,9 @@ class m_IDirect3DDeviceX : public IUnknown, public AddressLookupTableDdrawObject
2728
// SetTexture array
2829
LPDIRECTDRAWSURFACE7 AttachedTexture[8] = {};
2930

31+
// The data used for rendering
32+
RenderData RenderData;
33+
3034
// Wrapper interface functions
3135
inline REFIID GetWrapperType(DWORD DirectXVersion)
3236
{

ddraw/RenderData.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#pragma once
2+
3+
#include <d3d9types.h>
4+
#include <DirectXMath.h>
5+
#include <vector>
6+
7+
class RenderData
8+
{
9+
public:
10+
11+
// Store the projection matrix used to transform the geometry on the gpu
12+
_D3DMATRIX DdrawConvertHomogeneousToWorld_ProjectionMatrix;
13+
14+
// Store the view matrix used to transform the geometry on the gpu
15+
_D3DMATRIX DdrawConvertHomogeneousToWorld_ViewMatrix;
16+
17+
// Store the original view matrix, so we can restore it
18+
_D3DMATRIX DdrawConvertHomogeneousToWorld_ViewMatrixOriginal;
19+
20+
// Store the inverse view matrix to transform the geometry on the cpu
21+
DirectX::XMMATRIX DdrawConvertHomogeneousToWorld_ViewMatrixInverse;
22+
23+
// Intermediate buffer for the geometry conversion
24+
std::vector<uint8_t> DdrawConvertHomogeneousToWorld_IntermediateGeometry;
25+
26+
RenderData()
27+
{
28+
ZeroMemory(&DdrawConvertHomogeneousToWorld_ViewMatrix, sizeof(_D3DMATRIX));
29+
DdrawConvertHomogeneousToWorld_ViewMatrix._11 = 1.0f;
30+
DdrawConvertHomogeneousToWorld_ViewMatrix._22 = 1.0f;
31+
DdrawConvertHomogeneousToWorld_ViewMatrix._33 = 1.0f;
32+
DdrawConvertHomogeneousToWorld_ViewMatrix._44 = 1.0f;
33+
34+
std::memcpy(&DdrawConvertHomogeneousToWorld_ProjectionMatrix, &DdrawConvertHomogeneousToWorld_ViewMatrix, sizeof(_D3DMATRIX));
35+
std::memcpy(&DdrawConvertHomogeneousToWorld_ViewMatrixOriginal, &DdrawConvertHomogeneousToWorld_ViewMatrix, sizeof(_D3DMATRIX));
36+
}
37+
};

dxwrapper.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,7 @@ cmd /q /c "cd /D ""$(ProjectDir)d3d8\"" &amp;&amp; del build.bat"</Command>
588588
<ClInclude Include="ddraw\IDirectDrawGammaControl.h" />
589589
<ClInclude Include="ddraw\IDirectDrawPalette.h" />
590590
<ClInclude Include="ddraw\IDirectDrawX.h" />
591+
<ClInclude Include="ddraw\RenderData.h" />
591592
<ClInclude Include="ddraw\Versions\IDirect3D.h" />
592593
<ClInclude Include="ddraw\Versions\IDirect3D2.h" />
593594
<ClInclude Include="ddraw\Versions\IDirect3D3.h" />

dxwrapper.vcxproj.filters

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<?xml version="1.0" encoding="utf-8"?>
1+
<?xml version="1.0" encoding="utf-8"?>
22
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
33
<ItemGroup>
44
<Filter Include="DDrawCompat">
@@ -1868,6 +1868,9 @@
18681868
<ClInclude Include="ddraw\DebugOverlay.h">
18691869
<Filter>ddraw</Filter>
18701870
</ClInclude>
1871+
<ClInclude Include="ddraw\RenderData.h">
1872+
<Filter>ddraw</Filter>
1873+
</ClInclude>
18711874
</ItemGroup>
18721875
<ItemGroup>
18731876
<ResourceCompile Include="Dllmain\BuildNo.rc">

0 commit comments

Comments
 (0)