git.s-ol.nu ~forks/DiligentTools / cfdba55
Moved ImGuiImplDiligent_Internal into separate compilation unit Thomas Tissot 1 year, 10 days ago
5 changed file(s) with 710 addition(s) and 612 deletion(s). Raw diff Collapse all Expand all
99
1010 set(IMGUIZMO_QUAT_PATH ../ThirdParty/imGuIZMO.quat)
1111
12 set(DEAR_IMGUI_INCLUDE
12 set(DEAR_IMGUI_INCLUDE
1313 ${DEAR_IMGUI_PATH}/imconfig.h
1414 ${DEAR_IMGUI_PATH}/imgui_internal.h
1515 ${DEAR_IMGUI_PATH}/imstb_rectpack.h
2222 ${DEAR_IMGUI_PATH}/imgui.h
2323 )
2424
25 set(DEAR_IMGUI_SOURCE
25 set(DEAR_IMGUI_SOURCE
2626 ${DEAR_IMGUI_PATH}/imgui.cpp
2727 ${DEAR_IMGUI_PATH}/imgui_draw.cpp
2828 ${DEAR_IMGUI_PATH}/imgui_widgets.cpp
3030 )
3131
3232 set(SOURCE
33 src/ImGuiDiligentRenderer.cpp
3334 src/ImGuiImplDiligent.cpp
3435 )
3536
3940 )
4041
4142 set(INTERFACE
43 interface/ImGuiDiligentRenderer.hpp
4244 interface/ImGuiImplDiligent.hpp
4345 interface/ImGuiUtils.hpp
4446 )
101103 if(PLATFORM_WIN32 AND MINGW_BUILD)
102104 # Link with xinput.lib as imgui_impl_win32.cpp skips
103105 # '#pragma comment(lib, "xinput")'
104 # when compiler is not MSVC
106 # when compiler is not MSVC
105107 target_link_libraries(Diligent-Imgui PRIVATE xinput.lib)
106108 endif()
107109
111113 source_group("interface" FILES ${INTERFACE})
112114 source_group("imGuIZMO.quat" FILES ${IMGUIZMO_QUAT_SOURCE})
113115
114 target_link_libraries(Diligent-Imgui
115 PRIVATE
116 Diligent-BuildSettings
117 Diligent-Common
118 Diligent-PlatformInterface
119 Diligent-GraphicsEngineInterface
116 target_link_libraries(Diligent-Imgui
117 PRIVATE
118 Diligent-BuildSettings
119 Diligent-Common
120 Diligent-PlatformInterface
121 Diligent-GraphicsEngineInterface
120122 Diligent-GraphicsAccessories
121 Diligent-GraphicsTools
123 Diligent-GraphicsTools
122124 )
123125
124126 set_target_properties(Diligent-Imgui PROPERTIES
0 /*
1 * Copyright 2019-2020 Diligent Graphics LLC
2 * Copyright 2015-2019 Egor Yusov
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * In no event and under no legal theory, whether in tort (including negligence),
17 * contract, or otherwise, unless required by applicable law (such as deliberate
18 * and grossly negligent acts) or agreed to in writing, shall any Contributor be
19 * liable for any damages, including any direct, indirect, special, incidental,
20 * or consequential damages of any character arising as a result of this License or
21 * out of the use or inability to use the software (including but not limited to damages
22 * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
23 * all other commercial damages or losses), even if such Contributor has been advised
24 * of the possibility of such damages.
25 */
26
27 #pragma once
28
29 #include <memory>
30 #include "../../../DiligentCore/Primitives/interface/BasicTypes.h"
31 #include "../../../DiligentCore/Common/interface/BasicMath.hpp"
32 #include "../../../DiligentCore/Common/interface/RefCntAutoPtr.hpp"
33 #include "../../../DiligentCore/Graphics/GraphicsEngine/interface/GraphicsTypes.h"
34 #include "imgui.h"
35
36 struct ImDrawData;
37
38 namespace Diligent
39 {
40
41 struct IRenderDevice;
42 struct IDeviceContext;
43 struct IBuffer;
44 struct IPipelineState;
45 struct ITextureView;
46 struct IShaderResourceBinding;
47 enum TEXTURE_FORMAT : Uint16;
48 enum SURFACE_TRANSFORM : Uint32;
49
50 class ImGuiDiligentRenderer
51 {
52 public:
53 ImGuiDiligentRenderer(IRenderDevice* pDevice,
54 TEXTURE_FORMAT BackBufferFmt,
55 TEXTURE_FORMAT DepthBufferFmt,
56 Uint32 InitialVertexBufferSize,
57 Uint32 InitialIndexBufferSize);
58 ~ImGuiDiligentRenderer();
59 void NewFrame(Uint32 RenderSurfaceWidth,
60 Uint32 RenderSurfaceHeight,
61 SURFACE_TRANSFORM SurfacePreTransform);
62 void EndFrame();
63 void RenderDrawData(IDeviceContext* pCtx, ImDrawData* pDrawData);
64 void InvalidateDeviceObjects();
65 void CreateDeviceObjects();
66 void CreateFontsTexture();
67
68 private:
69 inline float4 TransformClipRect(const ImVec2& DisplaySize, const float4& rect) const;
70
71 private:
72 RefCntAutoPtr<IRenderDevice> m_pDevice;
73 RefCntAutoPtr<IBuffer> m_pVB;
74 RefCntAutoPtr<IBuffer> m_pIB;
75 RefCntAutoPtr<IBuffer> m_pVertexConstantBuffer;
76 RefCntAutoPtr<IPipelineState> m_pPSO;
77 RefCntAutoPtr<ITextureView> m_pFontSRV;
78 RefCntAutoPtr<IShaderResourceBinding> m_pSRB;
79 const TEXTURE_FORMAT m_BackBufferFmt;
80 const TEXTURE_FORMAT m_DepthBufferFmt;
81 Uint32 m_VertexBufferSize = 0;
82 Uint32 m_IndexBufferSize = 0;
83 Uint32 m_RenderSurfaceWidth = 0;
84 Uint32 m_RenderSurfaceHeight = 0;
85 SURFACE_TRANSFORM m_SurfacePreTransform = SURFACE_TRANSFORM_IDENTITY;
86 };
87
88 } // namespace Diligent
00 /*
11 * Copyright 2019-2020 Diligent Graphics LLC
22 * Copyright 2015-2019 Egor Yusov
3 *
3 *
44 * Licensed under the Apache License, Version 2.0 (the "License");
55 * you may not use this file except in compliance with the License.
66 * You may obtain a copy of the License at
7 *
7 *
88 * http://www.apache.org/licenses/LICENSE-2.0
9 *
9 *
1010 * Unless required by applicable law or agreed to in writing, software
1111 * distributed under the License is distributed on an "AS IS" BASIS,
1212 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1313 * See the License for the specific language governing permissions and
1414 * limitations under the License.
1515 *
16 * In no event and under no legal theory, whether in tort (including negligence),
17 * contract, or otherwise, unless required by applicable law (such as deliberate
16 * In no event and under no legal theory, whether in tort (including negligence),
17 * contract, or otherwise, unless required by applicable law (such as deliberate
1818 * and grossly negligent acts) or agreed to in writing, shall any Contributor be
19 * liable for any damages, including any direct, indirect, special, incidental,
20 * or consequential damages of any character arising as a result of this License or
21 * out of the use or inability to use the software (including but not limited to damages
22 * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
23 * all other commercial damages or losses), even if such Contributor has been advised
19 * liable for any damages, including any direct, indirect, special, incidental,
20 * or consequential damages of any character arising as a result of this License or
21 * out of the use or inability to use the software (including but not limited to damages
22 * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
23 * all other commercial damages or losses), even if such Contributor has been advised
2424 * of the possibility of such damages.
2525 */
2626
3737 enum TEXTURE_FORMAT : Uint16;
3838 enum SURFACE_TRANSFORM : Uint32;
3939
40 class ImGuiImplDiligent_Internal;
40 class ImGuiDiligentRenderer;
4141
4242 class ImGuiImplDiligent
4343 {
8282 void UpdateFontsTexture();
8383
8484 private:
85 std::unique_ptr<ImGuiImplDiligent_Internal> m_pImpl;
85 std::unique_ptr<ImGuiDiligentRenderer> m_pRenderer;
8686 };
8787
8888 } // namespace Diligent
0 /*
1 * Copyright 2019-2020 Diligent Graphics LLC
2 * Copyright 2015-2019 Egor Yusov
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * In no event and under no legal theory, whether in tort (including negligence),
17 * contract, or otherwise, unless required by applicable law (such as deliberate
18 * and grossly negligent acts) or agreed to in writing, shall any Contributor be
19 * liable for any damages, including any direct, indirect, special, incidental,
20 * or consequential damages of any character arising as a result of this License or
21 * out of the use or inability to use the software (including but not limited to damages
22 * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
23 * all other commercial damages or losses), even if such Contributor has been advised
24 * of the possibility of such damages.
25 */
26
27 #include <cstddef>
28 #include "ImGuiDiligentRenderer.hpp"
29 #include "RenderDevice.h"
30 #include "DeviceContext.h"
31 #include "MapHelper.hpp"
32
33 namespace Diligent
34 {
35
36 static const char* VertexShaderSource = R"(
37 cbuffer Constants
38 {
39 float4x4 ProjectionMatrix;
40 }
41
42 struct VSInput
43 {
44 float2 pos : ATTRIB0;
45 float2 uv : ATTRIB1;
46 float4 col : ATTRIB2;
47 };
48
49 struct PSInput
50 {
51 float4 pos : SV_POSITION;
52 float4 col : COLOR;
53 float2 uv : TEXCOORD;
54 };
55
56 void main(in VSInput VSIn, out PSInput PSIn)
57 {
58 PSIn.pos = mul(ProjectionMatrix, float4(VSIn.pos.xy, 0.0, 1.0));
59 PSIn.col = VSIn.col;
60 PSIn.uv = VSIn.uv;
61 }
62 )";
63
64 static const char* PixelShaderSource = R"(
65 struct PSInput
66 {
67 float4 pos : SV_POSITION;
68 float4 col : COLOR;
69 float2 uv : TEXCOORD;
70 };
71
72 Texture2D Texture;
73 SamplerState Texture_sampler;
74
75 float4 main(in PSInput PSIn) : SV_Target
76 {
77 return PSIn.col * Texture.Sample(Texture_sampler, PSIn.uv);
78 }
79 )";
80
81 ImGuiDiligentRenderer::ImGuiDiligentRenderer(IRenderDevice* pDevice,
82 TEXTURE_FORMAT BackBufferFmt,
83 TEXTURE_FORMAT DepthBufferFmt,
84 Uint32 InitialVertexBufferSize,
85 Uint32 InitialIndexBufferSize) :
86 // clang-format off
87 m_pDevice {pDevice},
88 m_BackBufferFmt {BackBufferFmt},
89 m_DepthBufferFmt {DepthBufferFmt},
90 m_VertexBufferSize{InitialVertexBufferSize},
91 m_IndexBufferSize {InitialIndexBufferSize}
92 // clang-format on
93 {
94 // Setup back-end capabilities flags
95 IMGUI_CHECKVERSION();
96 ImGuiIO& io = ImGui::GetIO();
97 io.BackendRendererName = "ImGuiDiligentRenderer";
98 io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
99
100 CreateDeviceObjects();
101 }
102
103 ImGuiDiligentRenderer::~ImGuiDiligentRenderer()
104 {
105 }
106
107 void ImGuiDiligentRenderer::NewFrame(Uint32 RenderSurfaceWidth,
108 Uint32 RenderSurfaceHeight,
109 SURFACE_TRANSFORM SurfacePreTransform)
110 {
111 if (!m_pPSO)
112 CreateDeviceObjects();
113 m_RenderSurfaceWidth = RenderSurfaceWidth;
114 m_RenderSurfaceHeight = RenderSurfaceHeight;
115 m_SurfacePreTransform = SurfacePreTransform;
116 }
117
118 void ImGuiDiligentRenderer::EndFrame()
119 {
120 }
121
122 void ImGuiDiligentRenderer::InvalidateDeviceObjects()
123 {
124 m_pVB.Release();
125 m_pIB.Release();
126 m_pVertexConstantBuffer.Release();
127 m_pPSO.Release();
128 m_pFontSRV.Release();
129 m_pSRB.Release();
130 }
131
132 void ImGuiDiligentRenderer::CreateDeviceObjects()
133 {
134 InvalidateDeviceObjects();
135
136 ShaderCreateInfo ShaderCI;
137 ShaderCI.UseCombinedTextureSamplers = true;
138 ShaderCI.SourceLanguage = SHADER_SOURCE_LANGUAGE_HLSL;
139
140 RefCntAutoPtr<IShader> pVS;
141 {
142 ShaderCI.Desc.ShaderType = SHADER_TYPE_VERTEX;
143 ShaderCI.Desc.Name = "Imgui VS";
144 ShaderCI.Source = VertexShaderSource;
145 m_pDevice->CreateShader(ShaderCI, &pVS);
146 }
147
148 RefCntAutoPtr<IShader> pPS;
149 {
150 ShaderCI.Desc.ShaderType = SHADER_TYPE_PIXEL;
151 ShaderCI.Desc.Name = "Imgui PS";
152 ShaderCI.Source = PixelShaderSource;
153 m_pDevice->CreateShader(ShaderCI, &pPS);
154 }
155
156 PipelineStateCreateInfo PSOCreateInfo;
157 PipelineStateDesc& PSODesc = PSOCreateInfo.PSODesc;
158
159 PSODesc.Name = "ImGUI PSO";
160 auto& GraphicsPipeline = PSODesc.GraphicsPipeline;
161
162 GraphicsPipeline.NumRenderTargets = 1;
163 GraphicsPipeline.RTVFormats[0] = m_BackBufferFmt;
164 GraphicsPipeline.DSVFormat = m_DepthBufferFmt;
165 GraphicsPipeline.PrimitiveTopology = PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
166
167 GraphicsPipeline.pVS = pVS;
168 GraphicsPipeline.pPS = pPS;
169
170 GraphicsPipeline.RasterizerDesc.CullMode = CULL_MODE_NONE;
171 GraphicsPipeline.RasterizerDesc.ScissorEnable = True;
172 GraphicsPipeline.DepthStencilDesc.DepthEnable = False;
173
174 auto& RT0 = GraphicsPipeline.BlendDesc.RenderTargets[0];
175 RT0.BlendEnable = True;
176 RT0.SrcBlend = BLEND_FACTOR_SRC_ALPHA;
177 RT0.DestBlend = BLEND_FACTOR_INV_SRC_ALPHA;
178 RT0.BlendOp = BLEND_OPERATION_ADD;
179 RT0.SrcBlendAlpha = BLEND_FACTOR_INV_SRC_ALPHA;
180 RT0.DestBlendAlpha = BLEND_FACTOR_ZERO;
181 RT0.BlendOpAlpha = BLEND_OPERATION_ADD;
182 RT0.RenderTargetWriteMask = COLOR_MASK_ALL;
183
184 LayoutElement VSInputs[] //
185 {
186 {0, 0, 2, VT_FLOAT32}, // pos
187 {1, 0, 2, VT_FLOAT32}, // uv
188 {2, 0, 4, VT_UINT8, True} // col
189 };
190 GraphicsPipeline.InputLayout.NumElements = _countof(VSInputs);
191 GraphicsPipeline.InputLayout.LayoutElements = VSInputs;
192
193 ShaderResourceVariableDesc Variables[] =
194 {
195 {SHADER_TYPE_PIXEL, "Texture", SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE} //
196 };
197 PSODesc.ResourceLayout.Variables = Variables;
198 PSODesc.ResourceLayout.NumVariables = _countof(Variables);
199
200 SamplerDesc SamLinearWrap;
201 SamLinearWrap.AddressU = TEXTURE_ADDRESS_WRAP;
202 SamLinearWrap.AddressV = TEXTURE_ADDRESS_WRAP;
203 SamLinearWrap.AddressW = TEXTURE_ADDRESS_WRAP;
204 StaticSamplerDesc StaticSamplers[] =
205 {
206 {SHADER_TYPE_PIXEL, "Texture", SamLinearWrap} //
207 };
208 PSODesc.ResourceLayout.StaticSamplers = StaticSamplers;
209 PSODesc.ResourceLayout.NumStaticSamplers = _countof(StaticSamplers);
210
211 m_pDevice->CreatePipelineState(PSOCreateInfo, &m_pPSO);
212
213 {
214 BufferDesc BuffDesc;
215 BuffDesc.uiSizeInBytes = sizeof(float4x4);
216 BuffDesc.Usage = USAGE_DYNAMIC;
217 BuffDesc.BindFlags = BIND_UNIFORM_BUFFER;
218 BuffDesc.CPUAccessFlags = CPU_ACCESS_WRITE;
219 m_pDevice->CreateBuffer(BuffDesc, nullptr, &m_pVertexConstantBuffer);
220 }
221 m_pPSO->GetStaticVariableByName(SHADER_TYPE_VERTEX, "Constants")->Set(m_pVertexConstantBuffer);
222
223 CreateFontsTexture();
224 }
225
226 void ImGuiDiligentRenderer::CreateFontsTexture()
227 {
228 // Build texture atlas
229 ImGuiIO& io = ImGui::GetIO();
230 unsigned char* pixels = nullptr;
231 int width = 0, height = 0;
232 io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
233
234 TextureDesc FontTexDesc;
235 FontTexDesc.Name = "Imgui font texture";
236 FontTexDesc.Type = RESOURCE_DIM_TEX_2D;
237 FontTexDesc.Width = static_cast<Uint32>(width);
238 FontTexDesc.Height = static_cast<Uint32>(height);
239 FontTexDesc.Format = TEX_FORMAT_RGBA8_UNORM;
240 FontTexDesc.BindFlags = BIND_SHADER_RESOURCE;
241 FontTexDesc.Usage = USAGE_STATIC;
242
243 TextureSubResData Mip0Data[] = {{pixels, FontTexDesc.Width * 4}};
244 TextureData InitData(Mip0Data, _countof(Mip0Data));
245
246 RefCntAutoPtr<ITexture> pFontTex;
247 m_pDevice->CreateTexture(FontTexDesc, &InitData, &pFontTex);
248 m_pFontSRV = pFontTex->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE);
249
250 m_pSRB.Release();
251 m_pPSO->CreateShaderResourceBinding(&m_pSRB, true);
252 m_pSRB->GetVariableByName(SHADER_TYPE_PIXEL, "Texture")->Set(m_pFontSRV);
253
254 // Store our identifier
255 io.Fonts->TexID = (ImTextureID)m_pFontSRV;
256 }
257
258 float4 ImGuiDiligentRenderer::TransformClipRect(const ImVec2& DisplaySize, const float4& rect) const
259 {
260 switch (m_SurfacePreTransform)
261 {
262 case SURFACE_TRANSFORM_IDENTITY:
263 return rect;
264
265 case SURFACE_TRANSFORM_ROTATE_90:
266 {
267 // The image content is rotated 90 degrees clockwise. The origin is in the left-top corner.
268 //
269 // DsplSz.y
270 // a.x -a.y a.y Old origin
271 // 0---->| 0------->|<------| /
272 // 0__|_____|____________________ 0__|________|_______|/
273 // | | ' | | | ' |
274 // a.y | | ' | a.x | | ' |
275 // _V_|_ _ _a____b | _V_|_ _d'___a' |
276 // A | | | | | | | |
277 // DsplSz.y | | |____| | | |____| |
278 // -a.y | | d c | | c' b' |
279 // _|_|__________________________| | |
280 // A | |
281 // |-----> Y' | |
282 // New Origin |________________|
283 //
284 float2 a{rect.x, rect.y};
285 float2 c{rect.z, rect.w};
286 return float4 //
287 {
288 DisplaySize.y - c.y, // min_x = c'.x
289 a.x, // min_y = a'.y
290 DisplaySize.y - a.y, // max_x = a'.x
291 c.x // max_y = c'.y
292 };
293 }
294
295 case SURFACE_TRANSFORM_ROTATE_180:
296 {
297 // The image content is rotated 180 degrees clockwise. The origin is in the left-top corner.
298 //
299 // a.x DsplSz.x - a.x
300 // 0---->| 0------------------>|
301 // 0__|_____|____________________ 0_ _|___________________|______
302 // | | ' | | | ' |
303 // a.y | | ' | DsplSz.y | | c'___d' |
304 // _V_|_ _ _a____b | -a.y | | | | |
305 // | | | | _V_|_ _ _ _ _ _ _ |____| |
306 // | |____| | | b' a' |
307 // | d c | | |
308 // |__________________________| |__________________________|
309 // A A
310 // | |
311 // New Origin Old Origin
312 float2 a{rect.x, rect.y};
313 float2 c{rect.z, rect.w};
314 return float4 //
315 {
316 DisplaySize.x - c.x, // min_x = c'.x
317 DisplaySize.y - c.y, // min_y = c'.y
318 DisplaySize.x - a.x, // max_x = a'.x
319 DisplaySize.y - a.y // max_y = a'.y
320 };
321 }
322
323 case SURFACE_TRANSFORM_ROTATE_270:
324 {
325 // The image content is rotated 270 degrees clockwise. The origin is in the left-top corner.
326 //
327 // 0 a.x DsplSz.x-a.x New Origin a.y
328 // |---->|<-------------------| 0----->|
329 // 0_ _|_____|____________________V 0 _|______|_________
330 // | | ' | | | ' |
331 // | | ' | | | ' |
332 // a.y_V_|_ _ _a____b | DsplSz.x | | ' |
333 // | | | | -a.x | | ' |
334 // | |____| | | | b'___c' |
335 // | d c | | | | | |
336 // DsplSz.y _ _|__________________________| _V_|_ _ _ |____| |
337 // | a' d' |
338 // | |
339 // |________________|
340 // A
341 // |
342 // Old origin
343 float2 a{rect.x, rect.y};
344 float2 c{rect.z, rect.w};
345 return float4 //
346 {
347 a.y, // min_x = a'.x
348 DisplaySize.x - c.x, // min_y = c'.y
349 c.y, // max_x = c'.x
350 DisplaySize.x - a.x // max_y = a'.y
351 };
352 }
353
354 case SURFACE_TRANSFORM_OPTIMAL:
355 UNEXPECTED("SURFACE_TRANSFORM_OPTIMAL is only valid as parameter during swap chain initialization.");
356 return rect;
357
358 case SURFACE_TRANSFORM_HORIZONTAL_MIRROR:
359 case SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90:
360 case SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180:
361 case SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270:
362 UNEXPECTED("Mirror transforms are not supported");
363 return rect;
364
365 default:
366 UNEXPECTED("Unknown transform");
367 return rect;
368 }
369 }
370
371 void ImGuiDiligentRenderer::RenderDrawData(IDeviceContext* pCtx, ImDrawData* pDrawData)
372 {
373 // Avoid rendering when minimized
374 if (pDrawData->DisplaySize.x <= 0.0f || pDrawData->DisplaySize.y <= 0.0f)
375 return;
376
377 // Create and grow vertex/index buffers if needed
378 if (!m_pVB || static_cast<int>(m_VertexBufferSize) < pDrawData->TotalVtxCount)
379 {
380 m_pVB.Release();
381 while (static_cast<int>(m_VertexBufferSize) < pDrawData->TotalVtxCount)
382 m_VertexBufferSize *= 2;
383
384 BufferDesc VBDesc;
385 VBDesc.Name = "Imgui vertex buffer";
386 VBDesc.BindFlags = BIND_VERTEX_BUFFER;
387 VBDesc.uiSizeInBytes = m_VertexBufferSize * sizeof(ImDrawVert);
388 VBDesc.Usage = USAGE_DYNAMIC;
389 VBDesc.CPUAccessFlags = CPU_ACCESS_WRITE;
390 m_pDevice->CreateBuffer(VBDesc, nullptr, &m_pVB);
391 }
392
393 if (!m_pIB || static_cast<int>(m_IndexBufferSize) < pDrawData->TotalIdxCount)
394 {
395 m_pIB.Release();
396 while (static_cast<int>(m_IndexBufferSize) < pDrawData->TotalIdxCount)
397 m_IndexBufferSize *= 2;
398
399 BufferDesc IBDesc;
400 IBDesc.Name = "Imgui index buffer";
401 IBDesc.BindFlags = BIND_INDEX_BUFFER;
402 IBDesc.uiSizeInBytes = m_IndexBufferSize * sizeof(ImDrawIdx);
403 IBDesc.Usage = USAGE_DYNAMIC;
404 IBDesc.CPUAccessFlags = CPU_ACCESS_WRITE;
405 m_pDevice->CreateBuffer(IBDesc, nullptr, &m_pIB);
406 }
407
408 {
409 MapHelper<ImDrawVert> Verices(pCtx, m_pVB, MAP_WRITE, MAP_FLAG_DISCARD);
410 MapHelper<ImDrawIdx> Indices(pCtx, m_pIB, MAP_WRITE, MAP_FLAG_DISCARD);
411
412 ImDrawVert* vtx_dst = Verices;
413 ImDrawIdx* idx_dst = Indices;
414 for (int n = 0; n < pDrawData->CmdListsCount; n++)
415 {
416 const ImDrawList* cmd_list = pDrawData->CmdLists[n];
417 memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
418 memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
419 vtx_dst += cmd_list->VtxBuffer.Size;
420 idx_dst += cmd_list->IdxBuffer.Size;
421 }
422 }
423
424 // Setup orthographic projection matrix into our constant buffer
425 // Our visible imgui space lies from pDrawData->DisplayPos (top left) to pDrawData->DisplayPos+data_data->DisplaySize (bottom right).
426 // DisplayPos is (0,0) for single viewport apps.
427 {
428 // DisplaySize always refers to the logical dimensions that account for pre-transform, hence
429 // the aspect ratio will be correct after applying appropriate rotation.
430 float L = pDrawData->DisplayPos.x;
431 float R = pDrawData->DisplayPos.x + pDrawData->DisplaySize.x;
432 float T = pDrawData->DisplayPos.y;
433 float B = pDrawData->DisplayPos.y + pDrawData->DisplaySize.y;
434
435 // clang-format off
436 float4x4 Projection
437 {
438 2.0f / (R - L), 0.0f, 0.0f, 0.0f,
439 0.0f, 2.0f / (T - B), 0.0f, 0.0f,
440 0.0f, 0.0f, 0.5f, 0.0f,
441 (R + L) / (L - R), (T + B) / (B - T), 0.5f, 1.0f
442 };
443 // clang-format on
444
445 // Bake pre-transform into projection
446 switch (m_SurfacePreTransform)
447 {
448 case SURFACE_TRANSFORM_IDENTITY:
449 // Nothing to do
450 break;
451
452 case SURFACE_TRANSFORM_ROTATE_90:
453 // The image content is rotated 90 degrees clockwise.
454 Projection *= float4x4::RotationZ(-PI_F * 0.5f);
455 break;
456
457 case SURFACE_TRANSFORM_ROTATE_180:
458 // The image content is rotated 180 degrees clockwise.
459 Projection *= float4x4::RotationZ(-PI_F * 1.0f);
460 break;
461
462 case SURFACE_TRANSFORM_ROTATE_270:
463 // The image content is rotated 270 degrees clockwise.
464 Projection *= float4x4::RotationZ(-PI_F * 1.5f);
465 break;
466
467 case SURFACE_TRANSFORM_OPTIMAL:
468 UNEXPECTED("SURFACE_TRANSFORM_OPTIMAL is only valid as parameter during swap chain initialization.");
469 break;
470
471 case SURFACE_TRANSFORM_HORIZONTAL_MIRROR:
472 case SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90:
473 case SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180:
474 case SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270:
475 UNEXPECTED("Mirror transforms are not supported");
476 break;
477
478 default:
479 UNEXPECTED("Unknown transform");
480 }
481
482 MapHelper<float4x4> CBData(pCtx, m_pVertexConstantBuffer, MAP_WRITE, MAP_FLAG_DISCARD);
483 *CBData = Projection;
484 }
485
486 auto SetupRenderState = [&]() //
487 {
488 // Setup shader and vertex buffers
489 Uint32 Offsets[] = {0};
490 IBuffer* pVBs[] = {m_pVB};
491 pCtx->SetVertexBuffers(0, 1, pVBs, Offsets, RESOURCE_STATE_TRANSITION_MODE_TRANSITION, SET_VERTEX_BUFFERS_FLAG_RESET);
492 pCtx->SetIndexBuffer(m_pIB, 0, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
493 pCtx->SetPipelineState(m_pPSO);
494 pCtx->CommitShaderResources(m_pSRB, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
495
496 const float blend_factor[4] = {0.f, 0.f, 0.f, 0.f};
497 pCtx->SetBlendFactors(blend_factor);
498
499 Viewport vp;
500 vp.Width = static_cast<float>(m_RenderSurfaceWidth) * pDrawData->FramebufferScale.x;
501 vp.Height = static_cast<float>(m_RenderSurfaceHeight) * pDrawData->FramebufferScale.y;
502 vp.MinDepth = 0.0f;
503 vp.MaxDepth = 1.0f;
504 vp.TopLeftX = vp.TopLeftY = 0;
505 pCtx->SetViewports(1,
506 &vp,
507 static_cast<Uint32>(m_RenderSurfaceWidth * pDrawData->FramebufferScale.x),
508 static_cast<Uint32>(m_RenderSurfaceHeight * pDrawData->FramebufferScale.y));
509 };
510
511 SetupRenderState();
512
513 // Render command lists
514 // (Because we merged all buffers into a single one, we maintain our own offset into them)
515 int global_idx_offset = 0;
516 int global_vtx_offset = 0;
517
518 for (int n = 0; n < pDrawData->CmdListsCount; n++)
519 {
520 const ImDrawList* cmd_list = pDrawData->CmdLists[n];
521 for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
522 {
523 const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
524 if (pcmd->UserCallback != NULL)
525 {
526 // User callback, registered via ImDrawList::AddCallback()
527 // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
528 if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
529 SetupRenderState();
530 else
531 pcmd->UserCallback(cmd_list, pcmd);
532 }
533 else
534 {
535 // Apply scissor/clipping rectangle
536 float4 ClipRect //
537 {
538 (pcmd->ClipRect.x - pDrawData->DisplayPos.x) * pDrawData->FramebufferScale.x,
539 (pcmd->ClipRect.y - pDrawData->DisplayPos.y) * pDrawData->FramebufferScale.y,
540 (pcmd->ClipRect.z - pDrawData->DisplayPos.x) * pDrawData->FramebufferScale.x,
541 (pcmd->ClipRect.w - pDrawData->DisplayPos.y) * pDrawData->FramebufferScale.y //
542 };
543 // Apply pretransform
544 ClipRect = TransformClipRect(pDrawData->DisplaySize, ClipRect);
545
546 Rect r //
547 {
548 static_cast<Int32>(ClipRect.x),
549 static_cast<Int32>(ClipRect.y),
550 static_cast<Int32>(ClipRect.z),
551 static_cast<Int32>(ClipRect.w) //
552 };
553 pCtx->SetScissorRects(1,
554 &r,
555 static_cast<Uint32>(m_RenderSurfaceWidth * pDrawData->FramebufferScale.x),
556 static_cast<Uint32>(m_RenderSurfaceHeight * pDrawData->FramebufferScale.y));
557
558 // Bind texture, Draw
559 auto* texture_srv = reinterpret_cast<ITextureView*>(pcmd->TextureId);
560 VERIFY_EXPR(texture_srv == m_pFontSRV);
561 (void)texture_srv;
562 //ctx->PSSetShaderResources(0, 1, &texture_srv);
563 DrawIndexedAttribs DrawAttrs(pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? VT_UINT16 : VT_UINT32, DRAW_FLAG_VERIFY_STATES);
564 DrawAttrs.FirstIndexLocation = pcmd->IdxOffset + global_idx_offset;
565 DrawAttrs.BaseVertex = pcmd->VtxOffset + global_vtx_offset;
566 pCtx->DrawIndexed(DrawAttrs);
567 }
568 }
569 global_idx_offset += cmd_list->IdxBuffer.Size;
570 global_vtx_offset += cmd_list->VtxBuffer.Size;
571 }
572 }
573
574 } // namespace Diligent
00 /*
11 * Copyright 2019-2020 Diligent Graphics LLC
22 * Copyright 2015-2019 Egor Yusov
3 *
3 *
44 * Licensed under the Apache License, Version 2.0 (the "License");
55 * you may not use this file except in compliance with the License.
66 * You may obtain a copy of the License at
7 *
7 *
88 * http://www.apache.org/licenses/LICENSE-2.0
9 *
9 *
1010 * Unless required by applicable law or agreed to in writing, software
1111 * distributed under the License is distributed on an "AS IS" BASIS,
1212 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1313 * See the License for the specific language governing permissions and
1414 * limitations under the License.
1515 *
16 * In no event and under no legal theory, whether in tort (including negligence),
17 * contract, or otherwise, unless required by applicable law (such as deliberate
16 * In no event and under no legal theory, whether in tort (including negligence),
17 * contract, or otherwise, unless required by applicable law (such as deliberate
1818 * and grossly negligent acts) or agreed to in writing, shall any Contributor be
19 * liable for any damages, including any direct, indirect, special, incidental,
20 * or consequential damages of any character arising as a result of this License or
21 * out of the use or inability to use the software (including but not limited to damages
22 * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
23 * all other commercial damages or losses), even if such Contributor has been advised
19 * liable for any damages, including any direct, indirect, special, incidental,
20 * or consequential damages of any character arising as a result of this License or
21 * out of the use or inability to use the software (including but not limited to damages
22 * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
23 * all other commercial damages or losses), even if such Contributor has been advised
2424 * of the possibility of such damages.
2525 */
2626
2727 #include <cstddef>
2828 #include "imgui.h"
2929 #include "ImGuiImplDiligent.hpp"
30 #include "ImGuiDiligentRenderer.hpp"
3031 #include "RenderDevice.h"
3132 #include "DeviceContext.h"
3233 #include "RefCntAutoPtr.hpp"
3637 namespace Diligent
3738 {
3839
39 class ImGuiImplDiligent_Internal
40 {
41 public:
42 ImGuiImplDiligent_Internal(IRenderDevice* pDevice,
43 TEXTURE_FORMAT BackBufferFmt,
44 TEXTURE_FORMAT DepthBufferFmt,
45 Uint32 InitialVertexBufferSize,
46 Uint32 InitialIndexBufferSize) :
47 // clang-format off
48 m_pDevice {pDevice},
49 m_BackBufferFmt {BackBufferFmt},
50 m_DepthBufferFmt {DepthBufferFmt},
51 m_VertexBufferSize{InitialVertexBufferSize},
52 m_IndexBufferSize {InitialIndexBufferSize}
53 // clang-format on
54 {
55 // Setup back-end capabilities flags
56 IMGUI_CHECKVERSION();
57 ImGui::CreateContext();
58 ImGuiIO& io = ImGui::GetIO();
59 io.BackendRendererName = "ImGuiImplDiligent";
60 io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
61 io.IniFilename = nullptr;
62
63 CreateDeviceObjects();
64 }
65
66 ~ImGuiImplDiligent_Internal()
67 {
68 ImGui::DestroyContext();
69 }
70
71 void NewFrame(Uint32 RenderSurfaceWidth, Uint32 RenderSurfaceHeight, SURFACE_TRANSFORM SurfacePreTransform);
72 void RenderDrawData(IDeviceContext* pCtx, ImDrawData* pDrawData);
73
74 // Use if you want to reset your rendering device without losing ImGui state.
75 void InvalidateDeviceObjects();
76 void CreateDeviceObjects();
77
78 void CreateFontsTexture();
79
80 private:
81 inline float4 TransformClipRect(const ImVec2& DisplaySize, const float4& rect) const;
82
83 RefCntAutoPtr<IRenderDevice> m_pDevice;
84 RefCntAutoPtr<IBuffer> m_pVB;
85 RefCntAutoPtr<IBuffer> m_pIB;
86 RefCntAutoPtr<IBuffer> m_pVertexConstantBuffer;
87 RefCntAutoPtr<IPipelineState> m_pPSO;
88 RefCntAutoPtr<ITextureView> m_pFontSRV;
89 RefCntAutoPtr<IShaderResourceBinding> m_pSRB;
90 const TEXTURE_FORMAT m_BackBufferFmt;
91 const TEXTURE_FORMAT m_DepthBufferFmt;
92 Uint32 m_VertexBufferSize = 0;
93 Uint32 m_IndexBufferSize = 0;
94
95 Uint32 m_RenderSurfaceWidth = 0;
96 Uint32 m_RenderSurfaceHeight = 0;
97 SURFACE_TRANSFORM m_SurfacePreTransform = SURFACE_TRANSFORM_IDENTITY;
98 };
99
100 void ImGuiImplDiligent_Internal::NewFrame(Uint32 RenderSurfaceWidth,
101 Uint32 RenderSurfaceHeight,
102 SURFACE_TRANSFORM SurfacePreTransform)
103 {
104 if (!m_pPSO)
105 CreateDeviceObjects();
106 m_RenderSurfaceWidth = RenderSurfaceWidth;
107 m_RenderSurfaceHeight = RenderSurfaceHeight;
108 m_SurfacePreTransform = SurfacePreTransform;
109 }
110
111 // Use if you want to reset your rendering device without losing ImGui state.
112 void ImGuiImplDiligent_Internal::InvalidateDeviceObjects()
113 {
114 m_pVB.Release();
115 m_pIB.Release();
116 m_pVertexConstantBuffer.Release();
117 m_pPSO.Release();
118 m_pFontSRV.Release();
119 m_pSRB.Release();
120 }
121
122 static const char* VertexShaderSource = R"(
123 cbuffer Constants
124 {
125 float4x4 ProjectionMatrix;
126 }
127
128 struct VSInput
129 {
130 float2 pos : ATTRIB0;
131 float2 uv : ATTRIB1;
132 float4 col : ATTRIB2;
133 };
134
135 struct PSInput
136 {
137 float4 pos : SV_POSITION;
138 float4 col : COLOR;
139 float2 uv : TEXCOORD;
140 };
141
142 void main(in VSInput VSIn, out PSInput PSIn)
143 {
144 PSIn.pos = mul(ProjectionMatrix, float4(VSIn.pos.xy, 0.0, 1.0));
145 PSIn.col = VSIn.col;
146 PSIn.uv = VSIn.uv;
147 }
148 )";
149
150 static const char* PixelShaderSource = R"(
151 struct PSInput
152 {
153 float4 pos : SV_POSITION;
154 float4 col : COLOR;
155 float2 uv : TEXCOORD;
156 };
157
158 Texture2D Texture;
159 SamplerState Texture_sampler;
160
161 float4 main(in PSInput PSIn) : SV_Target
162 {
163 return PSIn.col * Texture.Sample(Texture_sampler, PSIn.uv);
164 }
165 )";
166
167 void ImGuiImplDiligent_Internal::CreateDeviceObjects()
168 {
169 InvalidateDeviceObjects();
170
171 ShaderCreateInfo ShaderCI;
172 ShaderCI.UseCombinedTextureSamplers = true;
173 ShaderCI.SourceLanguage = SHADER_SOURCE_LANGUAGE_HLSL;
174
175 RefCntAutoPtr<IShader> pVS;
176 {
177 ShaderCI.Desc.ShaderType = SHADER_TYPE_VERTEX;
178 ShaderCI.Desc.Name = "Imgui VS";
179 ShaderCI.Source = VertexShaderSource;
180 m_pDevice->CreateShader(ShaderCI, &pVS);
181 }
182
183 RefCntAutoPtr<IShader> pPS;
184 {
185 ShaderCI.Desc.ShaderType = SHADER_TYPE_PIXEL;
186 ShaderCI.Desc.Name = "Imgui PS";
187 ShaderCI.Source = PixelShaderSource;
188 m_pDevice->CreateShader(ShaderCI, &pPS);
189 }
190
191 PipelineStateCreateInfo PSOCreateInfo;
192 PipelineStateDesc& PSODesc = PSOCreateInfo.PSODesc;
193
194 PSODesc.Name = "ImGUI PSO";
195 auto& GraphicsPipeline = PSODesc.GraphicsPipeline;
196
197 GraphicsPipeline.NumRenderTargets = 1;
198 GraphicsPipeline.RTVFormats[0] = m_BackBufferFmt;
199 GraphicsPipeline.DSVFormat = m_DepthBufferFmt;
200 GraphicsPipeline.PrimitiveTopology = PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
201
202 GraphicsPipeline.pVS = pVS;
203 GraphicsPipeline.pPS = pPS;
204
205 GraphicsPipeline.RasterizerDesc.CullMode = CULL_MODE_NONE;
206 GraphicsPipeline.RasterizerDesc.ScissorEnable = True;
207 GraphicsPipeline.DepthStencilDesc.DepthEnable = False;
208
209 auto& RT0 = GraphicsPipeline.BlendDesc.RenderTargets[0];
210 RT0.BlendEnable = True;
211 RT0.SrcBlend = BLEND_FACTOR_SRC_ALPHA;
212 RT0.DestBlend = BLEND_FACTOR_INV_SRC_ALPHA;
213 RT0.BlendOp = BLEND_OPERATION_ADD;
214 RT0.SrcBlendAlpha = BLEND_FACTOR_INV_SRC_ALPHA;
215 RT0.DestBlendAlpha = BLEND_FACTOR_ZERO;
216 RT0.BlendOpAlpha = BLEND_OPERATION_ADD;
217 RT0.RenderTargetWriteMask = COLOR_MASK_ALL;
218
219 LayoutElement VSInputs[] //
220 {
221 {0, 0, 2, VT_FLOAT32}, // pos
222 {1, 0, 2, VT_FLOAT32}, // uv
223 {2, 0, 4, VT_UINT8, True} // col
224 };
225 GraphicsPipeline.InputLayout.NumElements = _countof(VSInputs);
226 GraphicsPipeline.InputLayout.LayoutElements = VSInputs;
227
228 ShaderResourceVariableDesc Variables[] =
229 {
230 {SHADER_TYPE_PIXEL, "Texture", SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE} //
231 };
232 PSODesc.ResourceLayout.Variables = Variables;
233 PSODesc.ResourceLayout.NumVariables = _countof(Variables);
234
235 SamplerDesc SamLinearWrap;
236 SamLinearWrap.AddressU = TEXTURE_ADDRESS_WRAP;
237 SamLinearWrap.AddressV = TEXTURE_ADDRESS_WRAP;
238 SamLinearWrap.AddressW = TEXTURE_ADDRESS_WRAP;
239 StaticSamplerDesc StaticSamplers[] =
240 {
241 {SHADER_TYPE_PIXEL, "Texture", SamLinearWrap} //
242 };
243 PSODesc.ResourceLayout.StaticSamplers = StaticSamplers;
244 PSODesc.ResourceLayout.NumStaticSamplers = _countof(StaticSamplers);
245
246 m_pDevice->CreatePipelineState(PSOCreateInfo, &m_pPSO);
247
248 {
249 BufferDesc BuffDesc;
250 BuffDesc.uiSizeInBytes = sizeof(float4x4);
251 BuffDesc.Usage = USAGE_DYNAMIC;
252 BuffDesc.BindFlags = BIND_UNIFORM_BUFFER;
253 BuffDesc.CPUAccessFlags = CPU_ACCESS_WRITE;
254 m_pDevice->CreateBuffer(BuffDesc, nullptr, &m_pVertexConstantBuffer);
255 }
256 m_pPSO->GetStaticVariableByName(SHADER_TYPE_VERTEX, "Constants")->Set(m_pVertexConstantBuffer);
257
258 CreateFontsTexture();
259 }
260
261 void ImGuiImplDiligent_Internal::CreateFontsTexture()
262 {
263 // Build texture atlas
264 ImGuiIO& io = ImGui::GetIO();
265 unsigned char* pixels = nullptr;
266 int width = 0, height = 0;
267 io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
268
269 TextureDesc FontTexDesc;
270 FontTexDesc.Name = "Imgui font texture";
271 FontTexDesc.Type = RESOURCE_DIM_TEX_2D;
272 FontTexDesc.Width = static_cast<Uint32>(width);
273 FontTexDesc.Height = static_cast<Uint32>(height);
274 FontTexDesc.Format = TEX_FORMAT_RGBA8_UNORM;
275 FontTexDesc.BindFlags = BIND_SHADER_RESOURCE;
276 FontTexDesc.Usage = USAGE_STATIC;
277
278 TextureSubResData Mip0Data[] = {{pixels, FontTexDesc.Width * 4}};
279 TextureData InitData(Mip0Data, _countof(Mip0Data));
280
281 RefCntAutoPtr<ITexture> pFontTex;
282 m_pDevice->CreateTexture(FontTexDesc, &InitData, &pFontTex);
283 m_pFontSRV = pFontTex->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE);
284
285 m_pSRB.Release();
286 m_pPSO->CreateShaderResourceBinding(&m_pSRB, true);
287 m_pSRB->GetVariableByName(SHADER_TYPE_PIXEL, "Texture")->Set(m_pFontSRV);
288
289 // Store our identifier
290 io.Fonts->TexID = (ImTextureID)m_pFontSRV;
291 }
292
293 float4 ImGuiImplDiligent_Internal::TransformClipRect(const ImVec2& DisplaySize, const float4& rect) const
294 {
295 switch (m_SurfacePreTransform)
296 {
297 case SURFACE_TRANSFORM_IDENTITY:
298 return rect;
299
300 case SURFACE_TRANSFORM_ROTATE_90:
301 {
302 // The image content is rotated 90 degrees clockwise. The origin is in the left-top corner.
303 //
304 // DsplSz.y
305 // a.x -a.y a.y Old origin
306 // 0---->| 0------->|<------| /
307 // 0__|_____|____________________ 0__|________|_______|/
308 // | | ' | | | ' |
309 // a.y | | ' | a.x | | ' |
310 // _V_|_ _ _a____b | _V_|_ _d'___a' |
311 // A | | | | | | | |
312 // DsplSz.y | | |____| | | |____| |
313 // -a.y | | d c | | c' b' |
314 // _|_|__________________________| | |
315 // A | |
316 // |-----> Y' | |
317 // New Origin |________________|
318 //
319 float2 a{rect.x, rect.y};
320 float2 c{rect.z, rect.w};
321 return float4 //
322 {
323 DisplaySize.y - c.y, // min_x = c'.x
324 a.x, // min_y = a'.y
325 DisplaySize.y - a.y, // max_x = a'.x
326 c.x // max_y = c'.y
327 };
328 }
329
330 case SURFACE_TRANSFORM_ROTATE_180:
331 {
332 // The image content is rotated 180 degrees clockwise. The origin is in the left-top corner.
333 //
334 // a.x DsplSz.x - a.x
335 // 0---->| 0------------------>|
336 // 0__|_____|____________________ 0_ _|___________________|______
337 // | | ' | | | ' |
338 // a.y | | ' | DsplSz.y | | c'___d' |
339 // _V_|_ _ _a____b | -a.y | | | | |
340 // | | | | _V_|_ _ _ _ _ _ _ |____| |
341 // | |____| | | b' a' |
342 // | d c | | |
343 // |__________________________| |__________________________|
344 // A A
345 // | |
346 // New Origin Old Origin
347 float2 a{rect.x, rect.y};
348 float2 c{rect.z, rect.w};
349 return float4 //
350 {
351 DisplaySize.x - c.x, // min_x = c'.x
352 DisplaySize.y - c.y, // min_y = c'.y
353 DisplaySize.x - a.x, // max_x = a'.x
354 DisplaySize.y - a.y // max_y = a'.y
355 };
356 }
357
358 case SURFACE_TRANSFORM_ROTATE_270:
359 {
360 // The image content is rotated 270 degrees clockwise. The origin is in the left-top corner.
361 //
362 // 0 a.x DsplSz.x-a.x New Origin a.y
363 // |---->|<-------------------| 0----->|
364 // 0_ _|_____|____________________V 0 _|______|_________
365 // | | ' | | | ' |
366 // | | ' | | | ' |
367 // a.y_V_|_ _ _a____b | DsplSz.x | | ' |
368 // | | | | -a.x | | ' |
369 // | |____| | | | b'___c' |
370 // | d c | | | | | |
371 // DsplSz.y _ _|__________________________| _V_|_ _ _ |____| |
372 // | a' d' |
373 // | |
374 // |________________|
375 // A
376 // |
377 // Old origin
378 float2 a{rect.x, rect.y};
379 float2 c{rect.z, rect.w};
380 return float4 //
381 {
382 a.y, // min_x = a'.x
383 DisplaySize.x - c.x, // min_y = c'.y
384 c.y, // max_x = c'.x
385 DisplaySize.x - a.x // max_y = a'.y
386 };
387 }
388
389 case SURFACE_TRANSFORM_OPTIMAL:
390 UNEXPECTED("SURFACE_TRANSFORM_OPTIMAL is only valid as parameter during swap chain initialization.");
391 return rect;
392
393 case SURFACE_TRANSFORM_HORIZONTAL_MIRROR:
394 case SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90:
395 case SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180:
396 case SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270:
397 UNEXPECTED("Mirror transforms are not supported");
398 return rect;
399
400 default:
401 UNEXPECTED("Unknown transform");
402 return rect;
403 }
404 }
405
406 void ImGuiImplDiligent_Internal::RenderDrawData(IDeviceContext* pCtx, ImDrawData* pDrawData)
407 {
408 // Avoid rendering when minimized
409 if (pDrawData->DisplaySize.x <= 0.0f || pDrawData->DisplaySize.y <= 0.0f)
410 return;
411
412 // Create and grow vertex/index buffers if needed
413 if (!m_pVB || static_cast<int>(m_VertexBufferSize) < pDrawData->TotalVtxCount)
414 {
415 m_pVB.Release();
416 while (static_cast<int>(m_VertexBufferSize) < pDrawData->TotalVtxCount)
417 m_VertexBufferSize *= 2;
418
419 BufferDesc VBDesc;
420 VBDesc.Name = "Imgui vertex buffer";
421 VBDesc.BindFlags = BIND_VERTEX_BUFFER;
422 VBDesc.uiSizeInBytes = m_VertexBufferSize * sizeof(ImDrawVert);
423 VBDesc.Usage = USAGE_DYNAMIC;
424 VBDesc.CPUAccessFlags = CPU_ACCESS_WRITE;
425 m_pDevice->CreateBuffer(VBDesc, nullptr, &m_pVB);
426 }
427
428 if (!m_pIB || static_cast<int>(m_IndexBufferSize) < pDrawData->TotalIdxCount)
429 {
430 m_pIB.Release();
431 while (static_cast<int>(m_IndexBufferSize) < pDrawData->TotalIdxCount)
432 m_IndexBufferSize *= 2;
433
434 BufferDesc IBDesc;
435 IBDesc.Name = "Imgui index buffer";
436 IBDesc.BindFlags = BIND_INDEX_BUFFER;
437 IBDesc.uiSizeInBytes = m_IndexBufferSize * sizeof(ImDrawIdx);
438 IBDesc.Usage = USAGE_DYNAMIC;
439 IBDesc.CPUAccessFlags = CPU_ACCESS_WRITE;
440 m_pDevice->CreateBuffer(IBDesc, nullptr, &m_pIB);
441 }
442
443 {
444 MapHelper<ImDrawVert> Verices(pCtx, m_pVB, MAP_WRITE, MAP_FLAG_DISCARD);
445 MapHelper<ImDrawIdx> Indices(pCtx, m_pIB, MAP_WRITE, MAP_FLAG_DISCARD);
446
447 ImDrawVert* vtx_dst = Verices;
448 ImDrawIdx* idx_dst = Indices;
449 for (int n = 0; n < pDrawData->CmdListsCount; n++)
450 {
451 const ImDrawList* cmd_list = pDrawData->CmdLists[n];
452 memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
453 memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
454 vtx_dst += cmd_list->VtxBuffer.Size;
455 idx_dst += cmd_list->IdxBuffer.Size;
456 }
457 }
458
459 // Setup orthographic projection matrix into our constant buffer
460 // Our visible imgui space lies from pDrawData->DisplayPos (top left) to pDrawData->DisplayPos+data_data->DisplaySize (bottom right).
461 // DisplayPos is (0,0) for single viewport apps.
462 {
463 // DisplaySize always refers to the logical dimensions that account for pre-transform, hence
464 // the aspect ratio will be correct after applying appropriate rotation.
465 float L = pDrawData->DisplayPos.x;
466 float R = pDrawData->DisplayPos.x + pDrawData->DisplaySize.x;
467 float T = pDrawData->DisplayPos.y;
468 float B = pDrawData->DisplayPos.y + pDrawData->DisplaySize.y;
469
470 // clang-format off
471 float4x4 Projection
472 {
473 2.0f / (R - L), 0.0f, 0.0f, 0.0f,
474 0.0f, 2.0f / (T - B), 0.0f, 0.0f,
475 0.0f, 0.0f, 0.5f, 0.0f,
476 (R + L) / (L - R), (T + B) / (B - T), 0.5f, 1.0f
477 };
478 // clang-format on
479
480 // Bake pre-transform into projection
481 switch (m_SurfacePreTransform)
482 {
483 case SURFACE_TRANSFORM_IDENTITY:
484 // Nothing to do
485 break;
486
487 case SURFACE_TRANSFORM_ROTATE_90:
488 // The image content is rotated 90 degrees clockwise.
489 Projection *= float4x4::RotationZ(-PI_F * 0.5f);
490 break;
491
492 case SURFACE_TRANSFORM_ROTATE_180:
493 // The image content is rotated 180 degrees clockwise.
494 Projection *= float4x4::RotationZ(-PI_F * 1.0f);
495 break;
496
497 case SURFACE_TRANSFORM_ROTATE_270:
498 // The image content is rotated 270 degrees clockwise.
499 Projection *= float4x4::RotationZ(-PI_F * 1.5f);
500 break;
501
502 case SURFACE_TRANSFORM_OPTIMAL:
503 UNEXPECTED("SURFACE_TRANSFORM_OPTIMAL is only valid as parameter during swap chain initialization.");
504 break;
505
506 case SURFACE_TRANSFORM_HORIZONTAL_MIRROR:
507 case SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90:
508 case SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180:
509 case SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270:
510 UNEXPECTED("Mirror transforms are not supported");
511 break;
512
513 default:
514 UNEXPECTED("Unknown transform");
515 }
516
517 MapHelper<float4x4> CBData(pCtx, m_pVertexConstantBuffer, MAP_WRITE, MAP_FLAG_DISCARD);
518 *CBData = Projection;
519 }
520
521 auto SetupRenderState = [&]() //
522 {
523 // Setup shader and vertex buffers
524 Uint32 Offsets[] = {0};
525 IBuffer* pVBs[] = {m_pVB};
526 pCtx->SetVertexBuffers(0, 1, pVBs, Offsets, RESOURCE_STATE_TRANSITION_MODE_TRANSITION, SET_VERTEX_BUFFERS_FLAG_RESET);
527 pCtx->SetIndexBuffer(m_pIB, 0, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
528 pCtx->SetPipelineState(m_pPSO);
529 pCtx->CommitShaderResources(m_pSRB, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
530
531 const float blend_factor[4] = {0.f, 0.f, 0.f, 0.f};
532 pCtx->SetBlendFactors(blend_factor);
533
534 Viewport vp;
535 vp.Width = static_cast<float>(m_RenderSurfaceWidth) * pDrawData->FramebufferScale.x;
536 vp.Height = static_cast<float>(m_RenderSurfaceHeight) * pDrawData->FramebufferScale.y;
537 vp.MinDepth = 0.0f;
538 vp.MaxDepth = 1.0f;
539 vp.TopLeftX = vp.TopLeftY = 0;
540 pCtx->SetViewports(1,
541 &vp,
542 static_cast<Uint32>(m_RenderSurfaceWidth * pDrawData->FramebufferScale.x),
543 static_cast<Uint32>(m_RenderSurfaceHeight * pDrawData->FramebufferScale.y));
544 };
545
546 SetupRenderState();
547
548 // Render command lists
549 // (Because we merged all buffers into a single one, we maintain our own offset into them)
550 int global_idx_offset = 0;
551 int global_vtx_offset = 0;
552
553 for (int n = 0; n < pDrawData->CmdListsCount; n++)
554 {
555 const ImDrawList* cmd_list = pDrawData->CmdLists[n];
556 for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
557 {
558 const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
559 if (pcmd->UserCallback != NULL)
560 {
561 // User callback, registered via ImDrawList::AddCallback()
562 // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
563 if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
564 SetupRenderState();
565 else
566 pcmd->UserCallback(cmd_list, pcmd);
567 }
568 else
569 {
570 // Apply scissor/clipping rectangle
571 float4 ClipRect //
572 {
573 (pcmd->ClipRect.x - pDrawData->DisplayPos.x) * pDrawData->FramebufferScale.x,
574 (pcmd->ClipRect.y - pDrawData->DisplayPos.y) * pDrawData->FramebufferScale.y,
575 (pcmd->ClipRect.z - pDrawData->DisplayPos.x) * pDrawData->FramebufferScale.x,
576 (pcmd->ClipRect.w - pDrawData->DisplayPos.y) * pDrawData->FramebufferScale.y //
577 };
578 // Apply pretransform
579 ClipRect = TransformClipRect(pDrawData->DisplaySize, ClipRect);
580
581 Rect r //
582 {
583 static_cast<Int32>(ClipRect.x),
584 static_cast<Int32>(ClipRect.y),
585 static_cast<Int32>(ClipRect.z),
586 static_cast<Int32>(ClipRect.w) //
587 };
588 pCtx->SetScissorRects(1,
589 &r,
590 static_cast<Uint32>(m_RenderSurfaceWidth * pDrawData->FramebufferScale.x),
591 static_cast<Uint32>(m_RenderSurfaceHeight * pDrawData->FramebufferScale.y));
592
593 // Bind texture, Draw
594 auto* texture_srv = reinterpret_cast<ITextureView*>(pcmd->TextureId);
595 VERIFY_EXPR(texture_srv == m_pFontSRV);
596 (void)texture_srv;
597 //ctx->PSSetShaderResources(0, 1, &texture_srv);
598 DrawIndexedAttribs DrawAttrs(pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? VT_UINT16 : VT_UINT32, DRAW_FLAG_VERIFY_STATES);
599 DrawAttrs.FirstIndexLocation = pcmd->IdxOffset + global_idx_offset;
600 DrawAttrs.BaseVertex = pcmd->VtxOffset + global_vtx_offset;
601 pCtx->DrawIndexed(DrawAttrs);
602 }
603 }
604 global_idx_offset += cmd_list->IdxBuffer.Size;
605 global_vtx_offset += cmd_list->VtxBuffer.Size;
606 }
607 }
608
609
610
61140 ImGuiImplDiligent::ImGuiImplDiligent(IRenderDevice* pDevice,
61241 TEXTURE_FORMAT BackBufferFmt,
61342 TEXTURE_FORMAT DepthBufferFmt,
61443 Uint32 InitialVertexBufferSize,
615 Uint32 InitialIndexBufferSize) :
616 m_pImpl(new ImGuiImplDiligent_Internal(pDevice, BackBufferFmt, DepthBufferFmt, InitialVertexBufferSize, InitialIndexBufferSize))
44 Uint32 InitialIndexBufferSize)
61745 {
46 ImGui::CreateContext();
47 ImGuiIO& io = ImGui::GetIO();
48 io.IniFilename = nullptr;
49 m_pRenderer.reset(new ImGuiDiligentRenderer(pDevice, BackBufferFmt, DepthBufferFmt, InitialVertexBufferSize, InitialIndexBufferSize));
61850 }
61951
62052 ImGuiImplDiligent::~ImGuiImplDiligent()
62153 {
54 ImGui::DestroyContext();
62255 }
62356
62457 void ImGuiImplDiligent::NewFrame(Uint32 RenderSurfaceWidth, Uint32 RenderSurfaceHeight, SURFACE_TRANSFORM SurfacePreTransform)
62558 {
626 m_pImpl->NewFrame(RenderSurfaceWidth, RenderSurfaceHeight, SurfacePreTransform);
59 m_pRenderer->NewFrame(RenderSurfaceWidth, RenderSurfaceHeight, SurfacePreTransform);
62760 ImGui::NewFrame();
62861 }
62962
63669 {
63770 // No need to call ImGui::EndFrame as ImGui::Render calls it automatically
63871 ImGui::Render();
639 m_pImpl->RenderDrawData(pCtx, ImGui::GetDrawData());
72 m_pRenderer->RenderDrawData(pCtx, ImGui::GetDrawData());
64073 }
64174
64275 // Use if you want to reset your rendering device without losing ImGui state.
64376 void ImGuiImplDiligent::InvalidateDeviceObjects()
64477 {
645 m_pImpl->InvalidateDeviceObjects();
78 m_pRenderer->InvalidateDeviceObjects();
64679 }
64780
64881 void ImGuiImplDiligent::CreateDeviceObjects()
64982 {
650 m_pImpl->CreateDeviceObjects();
83 m_pRenderer->CreateDeviceObjects();
65184 }
65285
65386 void ImGuiImplDiligent::UpdateFontsTexture()
65487 {
655 m_pImpl->CreateFontsTexture();
88 m_pRenderer->CreateFontsTexture();
65689 }
65790
658
65991 } // namespace Diligent