2021-11-11 21:22:24 +01:00
// dear imgui: Renderer Backend for DirectX10
// This needs to be used along with a Platform Backend (e.g. Win32)
// Implemented features:
// [X] Renderer: User texture binding. Use 'ID3D10ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID!
2023-04-14 17:44:25 +02:00
// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices.
2021-11-11 21:22:24 +01:00
2023-04-14 17:44:25 +02:00
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
2021-11-11 21:22:24 +01:00
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
2023-04-14 17:44:25 +02:00
// 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11.
// 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-05-19: DirectX10: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
// 2021-02-18: DirectX10: Change blending equation to preserve alpha in output buffer.
2021-11-11 21:22:24 +01:00
// 2019-07-21: DirectX10: Backup, clear and restore Geometry Shader is any is bound when calling ImGui_ImplDX10_RenderDrawData().
// 2019-05-29: DirectX10: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
// 2019-04-30: DirectX10: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
// 2018-12-03: Misc: Added #pragma comment statement to automatically link with d3dcompiler.lib when using D3DCompile().
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
// 2018-07-13: DirectX10: Fixed unreleased resources in Init and Shutdown functions.
// 2018-06-08: Misc: Extracted imgui_impl_dx10.cpp/.h away from the old combined DX10+Win32 example.
// 2018-06-08: DirectX10: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
// 2018-04-09: Misc: Fixed erroneous call to io.Fonts->ClearInputData() + ClearTexData() that was left in DX10 example but removed in 1.47 (Nov 2015) on other backends.
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX10_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.
// 2016-05-07: DirectX10: Disabling depth-write.
#include "imgui.h"
#include "imgui_impl_dx10.h"
// DirectX
#include <stdio.h>
#include <d3d10_1.h>
#include <d3d10.h>
#include <d3dcompiler.h>
#ifdef _MSC_VER
#pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below.
#endif
// DirectX data
2023-04-14 17:44:25 +02:00
struct ImGui_ImplDX10_Data
{
ID3D10Device * pd3dDevice ;
IDXGIFactory * pFactory ;
ID3D10Buffer * pVB ;
ID3D10Buffer * pIB ;
ID3D10VertexShader * pVertexShader ;
ID3D10InputLayout * pInputLayout ;
ID3D10Buffer * pVertexConstantBuffer ;
ID3D10PixelShader * pPixelShader ;
ID3D10SamplerState * pFontSampler ;
ID3D10ShaderResourceView * pFontTextureView ;
ID3D10RasterizerState * pRasterizerState ;
ID3D10BlendState * pBlendState ;
ID3D10DepthStencilState * pDepthStencilState ;
int VertexBufferSize ;
int IndexBufferSize ;
2021-11-11 21:22:24 +01:00
2023-04-14 17:44:25 +02:00
ImGui_ImplDX10_Data () { memset (( void * ) this , 0 , sizeof ( * this )); VertexBufferSize = 5000 ; IndexBufferSize = 10000 ; }
};
struct VERTEX_CONSTANT_BUFFER_DX10
2021-11-11 21:22:24 +01:00
{
float mvp [ 4 ][ 4 ];
};
2023-04-14 17:44:25 +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_ImplDX10_Data * ImGui_ImplDX10_GetBackendData ()
{
return ImGui :: GetCurrentContext () ? ( ImGui_ImplDX10_Data * ) ImGui :: GetIO (). BackendRendererUserData : nullptr ;
}
2021-11-11 21:22:24 +01:00
2023-04-14 17:44:25 +02:00
// Functions
2021-11-11 21:22:24 +01:00
static void ImGui_ImplDX10_SetupRenderState ( ImDrawData * draw_data , ID3D10Device * ctx )
{
2023-04-14 17:44:25 +02:00
ImGui_ImplDX10_Data * bd = ImGui_ImplDX10_GetBackendData ();
2021-11-11 21:22:24 +01:00
// Setup viewport
D3D10_VIEWPORT vp ;
memset ( & vp , 0 , sizeof ( D3D10_VIEWPORT ));
vp . Width = ( UINT ) draw_data -> DisplaySize . x ;
vp . Height = ( UINT ) draw_data -> DisplaySize . y ;
vp . MinDepth = 0.0f ;
vp . MaxDepth = 1.0f ;
vp . TopLeftX = vp . TopLeftY = 0 ;
ctx -> RSSetViewports ( 1 , & vp );
// Bind shader and vertex buffers
unsigned int stride = sizeof ( ImDrawVert );
unsigned int offset = 0 ;
2023-04-14 17:44:25 +02:00
ctx -> IASetInputLayout ( bd -> pInputLayout );
ctx -> IASetVertexBuffers ( 0 , 1 , & bd -> pVB , & stride , & offset );
ctx -> IASetIndexBuffer ( bd -> pIB , sizeof ( ImDrawIdx ) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT , 0 );
2021-11-11 21:22:24 +01:00
ctx -> IASetPrimitiveTopology ( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
2023-04-14 17:44:25 +02:00
ctx -> VSSetShader ( bd -> pVertexShader );
ctx -> VSSetConstantBuffers ( 0 , 1 , & bd -> pVertexConstantBuffer );
ctx -> PSSetShader ( bd -> pPixelShader );
ctx -> PSSetSamplers ( 0 , 1 , & bd -> pFontSampler );
ctx -> GSSetShader ( nullptr );
2021-11-11 21:22:24 +01:00
// Setup render state
const float blend_factor [ 4 ] = { 0.f , 0.f , 0.f , 0.f };
2023-04-14 17:44:25 +02:00
ctx -> OMSetBlendState ( bd -> pBlendState , blend_factor , 0xffffffff );
ctx -> OMSetDepthStencilState ( bd -> pDepthStencilState , 0 );
ctx -> RSSetState ( bd -> pRasterizerState );
2021-11-11 21:22:24 +01:00
}
// Render function
void ImGui_ImplDX10_RenderDrawData ( ImDrawData * draw_data )
{
// Avoid rendering when minimized
if ( draw_data -> DisplaySize . x <= 0.0f || draw_data -> DisplaySize . y <= 0.0f )
return ;
2023-04-14 17:44:25 +02:00
ImGui_ImplDX10_Data * bd = ImGui_ImplDX10_GetBackendData ();
ID3D10Device * ctx = bd -> pd3dDevice ;
2021-11-11 21:22:24 +01:00
// Create and grow vertex/index buffers if needed
2023-04-14 17:44:25 +02:00
if ( ! bd -> pVB || bd -> VertexBufferSize < draw_data -> TotalVtxCount )
2021-11-11 21:22:24 +01:00
{
2023-04-14 17:44:25 +02:00
if ( bd -> pVB ) { bd -> pVB -> Release (); bd -> pVB = nullptr ; }
bd -> VertexBufferSize = draw_data -> TotalVtxCount + 5000 ;
2021-11-11 21:22:24 +01:00
D3D10_BUFFER_DESC desc ;
memset ( & desc , 0 , sizeof ( D3D10_BUFFER_DESC ));
desc . Usage = D3D10_USAGE_DYNAMIC ;
2023-04-14 17:44:25 +02:00
desc . ByteWidth = bd -> VertexBufferSize * sizeof ( ImDrawVert );
2021-11-11 21:22:24 +01:00
desc . BindFlags = D3D10_BIND_VERTEX_BUFFER ;
desc . CPUAccessFlags = D3D10_CPU_ACCESS_WRITE ;
desc . MiscFlags = 0 ;
2023-04-14 17:44:25 +02:00
if ( ctx -> CreateBuffer ( & desc , nullptr , & bd -> pVB ) < 0 )
2021-11-11 21:22:24 +01:00
return ;
}
2023-04-14 17:44:25 +02:00
if ( ! bd -> pIB || bd -> IndexBufferSize < draw_data -> TotalIdxCount )
2021-11-11 21:22:24 +01:00
{
2023-04-14 17:44:25 +02:00
if ( bd -> pIB ) { bd -> pIB -> Release (); bd -> pIB = nullptr ; }
bd -> IndexBufferSize = draw_data -> TotalIdxCount + 10000 ;
2021-11-11 21:22:24 +01:00
D3D10_BUFFER_DESC desc ;
memset ( & desc , 0 , sizeof ( D3D10_BUFFER_DESC ));
desc . Usage = D3D10_USAGE_DYNAMIC ;
2023-04-14 17:44:25 +02:00
desc . ByteWidth = bd -> IndexBufferSize * sizeof ( ImDrawIdx );
2021-11-11 21:22:24 +01:00
desc . BindFlags = D3D10_BIND_INDEX_BUFFER ;
desc . CPUAccessFlags = D3D10_CPU_ACCESS_WRITE ;
2023-04-14 17:44:25 +02:00
if ( ctx -> CreateBuffer ( & desc , nullptr , & bd -> pIB ) < 0 )
2021-11-11 21:22:24 +01:00
return ;
}
// Copy and convert all vertices into a single contiguous buffer
2023-04-14 17:44:25 +02:00
ImDrawVert * vtx_dst = nullptr ;
ImDrawIdx * idx_dst = nullptr ;
bd -> pVB -> Map ( D3D10_MAP_WRITE_DISCARD , 0 , ( void ** ) & vtx_dst );
bd -> pIB -> Map ( D3D10_MAP_WRITE_DISCARD , 0 , ( void ** ) & idx_dst );
2021-11-11 21:22:24 +01:00
for ( int n = 0 ; n < draw_data -> CmdListsCount ; n ++ )
{
const ImDrawList * cmd_list = draw_data -> CmdLists [ n ];
memcpy ( vtx_dst , cmd_list -> VtxBuffer . Data , cmd_list -> VtxBuffer . Size * sizeof ( ImDrawVert ));
memcpy ( idx_dst , cmd_list -> IdxBuffer . Data , cmd_list -> IdxBuffer . Size * sizeof ( ImDrawIdx ));
vtx_dst += cmd_list -> VtxBuffer . Size ;
idx_dst += cmd_list -> IdxBuffer . Size ;
}
2023-04-14 17:44:25 +02:00
bd -> pVB -> Unmap ();
bd -> pIB -> Unmap ();
2021-11-11 21:22:24 +01:00
// Setup orthographic projection matrix into our constant buffer
// 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.
{
void * mapped_resource ;
2023-04-14 17:44:25 +02:00
if ( bd -> pVertexConstantBuffer -> Map ( D3D10_MAP_WRITE_DISCARD , 0 , & mapped_resource ) != S_OK )
2021-11-11 21:22:24 +01:00
return ;
2023-04-14 17:44:25 +02:00
VERTEX_CONSTANT_BUFFER_DX10 * constant_buffer = ( VERTEX_CONSTANT_BUFFER_DX10 * ) mapped_resource ;
2021-11-11 21:22:24 +01:00
float L = draw_data -> DisplayPos . x ;
float R = draw_data -> DisplayPos . x + draw_data -> DisplaySize . x ;
float T = draw_data -> DisplayPos . y ;
float B = draw_data -> DisplayPos . y + draw_data -> DisplaySize . y ;
float mvp [ 4 ][ 4 ] =
{
{ 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 },
{ ( R + L ) / ( L - R ), ( T + B ) / ( B - T ), 0.5f , 1.0f },
};
memcpy ( & constant_buffer -> mvp , mvp , sizeof ( mvp ));
2023-04-14 17:44:25 +02:00
bd -> pVertexConstantBuffer -> Unmap ();
2021-11-11 21:22:24 +01:00
}
// Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!)
struct BACKUP_DX10_STATE
{
UINT ScissorRectsCount , ViewportsCount ;
D3D10_RECT ScissorRects [ D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE ];
D3D10_VIEWPORT Viewports [ D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE ];
ID3D10RasterizerState * RS ;
ID3D10BlendState * BlendState ;
FLOAT BlendFactor [ 4 ];
UINT SampleMask ;
UINT StencilRef ;
ID3D10DepthStencilState * DepthStencilState ;
ID3D10ShaderResourceView * PSShaderResource ;
ID3D10SamplerState * PSSampler ;
ID3D10PixelShader * PS ;
ID3D10VertexShader * VS ;
ID3D10GeometryShader * GS ;
D3D10_PRIMITIVE_TOPOLOGY PrimitiveTopology ;
ID3D10Buffer * IndexBuffer , * VertexBuffer , * VSConstantBuffer ;
UINT IndexBufferOffset , VertexBufferStride , VertexBufferOffset ;
DXGI_FORMAT IndexBufferFormat ;
ID3D10InputLayout * InputLayout ;
};
2023-04-14 17:44:25 +02:00
BACKUP_DX10_STATE old = {};
2021-11-11 21:22:24 +01:00
old . ScissorRectsCount = old . ViewportsCount = D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE ;
ctx -> RSGetScissorRects ( & old . ScissorRectsCount , old . ScissorRects );
ctx -> RSGetViewports ( & old . ViewportsCount , old . Viewports );
ctx -> RSGetState ( & old . RS );
ctx -> OMGetBlendState ( & old . BlendState , old . BlendFactor , & old . SampleMask );
ctx -> OMGetDepthStencilState ( & old . DepthStencilState , & old . StencilRef );
ctx -> PSGetShaderResources ( 0 , 1 , & old . PSShaderResource );
ctx -> PSGetSamplers ( 0 , 1 , & old . PSSampler );
ctx -> PSGetShader ( & old . PS );
ctx -> VSGetShader ( & old . VS );
ctx -> VSGetConstantBuffers ( 0 , 1 , & old . VSConstantBuffer );
ctx -> GSGetShader ( & old . GS );
ctx -> IAGetPrimitiveTopology ( & old . PrimitiveTopology );
ctx -> IAGetIndexBuffer ( & old . IndexBuffer , & old . IndexBufferFormat , & old . IndexBufferOffset );
ctx -> IAGetVertexBuffers ( 0 , 1 , & old . VertexBuffer , & old . VertexBufferStride , & old . VertexBufferOffset );
ctx -> IAGetInputLayout ( & old . InputLayout );
// Setup desired DX state
ImGui_ImplDX10_SetupRenderState ( draw_data , ctx );
// Render command lists
// (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 ;
ImVec2 clip_off = draw_data -> DisplayPos ;
for ( int n = 0 ; n < draw_data -> CmdListsCount ; n ++ )
{
const ImDrawList * cmd_list = draw_data -> CmdLists [ n ];
for ( int cmd_i = 0 ; cmd_i < cmd_list -> CmdBuffer . Size ; cmd_i ++ )
{
const ImDrawCmd * pcmd = & cmd_list -> CmdBuffer [ cmd_i ];
if ( pcmd -> UserCallback )
{
// User callback, registered via ImDrawList::AddCallback()
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
if ( pcmd -> UserCallback == ImDrawCallback_ResetRenderState )
ImGui_ImplDX10_SetupRenderState ( draw_data , ctx );
else
pcmd -> UserCallback ( cmd_list , pcmd );
}
else
{
2023-04-14 17:44:25 +02: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 );
if ( clip_max . x <= clip_min . x || clip_max . y <= clip_min . y )
continue ;
2021-11-11 21:22:24 +01:00
// Apply scissor/clipping rectangle
2023-04-14 17:44:25 +02:00
const D3D10_RECT r = { ( LONG ) clip_min . x , ( LONG ) clip_min . y , ( LONG ) clip_max . x , ( LONG ) clip_max . y };
2021-11-11 21:22:24 +01:00
ctx -> RSSetScissorRects ( 1 , & r );
// Bind texture, Draw
2023-04-14 17:44:25 +02:00
ID3D10ShaderResourceView * texture_srv = ( ID3D10ShaderResourceView * ) pcmd -> GetTexID ();
2021-11-11 21:22:24 +01:00
ctx -> PSSetShaderResources ( 0 , 1 , & texture_srv );
ctx -> DrawIndexed ( pcmd -> ElemCount , pcmd -> IdxOffset + global_idx_offset , pcmd -> VtxOffset + global_vtx_offset );
}
}
global_idx_offset += cmd_list -> IdxBuffer . Size ;
global_vtx_offset += cmd_list -> VtxBuffer . Size ;
}
// Restore modified DX state
ctx -> RSSetScissorRects ( old . ScissorRectsCount , old . ScissorRects );
ctx -> RSSetViewports ( old . ViewportsCount , old . Viewports );
ctx -> RSSetState ( old . RS ); if ( old . RS ) old . RS -> Release ();
ctx -> OMSetBlendState ( old . BlendState , old . BlendFactor , old . SampleMask ); if ( old . BlendState ) old . BlendState -> Release ();
ctx -> OMSetDepthStencilState ( old . DepthStencilState , old . StencilRef ); if ( old . DepthStencilState ) old . DepthStencilState -> Release ();
ctx -> PSSetShaderResources ( 0 , 1 , & old . PSShaderResource ); if ( old . PSShaderResource ) old . PSShaderResource -> Release ();
ctx -> PSSetSamplers ( 0 , 1 , & old . PSSampler ); if ( old . PSSampler ) old . PSSampler -> Release ();
ctx -> PSSetShader ( old . PS ); if ( old . PS ) old . PS -> Release ();
ctx -> VSSetShader ( old . VS ); if ( old . VS ) old . VS -> Release ();
ctx -> GSSetShader ( old . GS ); if ( old . GS ) old . GS -> Release ();
ctx -> VSSetConstantBuffers ( 0 , 1 , & old . VSConstantBuffer ); if ( old . VSConstantBuffer ) old . VSConstantBuffer -> Release ();
ctx -> IASetPrimitiveTopology ( old . PrimitiveTopology );
ctx -> IASetIndexBuffer ( old . IndexBuffer , old . IndexBufferFormat , old . IndexBufferOffset ); if ( old . IndexBuffer ) old . IndexBuffer -> Release ();
ctx -> IASetVertexBuffers ( 0 , 1 , & old . VertexBuffer , & old . VertexBufferStride , & old . VertexBufferOffset ); if ( old . VertexBuffer ) old . VertexBuffer -> Release ();
ctx -> IASetInputLayout ( old . InputLayout ); if ( old . InputLayout ) old . InputLayout -> Release ();
}
static void ImGui_ImplDX10_CreateFontsTexture ()
{
// Build texture atlas
2023-04-14 17:44:25 +02:00
ImGui_ImplDX10_Data * bd = ImGui_ImplDX10_GetBackendData ();
2021-11-11 21:22:24 +01:00
ImGuiIO & io = ImGui :: GetIO ();
unsigned char * pixels ;
int width , height ;
io . Fonts -> GetTexDataAsRGBA32 ( & pixels , & width , & height );
// Upload texture to graphics system
{
D3D10_TEXTURE2D_DESC desc ;
ZeroMemory ( & desc , sizeof ( desc ));
desc . Width = width ;
desc . Height = height ;
desc . MipLevels = 1 ;
desc . ArraySize = 1 ;
desc . Format = DXGI_FORMAT_R8G8B8A8_UNORM ;
desc . SampleDesc . Count = 1 ;
desc . Usage = D3D10_USAGE_DEFAULT ;
desc . BindFlags = D3D10_BIND_SHADER_RESOURCE ;
desc . CPUAccessFlags = 0 ;
2023-04-14 17:44:25 +02:00
ID3D10Texture2D * pTexture = nullptr ;
2021-11-11 21:22:24 +01:00
D3D10_SUBRESOURCE_DATA subResource ;
subResource . pSysMem = pixels ;
subResource . SysMemPitch = desc . Width * 4 ;
subResource . SysMemSlicePitch = 0 ;
2023-04-14 17:44:25 +02:00
bd -> pd3dDevice -> CreateTexture2D ( & desc , & subResource , & pTexture );
IM_ASSERT ( pTexture != nullptr );
2021-11-11 21:22:24 +01:00
// Create texture view
D3D10_SHADER_RESOURCE_VIEW_DESC srv_desc ;
ZeroMemory ( & srv_desc , sizeof ( srv_desc ));
srv_desc . Format = DXGI_FORMAT_R8G8B8A8_UNORM ;
srv_desc . ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D ;
srv_desc . Texture2D . MipLevels = desc . MipLevels ;
srv_desc . Texture2D . MostDetailedMip = 0 ;
2023-04-14 17:44:25 +02:00
bd -> pd3dDevice -> CreateShaderResourceView ( pTexture , & srv_desc , & bd -> pFontTextureView );
2021-11-11 21:22:24 +01:00
pTexture -> Release ();
}
// Store our identifier
2023-04-14 17:44:25 +02:00
io . Fonts -> SetTexID (( ImTextureID ) bd -> pFontTextureView );
2021-11-11 21:22:24 +01:00
// Create texture sampler
2023-04-14 17:44:25 +02:00
// (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
2021-11-11 21:22:24 +01:00
{
D3D10_SAMPLER_DESC desc ;
ZeroMemory ( & desc , sizeof ( desc ));
desc . Filter = D3D10_FILTER_MIN_MAG_MIP_LINEAR ;
desc . AddressU = D3D10_TEXTURE_ADDRESS_WRAP ;
desc . AddressV = D3D10_TEXTURE_ADDRESS_WRAP ;
desc . AddressW = D3D10_TEXTURE_ADDRESS_WRAP ;
desc . MipLODBias = 0.f ;
desc . ComparisonFunc = D3D10_COMPARISON_ALWAYS ;
desc . MinLOD = 0.f ;
desc . MaxLOD = 0.f ;
2023-04-14 17:44:25 +02:00
bd -> pd3dDevice -> CreateSamplerState ( & desc , & bd -> pFontSampler );
2021-11-11 21:22:24 +01:00
}
}
bool ImGui_ImplDX10_CreateDeviceObjects ()
{
2023-04-14 17:44:25 +02:00
ImGui_ImplDX10_Data * bd = ImGui_ImplDX10_GetBackendData ();
if ( ! bd -> pd3dDevice )
2021-11-11 21:22:24 +01:00
return false ;
2023-04-14 17:44:25 +02:00
if ( bd -> pFontSampler )
2021-11-11 21:22:24 +01:00
ImGui_ImplDX10_InvalidateDeviceObjects ();
// By using D3DCompile() from <d3dcompiler.h> / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A)
// If you would like to use this DX10 sample code but remove this dependency you can:
// 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [preferred solution]
// 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL.
// See https://github.com/ocornut/imgui/pull/638 for sources and details.
// Create the vertex shader
{
static const char * vertexShader =
"cbuffer vertexBuffer : register(b0) \
{\
float4x4 ProjectionMatrix; \
};\
struct VS_INPUT\
{\
float2 pos : POSITION;\
float4 col : COLOR0;\
float2 uv : TEXCOORD0;\
};\
\
struct PS_INPUT\
{\
float4 pos : SV_POSITION;\
float4 col : COLOR0;\
float2 uv : TEXCOORD0;\
};\
\
PS_INPUT main(VS_INPUT input)\
{\
PS_INPUT output;\
output.pos = mul( ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));\
output.col = input.col;\
output.uv = input.uv;\
return output;\
}" ;
ID3DBlob * vertexShaderBlob ;
2023-04-14 17:44:25 +02:00
if ( FAILED ( D3DCompile ( vertexShader , strlen ( vertexShader ), nullptr , nullptr , nullptr , "main" , "vs_4_0" , 0 , 0 , & vertexShaderBlob , nullptr )))
2021-11-11 21:22:24 +01:00
return false ; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
2023-04-14 17:44:25 +02:00
if ( bd -> pd3dDevice -> CreateVertexShader ( vertexShaderBlob -> GetBufferPointer (), vertexShaderBlob -> GetBufferSize (), & bd -> pVertexShader ) != S_OK )
2021-11-11 21:22:24 +01:00
{
vertexShaderBlob -> Release ();
return false ;
}
// Create the input layout
D3D10_INPUT_ELEMENT_DESC local_layout [] =
{
{ "POSITION" , 0 , DXGI_FORMAT_R32G32_FLOAT , 0 , ( UINT ) IM_OFFSETOF ( ImDrawVert , pos ), D3D10_INPUT_PER_VERTEX_DATA , 0 },
{ "TEXCOORD" , 0 , DXGI_FORMAT_R32G32_FLOAT , 0 , ( UINT ) IM_OFFSETOF ( ImDrawVert , uv ), D3D10_INPUT_PER_VERTEX_DATA , 0 },
{ "COLOR" , 0 , DXGI_FORMAT_R8G8B8A8_UNORM , 0 , ( UINT ) IM_OFFSETOF ( ImDrawVert , col ), D3D10_INPUT_PER_VERTEX_DATA , 0 },
};
2023-04-14 17:44:25 +02:00
if ( bd -> pd3dDevice -> CreateInputLayout ( local_layout , 3 , vertexShaderBlob -> GetBufferPointer (), vertexShaderBlob -> GetBufferSize (), & bd -> pInputLayout ) != S_OK )
2021-11-11 21:22:24 +01:00
{
vertexShaderBlob -> Release ();
return false ;
}
vertexShaderBlob -> Release ();
// Create the constant buffer
{
D3D10_BUFFER_DESC desc ;
2023-04-14 17:44:25 +02:00
desc . ByteWidth = sizeof ( VERTEX_CONSTANT_BUFFER_DX10 );
2021-11-11 21:22:24 +01:00
desc . Usage = D3D10_USAGE_DYNAMIC ;
desc . BindFlags = D3D10_BIND_CONSTANT_BUFFER ;
desc . CPUAccessFlags = D3D10_CPU_ACCESS_WRITE ;
desc . MiscFlags = 0 ;
2023-04-14 17:44:25 +02:00
bd -> pd3dDevice -> CreateBuffer ( & desc , nullptr , & bd -> pVertexConstantBuffer );
2021-11-11 21:22:24 +01:00
}
}
// Create the pixel shader
{
static const char * pixelShader =
"struct PS_INPUT\
{\
float4 pos : SV_POSITION;\
float4 col : COLOR0;\
float2 uv : TEXCOORD0;\
};\
sampler sampler0;\
Texture2D texture0;\
\
float4 main(PS_INPUT input) : SV_Target\
{\
float4 out_col = input.col * texture0.Sample(sampler0, input.uv); \
return out_col; \
}" ;
ID3DBlob * pixelShaderBlob ;
2023-04-14 17:44:25 +02:00
if ( FAILED ( D3DCompile ( pixelShader , strlen ( pixelShader ), nullptr , nullptr , nullptr , "main" , "ps_4_0" , 0 , 0 , & pixelShaderBlob , nullptr )))
2021-11-11 21:22:24 +01:00
return false ; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
2023-04-14 17:44:25 +02:00
if ( bd -> pd3dDevice -> CreatePixelShader ( pixelShaderBlob -> GetBufferPointer (), pixelShaderBlob -> GetBufferSize (), & bd -> pPixelShader ) != S_OK )
2021-11-11 21:22:24 +01:00
{
pixelShaderBlob -> Release ();
return false ;
}
pixelShaderBlob -> Release ();
}
// Create the blending setup
{
D3D10_BLEND_DESC desc ;
ZeroMemory ( & desc , sizeof ( desc ));
desc . AlphaToCoverageEnable = false ;
desc . BlendEnable [ 0 ] = true ;
desc . SrcBlend = D3D10_BLEND_SRC_ALPHA ;
desc . DestBlend = D3D10_BLEND_INV_SRC_ALPHA ;
desc . BlendOp = D3D10_BLEND_OP_ADD ;
2023-04-14 17:44:25 +02:00
desc . SrcBlendAlpha = D3D10_BLEND_ONE ;
desc . DestBlendAlpha = D3D10_BLEND_INV_SRC_ALPHA ;
2021-11-11 21:22:24 +01:00
desc . BlendOpAlpha = D3D10_BLEND_OP_ADD ;
desc . RenderTargetWriteMask [ 0 ] = D3D10_COLOR_WRITE_ENABLE_ALL ;
2023-04-14 17:44:25 +02:00
bd -> pd3dDevice -> CreateBlendState ( & desc , & bd -> pBlendState );
2021-11-11 21:22:24 +01:00
}
// Create the rasterizer state
{
D3D10_RASTERIZER_DESC desc ;
ZeroMemory ( & desc , sizeof ( desc ));
desc . FillMode = D3D10_FILL_SOLID ;
desc . CullMode = D3D10_CULL_NONE ;
desc . ScissorEnable = true ;
desc . DepthClipEnable = true ;
2023-04-14 17:44:25 +02:00
bd -> pd3dDevice -> CreateRasterizerState ( & desc , & bd -> pRasterizerState );
2021-11-11 21:22:24 +01:00
}
// Create depth-stencil State
{
D3D10_DEPTH_STENCIL_DESC desc ;
ZeroMemory ( & desc , sizeof ( desc ));
desc . DepthEnable = false ;
desc . DepthWriteMask = D3D10_DEPTH_WRITE_MASK_ALL ;
desc . DepthFunc = D3D10_COMPARISON_ALWAYS ;
desc . StencilEnable = false ;
desc . FrontFace . StencilFailOp = desc . FrontFace . StencilDepthFailOp = desc . FrontFace . StencilPassOp = D3D10_STENCIL_OP_KEEP ;
desc . FrontFace . StencilFunc = D3D10_COMPARISON_ALWAYS ;
desc . BackFace = desc . FrontFace ;
2023-04-14 17:44:25 +02:00
bd -> pd3dDevice -> CreateDepthStencilState ( & desc , & bd -> pDepthStencilState );
2021-11-11 21:22:24 +01:00
}
ImGui_ImplDX10_CreateFontsTexture ();
return true ;
}
void ImGui_ImplDX10_InvalidateDeviceObjects ()
{
2023-04-14 17:44:25 +02:00
ImGui_ImplDX10_Data * bd = ImGui_ImplDX10_GetBackendData ();
if ( ! bd -> pd3dDevice )
2021-11-11 21:22:24 +01:00
return ;
2023-04-14 17:44:25 +02:00
if ( bd -> pFontSampler ) { bd -> pFontSampler -> Release (); bd -> pFontSampler = nullptr ; }
if ( bd -> pFontTextureView ) { bd -> pFontTextureView -> Release (); bd -> pFontTextureView = nullptr ; ImGui :: GetIO (). Fonts -> SetTexID ( 0 ); } // We copied bd->pFontTextureView to io.Fonts->TexID so let's clear that as well.
if ( bd -> pIB ) { bd -> pIB -> Release (); bd -> pIB = nullptr ; }
if ( bd -> pVB ) { bd -> pVB -> Release (); bd -> pVB = nullptr ; }
if ( bd -> pBlendState ) { bd -> pBlendState -> Release (); bd -> pBlendState = nullptr ; }
if ( bd -> pDepthStencilState ) { bd -> pDepthStencilState -> Release (); bd -> pDepthStencilState = nullptr ; }
if ( bd -> pRasterizerState ) { bd -> pRasterizerState -> Release (); bd -> pRasterizerState = nullptr ; }
if ( bd -> pPixelShader ) { bd -> pPixelShader -> Release (); bd -> pPixelShader = nullptr ; }
if ( bd -> pVertexConstantBuffer ) { bd -> pVertexConstantBuffer -> Release (); bd -> pVertexConstantBuffer = nullptr ; }
if ( bd -> pInputLayout ) { bd -> pInputLayout -> Release (); bd -> pInputLayout = nullptr ; }
if ( bd -> pVertexShader ) { bd -> pVertexShader -> Release (); bd -> pVertexShader = nullptr ; }
2021-11-11 21:22:24 +01:00
}
bool ImGui_ImplDX10_Init ( ID3D10Device * device )
{
ImGuiIO & io = ImGui :: GetIO ();
2023-04-14 17:44:25 +02:00
IM_ASSERT ( io . BackendRendererUserData == nullptr && "Already initialized a renderer backend!" );
// Setup backend capabilities flags
ImGui_ImplDX10_Data * bd = IM_NEW ( ImGui_ImplDX10_Data )();
io . BackendRendererUserData = ( void * ) bd ;
2021-11-11 21:22:24 +01:00
io . BackendRendererName = "imgui_impl_dx10" ;
io . BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset ; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
// Get factory from device
2023-04-14 17:44:25 +02:00
IDXGIDevice * pDXGIDevice = nullptr ;
IDXGIAdapter * pDXGIAdapter = nullptr ;
IDXGIFactory * pFactory = nullptr ;
2021-11-11 21:22:24 +01:00
if ( device -> QueryInterface ( IID_PPV_ARGS ( & pDXGIDevice )) == S_OK )
if ( pDXGIDevice -> GetParent ( IID_PPV_ARGS ( & pDXGIAdapter )) == S_OK )
if ( pDXGIAdapter -> GetParent ( IID_PPV_ARGS ( & pFactory )) == S_OK )
{
2023-04-14 17:44:25 +02:00
bd -> pd3dDevice = device ;
bd -> pFactory = pFactory ;
2021-11-11 21:22:24 +01:00
}
if ( pDXGIDevice ) pDXGIDevice -> Release ();
if ( pDXGIAdapter ) pDXGIAdapter -> Release ();
2023-04-14 17:44:25 +02:00
bd -> pd3dDevice -> AddRef ();
2021-11-11 21:22:24 +01:00
return true ;
}
void ImGui_ImplDX10_Shutdown ()
{
2023-04-14 17:44:25 +02:00
ImGui_ImplDX10_Data * bd = ImGui_ImplDX10_GetBackendData ();
IM_ASSERT ( bd != nullptr && "No renderer backend to shutdown, or already shutdown?" );
ImGuiIO & io = ImGui :: GetIO ();
2021-11-11 21:22:24 +01:00
ImGui_ImplDX10_InvalidateDeviceObjects ();
2023-04-14 17:44:25 +02:00
if ( bd -> pFactory ) { bd -> pFactory -> Release (); }
if ( bd -> pd3dDevice ) { bd -> pd3dDevice -> Release (); }
io . BackendRendererName = nullptr ;
io . BackendRendererUserData = nullptr ;
IM_DELETE ( bd );
2021-11-11 21:22:24 +01:00
}
void ImGui_ImplDX10_NewFrame ()
{
2023-04-14 17:44:25 +02:00
ImGui_ImplDX10_Data * bd = ImGui_ImplDX10_GetBackendData ();
IM_ASSERT ( bd != nullptr && "Did you call ImGui_ImplDX10_Init()?" );
if ( ! bd -> pFontSampler )
2021-11-11 21:22:24 +01:00
ImGui_ImplDX10_CreateDeviceObjects ();
}