• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // dear imgui: Renderer Backend for DirectX10
2 // This needs to be used along with a Platform Backend (e.g. Win32)
3 
4 // Implemented features:
5 //  [X] Renderer: User texture backend. Use 'ID3D10ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID!
6 //  [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
7 
8 // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
9 // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
10 // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
11 // Read online: https://github.com/ocornut/imgui/tree/master/docs
12 
13 // CHANGELOG
14 // (minor and older changes stripped away, please see git history for details)
15 //  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).
16 //  2021-05-19: DirectX10: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
17 //  2021-02-18: DirectX10: Change blending equation to preserve alpha in output buffer.
18 //  2019-07-21: DirectX10: Backup, clear and restore Geometry Shader is any is bound when calling ImGui_ImplDX10_RenderDrawData().
19 //  2019-05-29: DirectX10: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
20 //  2019-04-30: DirectX10: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
21 //  2018-12-03: Misc: Added #pragma comment statement to automatically link with d3dcompiler.lib when using D3DCompile().
22 //  2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
23 //  2018-07-13: DirectX10: Fixed unreleased resources in Init and Shutdown functions.
24 //  2018-06-08: Misc: Extracted imgui_impl_dx10.cpp/.h away from the old combined DX10+Win32 example.
25 //  2018-06-08: DirectX10: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
26 //  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.
27 //  2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX10_RenderDrawData() in the .h file so you can call it yourself.
28 //  2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
29 //  2016-05-07: DirectX10: Disabling depth-write.
30 
31 #include "imgui.h"
32 #include "imgui_impl_dx10.h"
33 
34 // DirectX
35 #include <stdio.h>
36 #include <d3d10_1.h>
37 #include <d3d10.h>
38 #include <d3dcompiler.h>
39 #ifdef _MSC_VER
40 #pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below.
41 #endif
42 
43 // DirectX data
44 struct ImGui_ImplDX10_Data
45 {
46     ID3D10Device*               pd3dDevice;
47     IDXGIFactory*               pFactory;
48     ID3D10Buffer*               pVB;
49     ID3D10Buffer*               pIB;
50     ID3D10VertexShader*         pVertexShader;
51     ID3D10InputLayout*          pInputLayout;
52     ID3D10Buffer*               pVertexConstantBuffer;
53     ID3D10PixelShader*          pPixelShader;
54     ID3D10SamplerState*         pFontSampler;
55     ID3D10ShaderResourceView*   pFontTextureView;
56     ID3D10RasterizerState*      pRasterizerState;
57     ID3D10BlendState*           pBlendState;
58     ID3D10DepthStencilState*    pDepthStencilState;
59     int                         VertexBufferSize;
60     int                         IndexBufferSize;
61 
ImGui_ImplDX10_DataImGui_ImplDX10_Data62     ImGui_ImplDX10_Data()       { memset(this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; }
63 };
64 
65 struct VERTEX_CONSTANT_BUFFER
66 {
67     float   mvp[4][4];
68 };
69 
70 // Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
71 // It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
ImGui_ImplDX10_GetBackendData()72 static ImGui_ImplDX10_Data* ImGui_ImplDX10_GetBackendData()
73 {
74     return ImGui::GetCurrentContext() ? (ImGui_ImplDX10_Data*)ImGui::GetIO().BackendRendererUserData : NULL;
75 }
76 
77 // Functions
ImGui_ImplDX10_SetupRenderState(ImDrawData * draw_data,ID3D10Device * ctx)78 static void ImGui_ImplDX10_SetupRenderState(ImDrawData* draw_data, ID3D10Device* ctx)
79 {
80     ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
81 
82     // Setup viewport
83     D3D10_VIEWPORT vp;
84     memset(&vp, 0, sizeof(D3D10_VIEWPORT));
85     vp.Width = (UINT)draw_data->DisplaySize.x;
86     vp.Height = (UINT)draw_data->DisplaySize.y;
87     vp.MinDepth = 0.0f;
88     vp.MaxDepth = 1.0f;
89     vp.TopLeftX = vp.TopLeftY = 0;
90     ctx->RSSetViewports(1, &vp);
91 
92     // Bind shader and vertex buffers
93     unsigned int stride = sizeof(ImDrawVert);
94     unsigned int offset = 0;
95     ctx->IASetInputLayout(bd->pInputLayout);
96     ctx->IASetVertexBuffers(0, 1, &bd->pVB, &stride, &offset);
97     ctx->IASetIndexBuffer(bd->pIB, sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0);
98     ctx->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
99     ctx->VSSetShader(bd->pVertexShader);
100     ctx->VSSetConstantBuffers(0, 1, &bd->pVertexConstantBuffer);
101     ctx->PSSetShader(bd->pPixelShader);
102     ctx->PSSetSamplers(0, 1, &bd->pFontSampler);
103     ctx->GSSetShader(NULL);
104 
105     // Setup render state
106     const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f };
107     ctx->OMSetBlendState(bd->pBlendState, blend_factor, 0xffffffff);
108     ctx->OMSetDepthStencilState(bd->pDepthStencilState, 0);
109     ctx->RSSetState(bd->pRasterizerState);
110 }
111 
112 // Render function
ImGui_ImplDX10_RenderDrawData(ImDrawData * draw_data)113 void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
114 {
115     // Avoid rendering when minimized
116     if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
117         return;
118 
119     ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
120     ID3D10Device* ctx = bd->pd3dDevice;
121 
122     // Create and grow vertex/index buffers if needed
123     if (!bd->pVB || bd->VertexBufferSize < draw_data->TotalVtxCount)
124     {
125         if (bd->pVB) { bd->pVB->Release(); bd->pVB = NULL; }
126         bd->VertexBufferSize = draw_data->TotalVtxCount + 5000;
127         D3D10_BUFFER_DESC desc;
128         memset(&desc, 0, sizeof(D3D10_BUFFER_DESC));
129         desc.Usage = D3D10_USAGE_DYNAMIC;
130         desc.ByteWidth = bd->VertexBufferSize * sizeof(ImDrawVert);
131         desc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
132         desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
133         desc.MiscFlags = 0;
134         if (ctx->CreateBuffer(&desc, NULL, &bd->pVB) < 0)
135             return;
136     }
137 
138     if (!bd->pIB || bd->IndexBufferSize < draw_data->TotalIdxCount)
139     {
140         if (bd->pIB) { bd->pIB->Release(); bd->pIB = NULL; }
141         bd->IndexBufferSize = draw_data->TotalIdxCount + 10000;
142         D3D10_BUFFER_DESC desc;
143         memset(&desc, 0, sizeof(D3D10_BUFFER_DESC));
144         desc.Usage = D3D10_USAGE_DYNAMIC;
145         desc.ByteWidth = bd->IndexBufferSize * sizeof(ImDrawIdx);
146         desc.BindFlags = D3D10_BIND_INDEX_BUFFER;
147         desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
148         if (ctx->CreateBuffer(&desc, NULL, &bd->pIB) < 0)
149             return;
150     }
151 
152     // Copy and convert all vertices into a single contiguous buffer
153     ImDrawVert* vtx_dst = NULL;
154     ImDrawIdx* idx_dst = NULL;
155     bd->pVB->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&vtx_dst);
156     bd->pIB->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&idx_dst);
157     for (int n = 0; n < draw_data->CmdListsCount; n++)
158     {
159         const ImDrawList* cmd_list = draw_data->CmdLists[n];
160         memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
161         memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
162         vtx_dst += cmd_list->VtxBuffer.Size;
163         idx_dst += cmd_list->IdxBuffer.Size;
164     }
165     bd->pVB->Unmap();
166     bd->pIB->Unmap();
167 
168     // Setup orthographic projection matrix into our constant buffer
169     // 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.
170     {
171         void* mapped_resource;
172         if (bd->pVertexConstantBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK)
173             return;
174         VERTEX_CONSTANT_BUFFER* constant_buffer = (VERTEX_CONSTANT_BUFFER*)mapped_resource;
175         float L = draw_data->DisplayPos.x;
176         float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
177         float T = draw_data->DisplayPos.y;
178         float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
179         float mvp[4][4] =
180         {
181             { 2.0f/(R-L),   0.0f,           0.0f,       0.0f },
182             { 0.0f,         2.0f/(T-B),     0.0f,       0.0f },
183             { 0.0f,         0.0f,           0.5f,       0.0f },
184             { (R+L)/(L-R),  (T+B)/(B-T),    0.5f,       1.0f },
185         };
186         memcpy(&constant_buffer->mvp, mvp, sizeof(mvp));
187         bd->pVertexConstantBuffer->Unmap();
188     }
189 
190     // Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!)
191     struct BACKUP_DX10_STATE
192     {
193         UINT                        ScissorRectsCount, ViewportsCount;
194         D3D10_RECT                  ScissorRects[D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
195         D3D10_VIEWPORT              Viewports[D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
196         ID3D10RasterizerState*      RS;
197         ID3D10BlendState*           BlendState;
198         FLOAT                       BlendFactor[4];
199         UINT                        SampleMask;
200         UINT                        StencilRef;
201         ID3D10DepthStencilState*    DepthStencilState;
202         ID3D10ShaderResourceView*   PSShaderResource;
203         ID3D10SamplerState*         PSSampler;
204         ID3D10PixelShader*          PS;
205         ID3D10VertexShader*         VS;
206         ID3D10GeometryShader*       GS;
207         D3D10_PRIMITIVE_TOPOLOGY    PrimitiveTopology;
208         ID3D10Buffer*               IndexBuffer, *VertexBuffer, *VSConstantBuffer;
209         UINT                        IndexBufferOffset, VertexBufferStride, VertexBufferOffset;
210         DXGI_FORMAT                 IndexBufferFormat;
211         ID3D10InputLayout*          InputLayout;
212     };
213     BACKUP_DX10_STATE old = {};
214     old.ScissorRectsCount = old.ViewportsCount = D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
215     ctx->RSGetScissorRects(&old.ScissorRectsCount, old.ScissorRects);
216     ctx->RSGetViewports(&old.ViewportsCount, old.Viewports);
217     ctx->RSGetState(&old.RS);
218     ctx->OMGetBlendState(&old.BlendState, old.BlendFactor, &old.SampleMask);
219     ctx->OMGetDepthStencilState(&old.DepthStencilState, &old.StencilRef);
220     ctx->PSGetShaderResources(0, 1, &old.PSShaderResource);
221     ctx->PSGetSamplers(0, 1, &old.PSSampler);
222     ctx->PSGetShader(&old.PS);
223     ctx->VSGetShader(&old.VS);
224     ctx->VSGetConstantBuffers(0, 1, &old.VSConstantBuffer);
225     ctx->GSGetShader(&old.GS);
226     ctx->IAGetPrimitiveTopology(&old.PrimitiveTopology);
227     ctx->IAGetIndexBuffer(&old.IndexBuffer, &old.IndexBufferFormat, &old.IndexBufferOffset);
228     ctx->IAGetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset);
229     ctx->IAGetInputLayout(&old.InputLayout);
230 
231     // Setup desired DX state
232     ImGui_ImplDX10_SetupRenderState(draw_data, ctx);
233 
234     // Render command lists
235     // (Because we merged all buffers into a single one, we maintain our own offset into them)
236     int global_vtx_offset = 0;
237     int global_idx_offset = 0;
238     ImVec2 clip_off = draw_data->DisplayPos;
239     for (int n = 0; n < draw_data->CmdListsCount; n++)
240     {
241         const ImDrawList* cmd_list = draw_data->CmdLists[n];
242         for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
243         {
244             const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
245             if (pcmd->UserCallback)
246             {
247                 // User callback, registered via ImDrawList::AddCallback()
248                 // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
249                 if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
250                     ImGui_ImplDX10_SetupRenderState(draw_data, ctx);
251                 else
252                     pcmd->UserCallback(cmd_list, pcmd);
253             }
254             else
255             {
256                 // Project scissor/clipping rectangles into framebuffer space
257                 ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
258                 ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
259                 if (clip_max.x < clip_min.x || clip_max.y < clip_min.y)
260                     continue;
261 
262                 // Apply scissor/clipping rectangle
263                 const D3D10_RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y };
264                 ctx->RSSetScissorRects(1, &r);
265 
266                 // Bind texture, Draw
267                 ID3D10ShaderResourceView* texture_srv = (ID3D10ShaderResourceView*)pcmd->GetTexID();
268                 ctx->PSSetShaderResources(0, 1, &texture_srv);
269                 ctx->DrawIndexed(pcmd->ElemCount, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset);
270             }
271         }
272         global_idx_offset += cmd_list->IdxBuffer.Size;
273         global_vtx_offset += cmd_list->VtxBuffer.Size;
274     }
275 
276     // Restore modified DX state
277     ctx->RSSetScissorRects(old.ScissorRectsCount, old.ScissorRects);
278     ctx->RSSetViewports(old.ViewportsCount, old.Viewports);
279     ctx->RSSetState(old.RS); if (old.RS) old.RS->Release();
280     ctx->OMSetBlendState(old.BlendState, old.BlendFactor, old.SampleMask); if (old.BlendState) old.BlendState->Release();
281     ctx->OMSetDepthStencilState(old.DepthStencilState, old.StencilRef); if (old.DepthStencilState) old.DepthStencilState->Release();
282     ctx->PSSetShaderResources(0, 1, &old.PSShaderResource); if (old.PSShaderResource) old.PSShaderResource->Release();
283     ctx->PSSetSamplers(0, 1, &old.PSSampler); if (old.PSSampler) old.PSSampler->Release();
284     ctx->PSSetShader(old.PS); if (old.PS) old.PS->Release();
285     ctx->VSSetShader(old.VS); if (old.VS) old.VS->Release();
286     ctx->GSSetShader(old.GS); if (old.GS) old.GS->Release();
287     ctx->VSSetConstantBuffers(0, 1, &old.VSConstantBuffer); if (old.VSConstantBuffer) old.VSConstantBuffer->Release();
288     ctx->IASetPrimitiveTopology(old.PrimitiveTopology);
289     ctx->IASetIndexBuffer(old.IndexBuffer, old.IndexBufferFormat, old.IndexBufferOffset); if (old.IndexBuffer) old.IndexBuffer->Release();
290     ctx->IASetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); if (old.VertexBuffer) old.VertexBuffer->Release();
291     ctx->IASetInputLayout(old.InputLayout); if (old.InputLayout) old.InputLayout->Release();
292 }
293 
ImGui_ImplDX10_CreateFontsTexture()294 static void ImGui_ImplDX10_CreateFontsTexture()
295 {
296     // Build texture atlas
297     ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
298     ImGuiIO& io = ImGui::GetIO();
299     unsigned char* pixels;
300     int width, height;
301     io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
302 
303     // Upload texture to graphics system
304     {
305         D3D10_TEXTURE2D_DESC desc;
306         ZeroMemory(&desc, sizeof(desc));
307         desc.Width = width;
308         desc.Height = height;
309         desc.MipLevels = 1;
310         desc.ArraySize = 1;
311         desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
312         desc.SampleDesc.Count = 1;
313         desc.Usage = D3D10_USAGE_DEFAULT;
314         desc.BindFlags = D3D10_BIND_SHADER_RESOURCE;
315         desc.CPUAccessFlags = 0;
316 
317         ID3D10Texture2D* pTexture = NULL;
318         D3D10_SUBRESOURCE_DATA subResource;
319         subResource.pSysMem = pixels;
320         subResource.SysMemPitch = desc.Width * 4;
321         subResource.SysMemSlicePitch = 0;
322         bd->pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
323         IM_ASSERT(pTexture != NULL);
324 
325         // Create texture view
326         D3D10_SHADER_RESOURCE_VIEW_DESC srv_desc;
327         ZeroMemory(&srv_desc, sizeof(srv_desc));
328         srv_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
329         srv_desc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
330         srv_desc.Texture2D.MipLevels = desc.MipLevels;
331         srv_desc.Texture2D.MostDetailedMip = 0;
332         bd->pd3dDevice->CreateShaderResourceView(pTexture, &srv_desc, &bd->pFontTextureView);
333         pTexture->Release();
334     }
335 
336     // Store our identifier
337     io.Fonts->SetTexID((ImTextureID)bd->pFontTextureView);
338 
339     // Create texture sampler
340     {
341         D3D10_SAMPLER_DESC desc;
342         ZeroMemory(&desc, sizeof(desc));
343         desc.Filter = D3D10_FILTER_MIN_MAG_MIP_LINEAR;
344         desc.AddressU = D3D10_TEXTURE_ADDRESS_WRAP;
345         desc.AddressV = D3D10_TEXTURE_ADDRESS_WRAP;
346         desc.AddressW = D3D10_TEXTURE_ADDRESS_WRAP;
347         desc.MipLODBias = 0.f;
348         desc.ComparisonFunc = D3D10_COMPARISON_ALWAYS;
349         desc.MinLOD = 0.f;
350         desc.MaxLOD = 0.f;
351         bd->pd3dDevice->CreateSamplerState(&desc, &bd->pFontSampler);
352     }
353 }
354 
ImGui_ImplDX10_CreateDeviceObjects()355 bool    ImGui_ImplDX10_CreateDeviceObjects()
356 {
357     ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
358     if (!bd->pd3dDevice)
359         return false;
360     if (bd->pFontSampler)
361         ImGui_ImplDX10_InvalidateDeviceObjects();
362 
363     // By using D3DCompile() from <d3dcompiler.h> / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A)
364     // If you would like to use this DX10 sample code but remove this dependency you can:
365     //  1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [preferred solution]
366     //  2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL.
367     // See https://github.com/ocornut/imgui/pull/638 for sources and details.
368 
369     // Create the vertex shader
370     {
371         static const char* vertexShader =
372             "cbuffer vertexBuffer : register(b0) \
373             {\
374               float4x4 ProjectionMatrix; \
375             };\
376             struct VS_INPUT\
377             {\
378               float2 pos : POSITION;\
379               float4 col : COLOR0;\
380               float2 uv  : TEXCOORD0;\
381             };\
382             \
383             struct PS_INPUT\
384             {\
385               float4 pos : SV_POSITION;\
386               float4 col : COLOR0;\
387               float2 uv  : TEXCOORD0;\
388             };\
389             \
390             PS_INPUT main(VS_INPUT input)\
391             {\
392               PS_INPUT output;\
393               output.pos = mul( ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));\
394               output.col = input.col;\
395               output.uv  = input.uv;\
396               return output;\
397             }";
398 
399         ID3DBlob* vertexShaderBlob;
400         if (FAILED(D3DCompile(vertexShader, strlen(vertexShader), NULL, NULL, NULL, "main", "vs_4_0", 0, 0, &vertexShaderBlob, NULL)))
401             return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
402         if (bd->pd3dDevice->CreateVertexShader(vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), &bd->pVertexShader) != S_OK)
403         {
404             vertexShaderBlob->Release();
405             return false;
406         }
407 
408         // Create the input layout
409         D3D10_INPUT_ELEMENT_DESC local_layout[] =
410         {
411             { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT,   0, (UINT)IM_OFFSETOF(ImDrawVert, pos), D3D10_INPUT_PER_VERTEX_DATA, 0 },
412             { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,   0, (UINT)IM_OFFSETOF(ImDrawVert, uv),  D3D10_INPUT_PER_VERTEX_DATA, 0 },
413             { "COLOR",    0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (UINT)IM_OFFSETOF(ImDrawVert, col), D3D10_INPUT_PER_VERTEX_DATA, 0 },
414         };
415         if (bd->pd3dDevice->CreateInputLayout(local_layout, 3, vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), &bd->pInputLayout) != S_OK)
416         {
417             vertexShaderBlob->Release();
418             return false;
419         }
420         vertexShaderBlob->Release();
421 
422         // Create the constant buffer
423         {
424             D3D10_BUFFER_DESC desc;
425             desc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER);
426             desc.Usage = D3D10_USAGE_DYNAMIC;
427             desc.BindFlags = D3D10_BIND_CONSTANT_BUFFER;
428             desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
429             desc.MiscFlags = 0;
430             bd->pd3dDevice->CreateBuffer(&desc, NULL, &bd->pVertexConstantBuffer);
431         }
432     }
433 
434     // Create the pixel shader
435     {
436         static const char* pixelShader =
437             "struct PS_INPUT\
438             {\
439             float4 pos : SV_POSITION;\
440             float4 col : COLOR0;\
441             float2 uv  : TEXCOORD0;\
442             };\
443             sampler sampler0;\
444             Texture2D texture0;\
445             \
446             float4 main(PS_INPUT input) : SV_Target\
447             {\
448             float4 out_col = input.col * texture0.Sample(sampler0, input.uv); \
449             return out_col; \
450             }";
451 
452         ID3DBlob* pixelShaderBlob;
453         if (FAILED(D3DCompile(pixelShader, strlen(pixelShader), NULL, NULL, NULL, "main", "ps_4_0", 0, 0, &pixelShaderBlob, NULL)))
454             return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
455         if (bd->pd3dDevice->CreatePixelShader(pixelShaderBlob->GetBufferPointer(), pixelShaderBlob->GetBufferSize(), &bd->pPixelShader) != S_OK)
456         {
457             pixelShaderBlob->Release();
458             return false;
459         }
460         pixelShaderBlob->Release();
461     }
462 
463     // Create the blending setup
464     {
465         D3D10_BLEND_DESC desc;
466         ZeroMemory(&desc, sizeof(desc));
467         desc.AlphaToCoverageEnable = false;
468         desc.BlendEnable[0] = true;
469         desc.SrcBlend = D3D10_BLEND_SRC_ALPHA;
470         desc.DestBlend = D3D10_BLEND_INV_SRC_ALPHA;
471         desc.BlendOp = D3D10_BLEND_OP_ADD;
472         desc.SrcBlendAlpha = D3D10_BLEND_ONE;
473         desc.DestBlendAlpha = D3D10_BLEND_INV_SRC_ALPHA;
474         desc.BlendOpAlpha = D3D10_BLEND_OP_ADD;
475         desc.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL;
476         bd->pd3dDevice->CreateBlendState(&desc, &bd->pBlendState);
477     }
478 
479     // Create the rasterizer state
480     {
481         D3D10_RASTERIZER_DESC desc;
482         ZeroMemory(&desc, sizeof(desc));
483         desc.FillMode = D3D10_FILL_SOLID;
484         desc.CullMode = D3D10_CULL_NONE;
485         desc.ScissorEnable = true;
486         desc.DepthClipEnable = true;
487         bd->pd3dDevice->CreateRasterizerState(&desc, &bd->pRasterizerState);
488     }
489 
490     // Create depth-stencil State
491     {
492         D3D10_DEPTH_STENCIL_DESC desc;
493         ZeroMemory(&desc, sizeof(desc));
494         desc.DepthEnable = false;
495         desc.DepthWriteMask = D3D10_DEPTH_WRITE_MASK_ALL;
496         desc.DepthFunc = D3D10_COMPARISON_ALWAYS;
497         desc.StencilEnable = false;
498         desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D10_STENCIL_OP_KEEP;
499         desc.FrontFace.StencilFunc = D3D10_COMPARISON_ALWAYS;
500         desc.BackFace = desc.FrontFace;
501         bd->pd3dDevice->CreateDepthStencilState(&desc, &bd->pDepthStencilState);
502     }
503 
504     ImGui_ImplDX10_CreateFontsTexture();
505 
506     return true;
507 }
508 
ImGui_ImplDX10_InvalidateDeviceObjects()509 void    ImGui_ImplDX10_InvalidateDeviceObjects()
510 {
511     ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
512     if (!bd->pd3dDevice)
513         return;
514 
515     if (bd->pFontSampler)           { bd->pFontSampler->Release(); bd->pFontSampler = NULL; }
516     if (bd->pFontTextureView)       { bd->pFontTextureView->Release(); bd->pFontTextureView = NULL; ImGui::GetIO().Fonts->SetTexID(NULL); } // We copied bd->pFontTextureView to io.Fonts->TexID so let's clear that as well.
517     if (bd->pIB)                    { bd->pIB->Release(); bd->pIB = NULL; }
518     if (bd->pVB)                    { bd->pVB->Release(); bd->pVB = NULL; }
519     if (bd->pBlendState)            { bd->pBlendState->Release(); bd->pBlendState = NULL; }
520     if (bd->pDepthStencilState)     { bd->pDepthStencilState->Release(); bd->pDepthStencilState = NULL; }
521     if (bd->pRasterizerState)       { bd->pRasterizerState->Release(); bd->pRasterizerState = NULL; }
522     if (bd->pPixelShader)           { bd->pPixelShader->Release(); bd->pPixelShader = NULL; }
523     if (bd->pVertexConstantBuffer)  { bd->pVertexConstantBuffer->Release(); bd->pVertexConstantBuffer = NULL; }
524     if (bd->pInputLayout)           { bd->pInputLayout->Release(); bd->pInputLayout = NULL; }
525     if (bd->pVertexShader)          { bd->pVertexShader->Release(); bd->pVertexShader = NULL; }
526 }
527 
ImGui_ImplDX10_Init(ID3D10Device * device)528 bool    ImGui_ImplDX10_Init(ID3D10Device* device)
529 {
530     ImGuiIO& io = ImGui::GetIO();
531     IM_ASSERT(io.BackendRendererUserData == NULL && "Already initialized a renderer backend!");
532 
533     // Setup backend capabilities flags
534     ImGui_ImplDX10_Data* bd = IM_NEW(ImGui_ImplDX10_Data)();
535     io.BackendRendererUserData = (void*)bd;
536     io.BackendRendererName = "imgui_impl_dx10";
537     io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset;  // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
538 
539     // Get factory from device
540     IDXGIDevice* pDXGIDevice = NULL;
541     IDXGIAdapter* pDXGIAdapter = NULL;
542     IDXGIFactory* pFactory = NULL;
543     if (device->QueryInterface(IID_PPV_ARGS(&pDXGIDevice)) == S_OK)
544         if (pDXGIDevice->GetParent(IID_PPV_ARGS(&pDXGIAdapter)) == S_OK)
545             if (pDXGIAdapter->GetParent(IID_PPV_ARGS(&pFactory)) == S_OK)
546             {
547                 bd->pd3dDevice = device;
548                 bd->pFactory = pFactory;
549             }
550     if (pDXGIDevice) pDXGIDevice->Release();
551     if (pDXGIAdapter) pDXGIAdapter->Release();
552     bd->pd3dDevice->AddRef();
553 
554     return true;
555 }
556 
ImGui_ImplDX10_Shutdown()557 void ImGui_ImplDX10_Shutdown()
558 {
559     ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
560     IM_ASSERT(bd != NULL && "No renderer backend to shutdown, or already shutdown?");
561     ImGuiIO& io = ImGui::GetIO();
562 
563     ImGui_ImplDX10_InvalidateDeviceObjects();
564     if (bd->pFactory) { bd->pFactory->Release(); }
565     if (bd->pd3dDevice) { bd->pd3dDevice->Release(); }
566     io.BackendRendererName = NULL;
567     io.BackendRendererUserData = NULL;
568     IM_DELETE(bd);
569 }
570 
ImGui_ImplDX10_NewFrame()571 void ImGui_ImplDX10_NewFrame()
572 {
573     ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
574     IM_ASSERT(bd != NULL && "Did you call ImGui_ImplDX10_Init()?");
575 
576     if (!bd->pFontSampler)
577         ImGui_ImplDX10_CreateDeviceObjects();
578 }
579