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