Fetching DirectX 9 Device: Difference between revisions
(Created page with "This tutorial shows how to fetch the [https://learn.microsoft.com/en-us/windows/win32/api/d3d9helper/nn-d3d9helper-idirect3ddevice9 DirectX 9 Device] in 64-bit games on the {{tf2branch|4}}. Access to the low-level DirectX 9 device allows the creation of effects that Source has no support for, such as [https://learn.microsoft.com/en-us/windows/win32/direct3d9/creating-cubic-environment-map-surfaces rendering cubemaps in real-time]. {{warning|This is intended for adv...") |
SirYodaJedi (talk | contribs) No edit summary |
||
| Line 79: | Line 79: | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
[[Category:Programming]] | |||
Revision as of 04:43, 2 November 2025
This tutorial shows how to fetch the DirectX 9 Device in 64-bit games on the
Team Fortress 2 branch.
Access to the low-level DirectX 9 device allows the creation of effects that Source has no support for, such as rendering cubemaps in real-time.
Tutorial
Open the client initialization code in game/client/cdll_client_int.cpp.
Following the big wall of #includes, add the following:
#include "shaderapi/IShaderDevice.h"
Scrolling further down, you will see a list of interface pointers, below the comment that says this:
// IF YOU ADD AN INTERFACE, EXTERN IT IN THE HEADER FILE.
Add these interfaces:
IShaderDevice* g_pShaderDevice = NULL;
struct IDirect3DDevice9* g_pDirect3DDevice9 = NULL;
Tutorial
Now, go to the CHLClient::Init function and add the following after the if (!g_pMatSystemSurface) check:
g_pShaderDevice = (IShaderDevice*)appSystemFactory( SHADER_DEVICE_INTERFACE_VERSION, NULL );
if ( !g_pShaderDevice )
return false;
Next comes the fun part. The IShaderDevice class has a public function that checks whether the DirectX 9 device exists, named IsUsingGraphics. We can abuse this to fetch the actual pointer to the device.
Copy the following function into the file somewhere above. You don't need to worry about the specific details of how this works.
IDirect3DDevice9* GetDX9Device()
{
// Dereference the virtual table and access the IsUsingGraphics method
byte* IShaderDevice_IsUsingGraphics = (byte*)(*(void***)g_pShaderDevice)[5];
// Resolve the RIP instruction to get the absolute address
byte* pDirect3DDevice9 = IShaderDevice_IsUsingGraphics + 8 + *( int32* )( IShaderDevice_IsUsingGraphics + 3 );
return *( IDirect3DDevice9** )pDirect3DDevice9;
}
Now go back to where you added the code to fetch the g_pShaderDevice interface, and add the following below:
IDirect3DDevice9* g_pDirect3DDevice9 = GetDX9Device();
if ( !g_pDirect3DDevice9 )
{
Error( "Failed to get DirectX9 device pointer" );
return false;
}
And that's all! You can now call the raw DirectX9 API using the g_pDirect3DDevice9 interface.
Usage
To call functions on the DirectX 9 device, you will need to download the DirectX 9 SDK.
After you download it, extract it to a place in your mod's folder. The convention is to make a dx9sdk directory in the top-level folder of your source code.
You can then include the DirectX 9 API like-so in client code:
#include "../../dx9sdk/include/d3d9.h"
// ...
void Example()
{
IDirect3DSwapChain9* pSwapChain = NULL;
g_pDirect3DDevice9->GetSwapChain( 0, &pSwapChain );
}