2020-10-12 17:34:22 +02:00
// dear imgui: Renderer Backend for DirectX9
// This needs to be used along with a Platform Backend (e.g. Win32)
2018-02-05 20:34:11 +01:00
// Implemented features:
2024-11-27 18:47:21 +01:00
// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
2024-12-05 12:43:04 +01:00
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
2024-11-27 18:47:21 +01:00
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
2024-12-05 12:43:04 +01:00
// [X] Renderer: IMGUI_USE_BGRA_PACKED_COLOR support, as this is the optimal color encoding for DirectX9.
2016-03-24 11:00:47 +01:00
2021-06-24 15:13:21 +02:00
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
2021-05-27 13:59:35 +02:00
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
2023-09-11 13:47:08 +02:00
// Learn about Dear ImGui:
// - FAQ https://dearimgui.com/faq
// - Getting Started https://dearimgui.com/getting-started
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
// - Introduction, links and more at the top of imgui.cpp
2015-03-09 13:03:46 +00:00
2019-01-20 17:56:17 +01:00
// CHANGELOG
2018-02-16 19:18:16 +01:00
// (minor and older changes stripped away, please see git history for details)
2026-04-23 22:03:11 +02:00
// 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378)
2026-03-19 11:47:01 +01:00
// 2026-03-19: Fixed issue in ImGui_ImplDX9_UpdateTexture() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295, #9310)
2025-09-18 16:22:24 +02:00
// 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown.
2024-11-27 18:47:21 +01:00
// 2025-06-11: DirectX9: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas.
2024-10-07 22:02:55 +02:00
// 2024-10-07: DirectX9: Changed default texture sampler to Clamp instead of Repeat/Wrap.
2023-07-06 01:48:35 +08:00
// 2024-02-12: DirectX9: Using RGBA format when supported by the driver to avoid CPU side conversion. (#6575)
2022-10-11 12:22:29 +02:00
// 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11.
2021-06-28 16:52:10 +02:00
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
2021-06-25 22:06:38 +12:00
// 2021-06-25: DirectX9: Explicitly disable texture state stages after >= 1.
2021-02-07 12:36:54 +01:00
// 2021-05-19: DirectX9: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
2021-04-23 14:09:43 +02:00
// 2021-04-23: DirectX9: Explicitly setting up more graphics states to increase compatibility with unusual non-default states.
2021-03-18 18:04:38 +01:00
// 2021-03-18: DirectX9: Calling IDirect3DStateBlock9::Capture() after CreateStateBlock() as a workaround for state restoring issues (see #3857).
2021-02-26 10:40:22 +08:00
// 2021-03-03: DirectX9: Added support for IMGUI_USE_BGRA_PACKED_COLOR in user's imconfig file.
2021-02-17 19:29:07 +01:00
// 2021-02-18: DirectX9: Change blending equation to preserve alpha in output buffer.
2019-05-29 16:29:17 +02:00
// 2019-05-29: DirectX9: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
2019-04-30 22:28:29 +02:00
// 2019-04-30: DirectX9: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
2019-03-29 18:29:15 +01:00
// 2019-03-29: Misc: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects().
2019-01-17 06:07:15 +01:00
// 2019-01-16: Misc: Disabled fog before drawing UI's. Fixes issue #2288.
2018-11-30 18:18:15 +01:00
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
2018-06-08 19:37:33 +02:00
// 2018-06-08: Misc: Extracted imgui_impl_dx9.cpp/.h away from the old combined DX9+Win32 example.
// 2018-06-08: DirectX9: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
2018-05-07 11:52:11 +02:00
// 2018-05-07: Render: Saving/restoring Transform because they don't seem to be included in the StateBlock. Setting shading mode to Gouraud.
2018-02-16 19:18:16 +01:00
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX9_RenderDrawData() in the .h file so you can call it yourself.
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
2018-01-29 14:38:46 +01:00
# include "imgui.h"
2023-07-13 11:27:52 +02:00
# ifndef IMGUI_DISABLE
2015-03-09 13:03:46 +00:00
# include "imgui_impl_dx9.h"
// DirectX
2016-05-03 10:47:42 +02:00
# include <d3d9.h>
2015-03-09 13:03:46 +00:00
2025-06-20 14:46:32 +02:00
// Clang/GCC warnings with -Weverything
# if defined(__clang__)
# pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse.
# pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
# endif
2018-02-20 13:55:09 +01:00
// DirectX data
2021-06-28 16:52:10 +02:00
struct ImGui_ImplDX9_Data
{
LPDIRECT3DDEVICE9 pd3dDevice ;
LPDIRECT3DVERTEXBUFFER9 pVB ;
LPDIRECT3DINDEXBUFFER9 pIB ;
int VertexBufferSize ;
int IndexBufferSize ;
2024-11-20 22:19:34 +01:00
bool HasRgbaSupport ;
2021-06-28 16:52:10 +02:00
2022-03-13 13:15:32 +07:00
ImGui_ImplDX9_Data ( ) { memset ( ( void * ) this , 0 , sizeof ( * this ) ) ; VertexBufferSize = 5000 ; IndexBufferSize = 10000 ; }
2021-06-28 16:52:10 +02:00
} ;
2015-03-09 13:03:46 +00:00
struct CUSTOMVERTEX
{
2016-05-03 10:47:42 +02:00
float pos [ 3 ] ;
D3DCOLOR col ;
float uv [ 2 ] ;
2015-03-09 13:03:46 +00:00
} ;
# define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)
2021-03-02 15:03:16 +01:00
# ifdef IMGUI_USE_BGRA_PACKED_COLOR
# define IMGUI_COL_TO_DX9_ARGB(_COL) (_COL)
# else
# define IMGUI_COL_TO_DX9_ARGB(_COL) (((_COL) & 0xFF00FF00) | (((_COL) & 0xFF0000) >> 16) | (((_COL) & 0xFF) << 16))
# endif
2021-06-30 15:22:15 +02:00
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
static ImGui_ImplDX9_Data * ImGui_ImplDX9_GetBackendData ( )
{
2022-10-11 12:22:29 +02:00
return ImGui : : GetCurrentContext ( ) ? ( ImGui_ImplDX9_Data * ) ImGui : : GetIO ( ) . BackendRendererUserData : nullptr ;
2021-06-30 15:22:15 +02:00
}
2021-06-28 16:52:10 +02:00
// Functions
2019-04-30 22:15:59 +02:00
static void ImGui_ImplDX9_SetupRenderState ( ImDrawData * draw_data )
{
2021-06-28 16:52:10 +02:00
ImGui_ImplDX9_Data * bd = ImGui_ImplDX9_GetBackendData ( ) ;
2019-04-30 22:15:59 +02:00
// Setup viewport
D3DVIEWPORT9 vp ;
vp . X = vp . Y = 0 ;
vp . Width = ( DWORD ) draw_data - > DisplaySize . x ;
vp . Height = ( DWORD ) draw_data - > DisplaySize . y ;
vp . MinZ = 0.0f ;
vp . MaxZ = 1.0f ;
2024-10-07 17:52:57 +02:00
LPDIRECT3DDEVICE9 device = bd - > pd3dDevice ;
device - > SetViewport ( & vp ) ;
2019-04-30 22:15:59 +02:00
2022-04-07 14:28:08 +02:00
// Setup render state: fixed-pipeline, alpha-blending, no face culling, no depth testing, shade mode (for gradient), bilinear sampling.
2024-10-07 17:52:57 +02:00
device - > SetPixelShader ( nullptr ) ;
device - > SetVertexShader ( nullptr ) ;
device - > SetRenderState ( D3DRS_FILLMODE , D3DFILL_SOLID ) ;
device - > SetRenderState ( D3DRS_SHADEMODE , D3DSHADE_GOURAUD ) ;
device - > SetRenderState ( D3DRS_ZWRITEENABLE , FALSE ) ;
device - > SetRenderState ( D3DRS_ALPHATESTENABLE , FALSE ) ;
device - > SetRenderState ( D3DRS_CULLMODE , D3DCULL_NONE ) ;
device - > SetRenderState ( D3DRS_ZENABLE , FALSE ) ;
device - > SetRenderState ( D3DRS_ALPHABLENDENABLE , TRUE ) ;
device - > SetRenderState ( D3DRS_BLENDOP , D3DBLENDOP_ADD ) ;
device - > SetRenderState ( D3DRS_SRCBLEND , D3DBLEND_SRCALPHA ) ;
device - > SetRenderState ( D3DRS_DESTBLEND , D3DBLEND_INVSRCALPHA ) ;
device - > SetRenderState ( D3DRS_SEPARATEALPHABLENDENABLE , TRUE ) ;
device - > SetRenderState ( D3DRS_SRCBLENDALPHA , D3DBLEND_ONE ) ;
device - > SetRenderState ( D3DRS_DESTBLENDALPHA , D3DBLEND_INVSRCALPHA ) ;
device - > SetRenderState ( D3DRS_SCISSORTESTENABLE , TRUE ) ;
device - > SetRenderState ( D3DRS_FOGENABLE , FALSE ) ;
device - > SetRenderState ( D3DRS_RANGEFOGENABLE , FALSE ) ;
device - > SetRenderState ( D3DRS_SPECULARENABLE , FALSE ) ;
device - > SetRenderState ( D3DRS_STENCILENABLE , FALSE ) ;
device - > SetRenderState ( D3DRS_CLIPPING , TRUE ) ;
device - > SetRenderState ( D3DRS_LIGHTING , FALSE ) ;
device - > SetTextureStageState ( 0 , D3DTSS_COLOROP , D3DTOP_MODULATE ) ;
device - > SetTextureStageState ( 0 , D3DTSS_COLORARG1 , D3DTA_TEXTURE ) ;
device - > SetTextureStageState ( 0 , D3DTSS_COLORARG2 , D3DTA_DIFFUSE ) ;
device - > SetTextureStageState ( 0 , D3DTSS_ALPHAOP , D3DTOP_MODULATE ) ;
device - > SetTextureStageState ( 0 , D3DTSS_ALPHAARG1 , D3DTA_TEXTURE ) ;
device - > SetTextureStageState ( 0 , D3DTSS_ALPHAARG2 , D3DTA_DIFFUSE ) ;
device - > SetTextureStageState ( 1 , D3DTSS_COLOROP , D3DTOP_DISABLE ) ;
device - > SetTextureStageState ( 1 , D3DTSS_ALPHAOP , D3DTOP_DISABLE ) ;
device - > SetSamplerState ( 0 , D3DSAMP_MINFILTER , D3DTEXF_LINEAR ) ;
device - > SetSamplerState ( 0 , D3DSAMP_MAGFILTER , D3DTEXF_LINEAR ) ;
2024-10-07 22:02:55 +02:00
device - > SetSamplerState ( 0 , D3DSAMP_ADDRESSU , D3DTADDRESS_CLAMP ) ;
device - > SetSamplerState ( 0 , D3DSAMP_ADDRESSV , D3DTADDRESS_CLAMP ) ;
2019-04-30 22:15:59 +02:00
// Setup orthographic projection matrix
2019-06-06 16:13:30 +02:00
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
2019-04-30 22:15:59 +02:00
// Being agnostic of whether <d3dx9.h> or <DirectXMath.h> can be used, we aren't relying on D3DXMatrixIdentity()/D3DXMatrixOrthoOffCenterLH() or DirectX::XMMatrixIdentity()/DirectX::XMMatrixOrthographicOffCenterLH()
{
float L = draw_data - > DisplayPos . x + 0.5f ;
float R = draw_data - > DisplayPos . x + draw_data - > DisplaySize . x + 0.5f ;
float T = draw_data - > DisplayPos . y + 0.5f ;
float B = draw_data - > DisplayPos . y + draw_data - > DisplaySize . y + 0.5f ;
D3DMATRIX mat_identity = { { { 1.0f , 0.0f , 0.0f , 0.0f , 0.0f , 1.0f , 0.0f , 0.0f , 0.0f , 0.0f , 1.0f , 0.0f , 0.0f , 0.0f , 0.0f , 1.0f } } } ;
D3DMATRIX mat_projection =
{ { {
2.0f / ( R - L ) , 0.0f , 0.0f , 0.0f ,
0.0f , 2.0f / ( T - B ) , 0.0f , 0.0f ,
0.0f , 0.0f , 0.5f , 0.0f ,
( L + R ) / ( L - R ) , ( T + B ) / ( B - T ) , 0.5f , 1.0f
} } } ;
2024-10-07 17:52:57 +02:00
device - > SetTransform ( D3DTS_WORLD , & mat_identity ) ;
device - > SetTransform ( D3DTS_VIEW , & mat_identity ) ;
device - > SetTransform ( D3DTS_PROJECTION , & mat_projection ) ;
2019-04-30 22:15:59 +02:00
}
}
Backends: DX9, DX10, DX11, DX12, Allegro5, OpenGL2, OpenGL3, SDLRenderer2, SDLRenderer3, SDLGPU3, Vulkan: added standard draw callbacks when possible. (#9378)
2019-09-20 18:55:00 +02:00
// Draw callbacks
static void ImGui_ImplDX9_DrawCallback_ResetRenderState ( const ImDrawList * , const ImDrawCmd * ) { } // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way.
static void ImGui_ImplDX9_DrawCallback_SetSamplerLinear ( const ImDrawList * , const ImDrawCmd * ) { ImGui_ImplDX9_Data * bd = ImGui_ImplDX9_GetBackendData ( ) ; bd - > pd3dDevice - > SetSamplerState ( 0 , D3DSAMP_MINFILTER , D3DTEXF_LINEAR ) ; bd - > pd3dDevice - > SetSamplerState ( 0 , D3DSAMP_MAGFILTER , D3DTEXF_LINEAR ) ; }
static void ImGui_ImplDX9_DrawCallback_SetSamplerNearest ( const ImDrawList * , const ImDrawCmd * ) { ImGui_ImplDX9_Data * bd = ImGui_ImplDX9_GetBackendData ( ) ; bd - > pd3dDevice - > SetSamplerState ( 0 , D3DSAMP_MINFILTER , D3DTEXF_POINT ) ; bd - > pd3dDevice - > SetSamplerState ( 0 , D3DSAMP_MAGFILTER , D3DTEXF_POINT ) ; }
2018-02-16 19:18:16 +01:00
// Render function.
void ImGui_ImplDX9_RenderDrawData ( ImDrawData * draw_data )
2015-03-09 13:03:46 +00:00
{
2016-05-03 10:47:42 +02:00
// Avoid rendering when minimized
2018-06-08 19:37:33 +02:00
if ( draw_data - > DisplaySize . x < = 0.0f | | draw_data - > DisplaySize . y < = 0.0f )
2016-05-03 10:47:42 +02:00
return ;
2021-06-28 16:52:10 +02:00
ImGui_ImplDX9_Data * bd = ImGui_ImplDX9_GetBackendData ( ) ;
2024-10-07 17:52:57 +02:00
LPDIRECT3DDEVICE9 device = bd - > pd3dDevice ;
2024-11-27 18:47:21 +01:00
// Catch up with texture updates. Most of the times, the list will have 1 element with an OK status, aka nothing to do.
// (This almost always points to ImGui::GetPlatformIO().Textures[] but is part of ImDrawData to allow overriding or disabling texture updates).
if ( draw_data - > Textures ! = nullptr )
for ( ImTextureData * tex : * draw_data - > Textures )
if ( tex - > Status ! = ImTextureStatus_OK )
ImGui_ImplDX9_UpdateTexture ( tex ) ;
2024-10-07 17:52:57 +02:00
// Create and grow buffers if needed
2021-06-28 16:52:10 +02:00
if ( ! bd - > pVB | | bd - > VertexBufferSize < draw_data - > TotalVtxCount )
2015-08-13 23:06:11 -06:00
{
2022-10-11 12:22:29 +02:00
if ( bd - > pVB ) { bd - > pVB - > Release ( ) ; bd - > pVB = nullptr ; }
2021-06-28 16:52:10 +02:00
bd - > VertexBufferSize = draw_data - > TotalVtxCount + 5000 ;
2026-04-23 17:01:02 +02:00
if ( device - > CreateVertexBuffer ( ( UINT ) bd - > VertexBufferSize * sizeof ( CUSTOMVERTEX ) , D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY , D3DFVF_CUSTOMVERTEX , D3DPOOL_DEFAULT , & bd - > pVB , nullptr ) < 0 )
2015-08-13 23:06:11 -06:00
return ;
}
2021-06-28 16:52:10 +02:00
if ( ! bd - > pIB | | bd - > IndexBufferSize < draw_data - > TotalIdxCount )
2015-08-13 23:06:11 -06:00
{
2022-10-11 12:22:29 +02:00
if ( bd - > pIB ) { bd - > pIB - > Release ( ) ; bd - > pIB = nullptr ; }
2021-06-28 16:52:10 +02:00
bd - > IndexBufferSize = draw_data - > TotalIdxCount + 10000 ;
2026-04-23 17:01:02 +02:00
if ( device - > CreateIndexBuffer ( ( UINT ) bd - > IndexBufferSize * sizeof ( ImDrawIdx ) , D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY , sizeof ( ImDrawIdx ) = = 2 ? D3DFMT_INDEX16 : D3DFMT_INDEX32 , D3DPOOL_DEFAULT , & bd - > pIB , nullptr ) < 0 )
2015-08-13 23:06:11 -06:00
return ;
}
2016-05-16 01:02:09 +01:00
// Backup the DX9 state
2024-10-07 17:52:57 +02:00
IDirect3DStateBlock9 * state_block = nullptr ;
if ( device - > CreateStateBlock ( D3DSBT_ALL , & state_block ) < 0 )
2016-05-16 01:02:09 +01:00
return ;
2024-10-07 17:52:57 +02:00
if ( state_block - > Capture ( ) < 0 )
2021-03-18 18:04:38 +01:00
{
2024-10-07 17:52:57 +02:00
state_block - > Release ( ) ;
2021-03-18 18:04:38 +01:00
return ;
}
2016-04-11 18:33:16 +02:00
2018-05-07 11:52:11 +02:00
// Backup the DX9 transform (DX9 documentation suggests that it is included in the StateBlock but it doesn't appear to)
2018-05-03 12:01:41 +03:00
D3DMATRIX last_world , last_view , last_projection ;
2024-10-07 17:52:57 +02:00
device - > GetTransform ( D3DTS_WORLD , & last_world ) ;
device - > GetTransform ( D3DTS_VIEW , & last_view ) ;
device - > GetTransform ( D3DTS_PROJECTION , & last_projection ) ;
2018-05-03 12:01:41 +03:00
2021-05-01 21:47:48 +03:00
// Allocate buffers
2015-03-09 13:03:46 +00:00
CUSTOMVERTEX * vtx_dst ;
2015-04-09 21:05:35 +01:00
ImDrawIdx * idx_dst ;
2021-06-28 16:52:10 +02:00
if ( bd - > pVB - > Lock ( 0 , ( UINT ) ( draw_data - > TotalVtxCount * sizeof ( CUSTOMVERTEX ) ) , ( void * * ) & vtx_dst , D3DLOCK_DISCARD ) < 0 )
2021-05-01 21:47:48 +03:00
{
2024-10-07 17:52:57 +02:00
state_block - > Release ( ) ;
2015-03-09 13:03:46 +00:00
return ;
2021-05-01 21:47:48 +03:00
}
2021-06-28 16:52:10 +02:00
if ( bd - > pIB - > Lock ( 0 , ( UINT ) ( draw_data - > TotalIdxCount * sizeof ( ImDrawIdx ) ) , ( void * * ) & idx_dst , D3DLOCK_DISCARD ) < 0 )
2021-05-01 21:47:48 +03:00
{
2021-06-28 16:52:10 +02:00
bd - > pVB - > Unlock ( ) ;
2024-10-07 17:52:57 +02:00
state_block - > Release ( ) ;
2015-04-09 21:05:35 +01:00
return ;
2021-05-01 21:47:48 +03:00
}
// Copy and convert all vertices into a single contiguous buffer, convert colors to DX9 default format.
// FIXME-OPT: This is a minor waste of resource, the ideal is to use imconfig.h and
// 1) to avoid repacking colors: #define IMGUI_USE_BGRA_PACKED_COLOR
// 2) to avoid repacking vertices: #define IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT struct ImDrawVert { ImVec2 pos; float z; ImU32 col; ImVec2 uv; }
2025-07-11 17:41:52 +02:00
for ( const ImDrawList * draw_list : draw_data - > CmdLists )
2015-03-09 13:03:46 +00:00
{
2024-10-07 17:52:57 +02:00
const ImDrawVert * vtx_src = draw_list - > VtxBuffer . Data ;
for ( int i = 0 ; i < draw_list - > VtxBuffer . Size ; i + + )
2015-03-09 13:03:46 +00:00
{
2016-05-03 10:47:42 +02:00
vtx_dst - > pos [ 0 ] = vtx_src - > pos . x ;
vtx_dst - > pos [ 1 ] = vtx_src - > pos . y ;
vtx_dst - > pos [ 2 ] = 0.0f ;
2021-03-02 15:03:16 +01:00
vtx_dst - > col = IMGUI_COL_TO_DX9_ARGB ( vtx_src - > col ) ;
2016-05-03 10:47:42 +02:00
vtx_dst - > uv [ 0 ] = vtx_src - > uv . x ;
vtx_dst - > uv [ 1 ] = vtx_src - > uv . y ;
2015-03-09 13:03:46 +00:00
vtx_dst + + ;
vtx_src + + ;
}
2024-10-07 17:52:57 +02:00
memcpy ( idx_dst , draw_list - > IdxBuffer . Data , draw_list - > IdxBuffer . Size * sizeof ( ImDrawIdx ) ) ;
idx_dst + = draw_list - > IdxBuffer . Size ;
2015-03-09 13:03:46 +00:00
}
2021-06-28 16:52:10 +02:00
bd - > pVB - > Unlock ( ) ;
bd - > pIB - > Unlock ( ) ;
2024-10-07 17:52:57 +02:00
device - > SetStreamSource ( 0 , bd - > pVB , 0 , sizeof ( CUSTOMVERTEX ) ) ;
device - > SetIndices ( bd - > pIB ) ;
device - > SetFVF ( D3DFVF_CUSTOMVERTEX ) ;
2015-03-09 13:03:46 +00:00
2019-04-30 22:15:59 +02:00
// Setup desired DX state
ImGui_ImplDX9_SetupRenderState ( draw_data ) ;
2015-03-09 13:03:46 +00:00
// Render command lists
2019-05-29 15:53:36 +02:00
// (Because we merged all buffers into a single one, we maintain our own offset into them)
int global_vtx_offset = 0 ;
int global_idx_offset = 0 ;
2019-02-11 18:38:07 +01:00
ImVec2 clip_off = draw_data - > DisplayPos ;
2025-07-11 17:41:52 +02:00
for ( const ImDrawList * draw_list : draw_data - > CmdLists )
2015-03-09 13:03:46 +00:00
{
2024-10-07 17:52:57 +02:00
for ( int cmd_i = 0 ; cmd_i < draw_list - > CmdBuffer . Size ; cmd_i + + )
2015-03-09 13:03:46 +00:00
{
2024-10-07 17:52:57 +02:00
const ImDrawCmd * pcmd = & draw_list - > CmdBuffer [ cmd_i ] ;
2022-10-11 12:22:29 +02:00
if ( pcmd - > UserCallback ! = nullptr )
2015-03-09 15:26:58 +00:00
{
2019-04-30 22:15:59 +02:00
// User callback, registered via ImDrawList::AddCallback()
Backends: DX9, DX10, DX11, DX12, Allegro5, OpenGL2, OpenGL3, SDLRenderer2, SDLRenderer3, SDLGPU3, Vulkan: added standard draw callbacks when possible. (#9378)
2019-09-20 18:55:00 +02:00
if ( pcmd - > UserCallback = = ImGui_ImplDX9_DrawCallback_ResetRenderState )
2019-04-30 22:15:59 +02:00
ImGui_ImplDX9_SetupRenderState ( draw_data ) ;
else
2024-10-07 17:52:57 +02:00
pcmd - > UserCallback ( draw_list , pcmd ) ;
2015-03-09 15:26:58 +00:00
}
else
{
2021-08-24 18:03:52 +03:00
// Project scissor/clipping rectangles into framebuffer space
ImVec2 clip_min ( pcmd - > ClipRect . x - clip_off . x , pcmd - > ClipRect . y - clip_off . y ) ;
ImVec2 clip_max ( pcmd - > ClipRect . z - clip_off . x , pcmd - > ClipRect . w - clip_off . y ) ;
2021-11-30 21:48:29 +01:00
if ( clip_max . x < = clip_min . x | | clip_max . y < = clip_min . y )
2021-08-24 18:03:52 +03:00
continue ;
2024-10-07 17:52:57 +02:00
// Apply scissor/clipping rectangle
2021-08-24 18:03:52 +03:00
const RECT r = { ( LONG ) clip_min . x , ( LONG ) clip_min . y , ( LONG ) clip_max . x , ( LONG ) clip_max . y } ;
2024-10-07 17:52:57 +02:00
device - > SetScissorRect ( & r ) ;
// Bind texture, Draw
2021-02-07 12:36:54 +01:00
const LPDIRECT3DTEXTURE9 texture = ( LPDIRECT3DTEXTURE9 ) pcmd - > GetTexID ( ) ;
2024-10-07 17:52:57 +02:00
device - > SetTexture ( 0 , texture ) ;
device - > DrawIndexedPrimitive ( D3DPT_TRIANGLELIST , pcmd - > VtxOffset + global_vtx_offset , 0 , ( UINT ) draw_list - > VtxBuffer . Size , pcmd - > IdxOffset + global_idx_offset , pcmd - > ElemCount / 3 ) ;
2015-03-09 15:26:58 +00:00
}
2015-03-09 13:03:46 +00:00
}
2024-10-07 17:52:57 +02:00
global_idx_offset + = draw_list - > IdxBuffer . Size ;
global_vtx_offset + = draw_list - > VtxBuffer . Size ;
2015-03-09 13:03:46 +00:00
}
2016-04-11 18:33:16 +02:00
2018-05-03 12:01:41 +03:00
// Restore the DX9 transform
2024-10-07 17:52:57 +02:00
device - > SetTransform ( D3DTS_WORLD , & last_world ) ;
device - > SetTransform ( D3DTS_VIEW , & last_view ) ;
device - > SetTransform ( D3DTS_PROJECTION , & last_projection ) ;
2018-05-03 12:01:41 +03:00
2016-05-16 01:02:09 +01:00
// Restore the DX9 state
2024-10-07 17:52:57 +02:00
state_block - > Apply ( ) ;
state_block - > Release ( ) ;
2015-03-09 13:03:46 +00:00
}
2024-11-20 22:19:34 +01:00
static bool ImGui_ImplDX9_CheckFormatSupport ( LPDIRECT3DDEVICE9 pDevice , D3DFORMAT format )
{
LPDIRECT3D9 pd3d = nullptr ;
if ( pDevice - > GetDirect3D ( & pd3d ) ! = D3D_OK )
return false ;
D3DDEVICE_CREATION_PARAMETERS param = { } ;
D3DDISPLAYMODE mode = { } ;
if ( pDevice - > GetCreationParameters ( & param ) ! = D3D_OK | | pDevice - > GetDisplayMode ( 0 , & mode ) ! = D3D_OK )
{
pd3d - > Release ( ) ;
return false ;
}
// Font texture should support linear filter, color blend and write to render-target
bool support = ( pd3d - > CheckDeviceFormat ( param . AdapterOrdinal , param . DeviceType , mode . Format , D3DUSAGE_DYNAMIC | D3DUSAGE_QUERY_FILTER | D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING , D3DRTYPE_TEXTURE , format ) ) = = D3D_OK ;
pd3d - > Release ( ) ;
return support ;
}
2024-11-21 16:57:51 +01:00
// Convert RGBA32 to BGRA32 (because RGBA32 is not well supported by DX9 devices)
2024-11-27 18:47:21 +01:00
static void ImGui_ImplDX9_CopyTextureRegion ( bool tex_use_colors , const ImU32 * src , int src_pitch , ImU32 * dst , int dst_pitch , int w , int h )
2024-11-21 16:57:51 +01:00
{
# ifndef IMGUI_USE_BGRA_PACKED_COLOR
ImGui_ImplDX9_Data * bd = ImGui_ImplDX9_GetBackendData ( ) ;
const bool convert_rgba_to_bgra = ( ! bd - > HasRgbaSupport & & tex_use_colors ) ;
# else
const bool convert_rgba_to_bgra = false ;
IM_UNUSED ( tex_use_colors ) ;
# endif
for ( int y = 0 ; y < h ; y + + )
{
2025-06-20 15:23:52 +02:00
const ImU32 * src_p = ( const ImU32 * ) ( const void * ) ( ( const unsigned char * ) src + src_pitch * y ) ;
2025-06-20 14:46:32 +02:00
ImU32 * dst_p = ( ImU32 * ) ( void * ) ( ( unsigned char * ) dst + dst_pitch * y ) ;
2024-11-21 16:57:51 +01:00
if ( convert_rgba_to_bgra )
for ( int x = w ; x > 0 ; x - - , src_p + + , dst_p + + ) // Convert copy
* dst_p = IMGUI_COL_TO_DX9_ARGB ( * src_p ) ;
else
memcpy ( dst_p , src_p , w * 4 ) ; // Raw copy
}
}
2024-11-27 18:47:21 +01:00
void ImGui_ImplDX9_UpdateTexture ( ImTextureData * tex )
2015-03-09 14:55:46 +00:00
{
2021-06-28 16:52:10 +02:00
ImGui_ImplDX9_Data * bd = ImGui_ImplDX9_GetBackendData ( ) ;
2015-03-09 14:55:46 +00:00
2024-11-27 18:47:21 +01:00
if ( tex - > Status = = ImTextureStatus_WantCreate )
{
// Create and upload new texture to graphics system
//IMGUI_DEBUG_LOG("UpdateTexture #%03d: WantCreate %dx%d\n", tex->UniqueID, tex->Width, tex->Height);
IM_ASSERT ( tex - > TexID = = ImTextureID_Invalid & & tex - > BackendUserData = = nullptr ) ;
IM_ASSERT ( tex - > Format = = ImTextureFormat_RGBA32 ) ;
LPDIRECT3DTEXTURE9 dx_tex = nullptr ;
HRESULT hr = bd - > pd3dDevice - > CreateTexture ( tex - > Width , tex - > Height , 1 , D3DUSAGE_DYNAMIC , bd - > HasRgbaSupport ? D3DFMT_A8B8G8R8 : D3DFMT_A8R8G8B8 , D3DPOOL_DEFAULT , & dx_tex , nullptr ) ;
if ( hr < 0 )
{
IM_ASSERT ( hr > = 0 & & " Backend failed to create texture! " ) ;
return ;
}
2015-03-09 14:55:46 +00:00
2024-11-27 18:47:21 +01:00
D3DLOCKED_RECT locked_rect ;
if ( dx_tex - > LockRect ( 0 , & locked_rect , nullptr , 0 ) = = D3D_OK )
{
ImGui_ImplDX9_CopyTextureRegion ( tex - > UseColors , ( ImU32 * ) tex - > GetPixels ( ) , tex - > Width * 4 , ( ImU32 * ) locked_rect . pBits , ( ImU32 ) locked_rect . Pitch , tex - > Width , tex - > Height ) ;
dx_tex - > UnlockRect ( 0 ) ;
}
// Store identifiers
tex - > SetTexID ( ( ImTextureID ) ( intptr_t ) dx_tex ) ;
tex - > SetStatus ( ImTextureStatus_OK ) ;
}
else if ( tex - > Status = = ImTextureStatus_WantUpdates )
{
// Update selected blocks. We only ever write to textures regions which have never been used before!
// This backend choose to use tex->Updates[] but you can use tex->UpdateRect to upload a single region.
LPDIRECT3DTEXTURE9 backend_tex = ( LPDIRECT3DTEXTURE9 ) ( intptr_t ) tex - > TexID ;
RECT update_rect = { ( LONG ) tex - > UpdateRect . x , ( LONG ) tex - > UpdateRect . y , ( LONG ) ( tex - > UpdateRect . x + tex - > UpdateRect . w ) , ( LONG ) ( tex - > UpdateRect . y + tex - > UpdateRect . h ) } ;
D3DLOCKED_RECT locked_rect ;
if ( backend_tex - > LockRect ( 0 , & locked_rect , & update_rect , 0 ) = = D3D_OK )
for ( ImTextureRect & r : tex - > Updates )
ImGui_ImplDX9_CopyTextureRegion ( tex - > UseColors , ( ImU32 * ) tex - > GetPixelsAt ( r . x , r . y ) , tex - > Width * 4 ,
( ImU32 * ) locked_rect . pBits + ( r . x - update_rect . left ) + ( r . y - update_rect . top ) * ( locked_rect . Pitch / 4 ) , ( int ) locked_rect . Pitch , r . w , r . h ) ;
backend_tex - > UnlockRect ( 0 ) ;
tex - > SetStatus ( ImTextureStatus_OK ) ;
}
else if ( tex - > Status = = ImTextureStatus_WantDestroy )
{
2026-03-19 18:17:35 +01:00
if ( tex - > TexID ! = ImTextureID_Invalid )
2026-03-19 11:47:01 +01:00
if ( LPDIRECT3DTEXTURE9 backend_tex = ( LPDIRECT3DTEXTURE9 ) tex - > TexID )
{
IM_ASSERT ( tex - > TexID = = ( ImTextureID ) ( intptr_t ) backend_tex ) ;
backend_tex - > Release ( ) ;
2024-11-27 18:47:21 +01:00
2026-03-19 11:47:01 +01:00
// Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running)
tex - > SetTexID ( ImTextureID_Invalid ) ;
}
2024-11-27 18:47:21 +01:00
tex - > SetStatus ( ImTextureStatus_Destroyed ) ;
}
2015-03-09 14:55:46 +00:00
}
bool ImGui_ImplDX9_CreateDeviceObjects ( )
{
2021-06-28 16:52:10 +02:00
ImGui_ImplDX9_Data * bd = ImGui_ImplDX9_GetBackendData ( ) ;
if ( ! bd | | ! bd - > pd3dDevice )
2015-03-09 14:55:46 +00:00
return false ;
return true ;
}
2015-03-09 14:13:29 +00:00
void ImGui_ImplDX9_InvalidateDeviceObjects ( )
2015-03-09 13:03:46 +00:00
{
2021-06-28 16:52:10 +02:00
ImGui_ImplDX9_Data * bd = ImGui_ImplDX9_GetBackendData ( ) ;
if ( ! bd | | ! bd - > pd3dDevice )
2015-03-09 14:13:29 +00:00
return ;
2024-11-27 18:47:21 +01:00
// Destroy all textures
for ( ImTextureData * tex : ImGui : : GetPlatformIO ( ) . Textures )
if ( tex - > RefCount = = 1 )
{
tex - > SetStatus ( ImTextureStatus_WantDestroy ) ;
ImGui_ImplDX9_UpdateTexture ( tex ) ;
}
2022-10-11 12:22:29 +02:00
if ( bd - > pVB ) { bd - > pVB - > Release ( ) ; bd - > pVB = nullptr ; }
if ( bd - > pIB ) { bd - > pIB - > Release ( ) ; bd - > pIB = nullptr ; }
2015-03-09 14:13:29 +00:00
}
2015-03-09 13:03:46 +00:00
void ImGui_ImplDX9_NewFrame ( )
{
2021-06-28 16:52:10 +02:00
ImGui_ImplDX9_Data * bd = ImGui_ImplDX9_GetBackendData ( ) ;
2024-05-07 16:53:03 +02:00
IM_ASSERT ( bd ! = nullptr & & " Context or backend not initialized! Did you call ImGui_ImplDX9_Init()? " ) ;
2024-11-27 18:47:21 +01:00
IM_UNUSED ( bd ) ;
2015-03-09 13:03:46 +00:00
}
2023-07-13 11:27:52 +02:00
2026-04-22 17:20:27 +02:00
bool ImGui_ImplDX9_Init ( IDirect3DDevice9 * device )
{
ImGuiIO & io = ImGui : : GetIO ( ) ;
IMGUI_CHECKVERSION ( ) ;
IM_ASSERT ( io . BackendRendererUserData = = nullptr & & " Already initialized a renderer backend! " ) ;
// Setup backend capabilities flags
ImGui_ImplDX9_Data * bd = IM_NEW ( ImGui_ImplDX9_Data ) ( ) ;
io . BackendRendererUserData = ( void * ) bd ;
io . BackendRendererName = " imgui_impl_dx9 " ;
io . BackendFlags | = ImGuiBackendFlags_RendererHasVtxOffset ; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
io . BackendFlags | = ImGuiBackendFlags_RendererHasTextures ; // We can honor ImGuiPlatformIO::Textures[] requests during render.
ImGuiPlatformIO & platform_io = ImGui : : GetPlatformIO ( ) ;
platform_io . Renderer_TextureMaxWidth = platform_io . Renderer_TextureMaxHeight = 4096 ;
Backends: DX9, DX10, DX11, DX12, Allegro5, OpenGL2, OpenGL3, SDLRenderer2, SDLRenderer3, SDLGPU3, Vulkan: added standard draw callbacks when possible. (#9378)
2019-09-20 18:55:00 +02:00
platform_io . DrawCallback_ResetRenderState = ImGui_ImplDX9_DrawCallback_ResetRenderState ;
platform_io . DrawCallback_SetSamplerLinear = ImGui_ImplDX9_DrawCallback_SetSamplerLinear ;
platform_io . DrawCallback_SetSamplerNearest = ImGui_ImplDX9_DrawCallback_SetSamplerNearest ;
2026-04-22 17:20:27 +02:00
bd - > pd3dDevice = device ;
bd - > pd3dDevice - > AddRef ( ) ;
bd - > HasRgbaSupport = ImGui_ImplDX9_CheckFormatSupport ( bd - > pd3dDevice , D3DFMT_A8B8G8R8 ) ;
return true ;
}
void ImGui_ImplDX9_Shutdown ( )
{
ImGui_ImplDX9_Data * bd = ImGui_ImplDX9_GetBackendData ( ) ;
IM_ASSERT ( bd ! = nullptr & & " No renderer backend to shutdown, or already shutdown? " ) ;
ImGuiIO & io = ImGui : : GetIO ( ) ;
ImGuiPlatformIO & platform_io = ImGui : : GetPlatformIO ( ) ;
ImGui_ImplDX9_InvalidateDeviceObjects ( ) ;
if ( bd - > pd3dDevice ) { bd - > pd3dDevice - > Release ( ) ; }
io . BackendRendererName = nullptr ;
io . BackendRendererUserData = nullptr ;
io . BackendFlags & = ~ ( ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures ) ;
platform_io . ClearRendererHandlers ( ) ;
IM_DELETE ( bd ) ;
}
2023-07-13 11:27:52 +02:00
//-----------------------------------------------------------------------------
# endif // #ifndef IMGUI_DISABLE