summaryrefslogtreecommitdiff
path: root/3rdparty/imgui/backend
diff options
context:
space:
mode:
authorrtk0c <[email protected]>2021-03-27 23:01:07 -0700
committerrtk0c <[email protected]>2021-03-27 23:01:07 -0700
commit442d2d75d71bbc057e667edc301a79fa1cc813be (patch)
treeb5d1e5068a4d481bc6bcd72dca851ac7a85bf7e4 /3rdparty/imgui/backend
Initial setup
Diffstat (limited to '3rdparty/imgui/backend')
-rw-r--r--3rdparty/imgui/backend/imgui_impl_dx11.cpp551
-rw-r--r--3rdparty/imgui/backend/imgui_impl_dx11.h25
-rw-r--r--3rdparty/imgui/backend/imgui_impl_dx12.cpp700
-rw-r--r--3rdparty/imgui/backend/imgui_impl_dx12.h48
-rw-r--r--3rdparty/imgui/backend/imgui_impl_glfw.cpp374
-rw-r--r--3rdparty/imgui/backend/imgui_impl_glfw.h36
-rw-r--r--3rdparty/imgui/backend/imgui_impl_metal.h28
-rw-r--r--3rdparty/imgui/backend/imgui_impl_metal.mm552
-rw-r--r--3rdparty/imgui/backend/imgui_impl_opengl2.cpp258
-rw-r--r--3rdparty/imgui/backend/imgui_impl_opengl2.h31
-rw-r--r--3rdparty/imgui/backend/imgui_impl_opengl3.cpp720
-rw-r--r--3rdparty/imgui/backend/imgui_impl_opengl3.h87
-rw-r--r--3rdparty/imgui/backend/imgui_impl_vulkan.cpp1416
-rw-r--r--3rdparty/imgui/backend/imgui_impl_vulkan.h148
14 files changed, 4974 insertions, 0 deletions
diff --git a/3rdparty/imgui/backend/imgui_impl_dx11.cpp b/3rdparty/imgui/backend/imgui_impl_dx11.cpp
new file mode 100644
index 0000000..f114cdc
--- /dev/null
+++ b/3rdparty/imgui/backend/imgui_impl_dx11.cpp
@@ -0,0 +1,551 @@
+// dear imgui: Renderer Backend for DirectX11
+// This needs to be used along with a Platform Backend (e.g. Win32)
+
+// Implemented features:
+// [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID!
+// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
+
+// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
+// Read online: https://github.com/ocornut/imgui/tree/master/docs
+
+// CHANGELOG
+// (minor and older changes stripped away, please see git history for details)
+// 2021-02-18: DirectX11: Change blending equation to preserve alpha in output buffer.
+// 2019-08-01: DirectX11: Fixed code querying the Geometry Shader state (would generally error with Debug layer enabled).
+// 2019-07-21: DirectX11: Backup, clear and restore Geometry Shader is any is bound when calling ImGui_ImplDX10_RenderDrawData. Clearing Hull/Domain/Compute shaders without backup/restore.
+// 2019-05-29: DirectX11: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
+// 2019-04-30: DirectX11: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
+// 2018-12-03: Misc: Added #pragma comment statement to automatically link with d3dcompiler.lib when using D3DCompile().
+// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
+// 2018-08-01: DirectX11: Querying for IDXGIFactory instead of IDXGIFactory1 to increase compatibility.
+// 2018-07-13: DirectX11: Fixed unreleased resources in Init and Shutdown functions.
+// 2018-06-08: Misc: Extracted imgui_impl_dx11.cpp/.h away from the old combined DX11+Win32 example.
+// 2018-06-08: DirectX11: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
+// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX11_RenderDrawData() in the .h file so you can call it yourself.
+// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
+// 2016-05-07: DirectX11: Disabling depth-write.
+
+#include "imgui.h"
+#include "imgui_impl_dx11.h"
+
+// DirectX
+#include <stdio.h>
+#include <d3d11.h>
+#include <d3dcompiler.h>
+#ifdef _MSC_VER
+#pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below.
+#endif
+
+// DirectX data
+static ID3D11Device* g_pd3dDevice = NULL;
+static ID3D11DeviceContext* g_pd3dDeviceContext = NULL;
+static IDXGIFactory* g_pFactory = NULL;
+static ID3D11Buffer* g_pVB = NULL;
+static ID3D11Buffer* g_pIB = NULL;
+static ID3D11VertexShader* g_pVertexShader = NULL;
+static ID3D11InputLayout* g_pInputLayout = NULL;
+static ID3D11Buffer* g_pVertexConstantBuffer = NULL;
+static ID3D11PixelShader* g_pPixelShader = NULL;
+static ID3D11SamplerState* g_pFontSampler = NULL;
+static ID3D11ShaderResourceView*g_pFontTextureView = NULL;
+static ID3D11RasterizerState* g_pRasterizerState = NULL;
+static ID3D11BlendState* g_pBlendState = NULL;
+static ID3D11DepthStencilState* g_pDepthStencilState = NULL;
+static int g_VertexBufferSize = 5000, g_IndexBufferSize = 10000;
+
+struct VERTEX_CONSTANT_BUFFER
+{
+ float mvp[4][4];
+};
+
+static void ImGui_ImplDX11_SetupRenderState(ImDrawData* draw_data, ID3D11DeviceContext* ctx)
+{
+ // Setup viewport
+ D3D11_VIEWPORT vp;
+ memset(&vp, 0, sizeof(D3D11_VIEWPORT));
+ vp.Width = draw_data->DisplaySize.x;
+ vp.Height = draw_data->DisplaySize.y;
+ vp.MinDepth = 0.0f;
+ vp.MaxDepth = 1.0f;
+ vp.TopLeftX = vp.TopLeftY = 0;
+ ctx->RSSetViewports(1, &vp);
+
+ // Setup shader and vertex buffers
+ unsigned int stride = sizeof(ImDrawVert);
+ unsigned int offset = 0;
+ ctx->IASetInputLayout(g_pInputLayout);
+ ctx->IASetVertexBuffers(0, 1, &g_pVB, &stride, &offset);
+ ctx->IASetIndexBuffer(g_pIB, sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0);
+ ctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
+ ctx->VSSetShader(g_pVertexShader, NULL, 0);
+ ctx->VSSetConstantBuffers(0, 1, &g_pVertexConstantBuffer);
+ ctx->PSSetShader(g_pPixelShader, NULL, 0);
+ ctx->PSSetSamplers(0, 1, &g_pFontSampler);
+ ctx->GSSetShader(NULL, NULL, 0);
+ ctx->HSSetShader(NULL, NULL, 0); // In theory we should backup and restore this as well.. very infrequently used..
+ ctx->DSSetShader(NULL, NULL, 0); // In theory we should backup and restore this as well.. very infrequently used..
+ ctx->CSSetShader(NULL, NULL, 0); // In theory we should backup and restore this as well.. very infrequently used..
+
+ // Setup blend state
+ const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f };
+ ctx->OMSetBlendState(g_pBlendState, blend_factor, 0xffffffff);
+ ctx->OMSetDepthStencilState(g_pDepthStencilState, 0);
+ ctx->RSSetState(g_pRasterizerState);
+}
+
+// Render function
+void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
+{
+ // Avoid rendering when minimized
+ if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
+ return;
+
+ ID3D11DeviceContext* ctx = g_pd3dDeviceContext;
+
+ // Create and grow vertex/index buffers if needed
+ if (!g_pVB || g_VertexBufferSize < draw_data->TotalVtxCount)
+ {
+ if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
+ g_VertexBufferSize = draw_data->TotalVtxCount + 5000;
+ D3D11_BUFFER_DESC desc;
+ memset(&desc, 0, sizeof(D3D11_BUFFER_DESC));
+ desc.Usage = D3D11_USAGE_DYNAMIC;
+ desc.ByteWidth = g_VertexBufferSize * sizeof(ImDrawVert);
+ desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
+ desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ desc.MiscFlags = 0;
+ if (g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pVB) < 0)
+ return;
+ }
+ if (!g_pIB || g_IndexBufferSize < draw_data->TotalIdxCount)
+ {
+ if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
+ g_IndexBufferSize = draw_data->TotalIdxCount + 10000;
+ D3D11_BUFFER_DESC desc;
+ memset(&desc, 0, sizeof(D3D11_BUFFER_DESC));
+ desc.Usage = D3D11_USAGE_DYNAMIC;
+ desc.ByteWidth = g_IndexBufferSize * sizeof(ImDrawIdx);
+ desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
+ desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ if (g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pIB) < 0)
+ return;
+ }
+
+ // Upload vertex/index data into a single contiguous GPU buffer
+ D3D11_MAPPED_SUBRESOURCE vtx_resource, idx_resource;
+ if (ctx->Map(g_pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vtx_resource) != S_OK)
+ return;
+ if (ctx->Map(g_pIB, 0, D3D11_MAP_WRITE_DISCARD, 0, &idx_resource) != S_OK)
+ return;
+ ImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource.pData;
+ ImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource.pData;
+ for (int n = 0; n < draw_data->CmdListsCount; n++)
+ {
+ const ImDrawList* cmd_list = draw_data->CmdLists[n];
+ memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
+ memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
+ vtx_dst += cmd_list->VtxBuffer.Size;
+ idx_dst += cmd_list->IdxBuffer.Size;
+ }
+ ctx->Unmap(g_pVB, 0);
+ ctx->Unmap(g_pIB, 0);
+
+ // Setup orthographic projection matrix into our constant buffer
+ // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
+ {
+ D3D11_MAPPED_SUBRESOURCE mapped_resource;
+ if (ctx->Map(g_pVertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK)
+ return;
+ VERTEX_CONSTANT_BUFFER* constant_buffer = (VERTEX_CONSTANT_BUFFER*)mapped_resource.pData;
+ float L = draw_data->DisplayPos.x;
+ float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
+ float T = draw_data->DisplayPos.y;
+ float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
+ float mvp[4][4] =
+ {
+ { 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
+ { 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
+ { 0.0f, 0.0f, 0.5f, 0.0f },
+ { (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f },
+ };
+ memcpy(&constant_buffer->mvp, mvp, sizeof(mvp));
+ ctx->Unmap(g_pVertexConstantBuffer, 0);
+ }
+
+ // Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!)
+ struct BACKUP_DX11_STATE
+ {
+ UINT ScissorRectsCount, ViewportsCount;
+ D3D11_RECT ScissorRects[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
+ D3D11_VIEWPORT Viewports[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
+ ID3D11RasterizerState* RS;
+ ID3D11BlendState* BlendState;
+ FLOAT BlendFactor[4];
+ UINT SampleMask;
+ UINT StencilRef;
+ ID3D11DepthStencilState* DepthStencilState;
+ ID3D11ShaderResourceView* PSShaderResource;
+ ID3D11SamplerState* PSSampler;
+ ID3D11PixelShader* PS;
+ ID3D11VertexShader* VS;
+ ID3D11GeometryShader* GS;
+ UINT PSInstancesCount, VSInstancesCount, GSInstancesCount;
+ ID3D11ClassInstance *PSInstances[256], *VSInstances[256], *GSInstances[256]; // 256 is max according to PSSetShader documentation
+ D3D11_PRIMITIVE_TOPOLOGY PrimitiveTopology;
+ ID3D11Buffer* IndexBuffer, *VertexBuffer, *VSConstantBuffer;
+ UINT IndexBufferOffset, VertexBufferStride, VertexBufferOffset;
+ DXGI_FORMAT IndexBufferFormat;
+ ID3D11InputLayout* InputLayout;
+ };
+ BACKUP_DX11_STATE old;
+ old.ScissorRectsCount = old.ViewportsCount = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
+ ctx->RSGetScissorRects(&old.ScissorRectsCount, old.ScissorRects);
+ ctx->RSGetViewports(&old.ViewportsCount, old.Viewports);
+ ctx->RSGetState(&old.RS);
+ ctx->OMGetBlendState(&old.BlendState, old.BlendFactor, &old.SampleMask);
+ ctx->OMGetDepthStencilState(&old.DepthStencilState, &old.StencilRef);
+ ctx->PSGetShaderResources(0, 1, &old.PSShaderResource);
+ ctx->PSGetSamplers(0, 1, &old.PSSampler);
+ old.PSInstancesCount = old.VSInstancesCount = old.GSInstancesCount = 256;
+ ctx->PSGetShader(&old.PS, old.PSInstances, &old.PSInstancesCount);
+ ctx->VSGetShader(&old.VS, old.VSInstances, &old.VSInstancesCount);
+ ctx->VSGetConstantBuffers(0, 1, &old.VSConstantBuffer);
+ ctx->GSGetShader(&old.GS, old.GSInstances, &old.GSInstancesCount);
+
+ ctx->IAGetPrimitiveTopology(&old.PrimitiveTopology);
+ ctx->IAGetIndexBuffer(&old.IndexBuffer, &old.IndexBufferFormat, &old.IndexBufferOffset);
+ ctx->IAGetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset);
+ ctx->IAGetInputLayout(&old.InputLayout);
+
+ // Setup desired DX state
+ ImGui_ImplDX11_SetupRenderState(draw_data, ctx);
+
+ // Render command lists
+ // (Because we merged all buffers into a single one, we maintain our own offset into them)
+ int global_idx_offset = 0;
+ int global_vtx_offset = 0;
+ ImVec2 clip_off = draw_data->DisplayPos;
+ for (int n = 0; n < draw_data->CmdListsCount; n++)
+ {
+ const ImDrawList* cmd_list = draw_data->CmdLists[n];
+ for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
+ {
+ const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
+ if (pcmd->UserCallback != NULL)
+ {
+ // User callback, registered via ImDrawList::AddCallback()
+ // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
+ if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
+ ImGui_ImplDX11_SetupRenderState(draw_data, ctx);
+ else
+ pcmd->UserCallback(cmd_list, pcmd);
+ }
+ else
+ {
+ // Apply scissor/clipping rectangle
+ const D3D11_RECT r = { (LONG)(pcmd->ClipRect.x - clip_off.x), (LONG)(pcmd->ClipRect.y - clip_off.y), (LONG)(pcmd->ClipRect.z - clip_off.x), (LONG)(pcmd->ClipRect.w - clip_off.y) };
+ ctx->RSSetScissorRects(1, &r);
+
+ // Bind texture, Draw
+ ID3D11ShaderResourceView* texture_srv = (ID3D11ShaderResourceView*)pcmd->TextureId;
+ ctx->PSSetShaderResources(0, 1, &texture_srv);
+ ctx->DrawIndexed(pcmd->ElemCount, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset);
+ }
+ }
+ global_idx_offset += cmd_list->IdxBuffer.Size;
+ global_vtx_offset += cmd_list->VtxBuffer.Size;
+ }
+
+ // Restore modified DX state
+ ctx->RSSetScissorRects(old.ScissorRectsCount, old.ScissorRects);
+ ctx->RSSetViewports(old.ViewportsCount, old.Viewports);
+ ctx->RSSetState(old.RS); if (old.RS) old.RS->Release();
+ ctx->OMSetBlendState(old.BlendState, old.BlendFactor, old.SampleMask); if (old.BlendState) old.BlendState->Release();
+ ctx->OMSetDepthStencilState(old.DepthStencilState, old.StencilRef); if (old.DepthStencilState) old.DepthStencilState->Release();
+ ctx->PSSetShaderResources(0, 1, &old.PSShaderResource); if (old.PSShaderResource) old.PSShaderResource->Release();
+ ctx->PSSetSamplers(0, 1, &old.PSSampler); if (old.PSSampler) old.PSSampler->Release();
+ ctx->PSSetShader(old.PS, old.PSInstances, old.PSInstancesCount); if (old.PS) old.PS->Release();
+ for (UINT i = 0; i < old.PSInstancesCount; i++) if (old.PSInstances[i]) old.PSInstances[i]->Release();
+ ctx->VSSetShader(old.VS, old.VSInstances, old.VSInstancesCount); if (old.VS) old.VS->Release();
+ ctx->VSSetConstantBuffers(0, 1, &old.VSConstantBuffer); if (old.VSConstantBuffer) old.VSConstantBuffer->Release();
+ ctx->GSSetShader(old.GS, old.GSInstances, old.GSInstancesCount); if (old.GS) old.GS->Release();
+ for (UINT i = 0; i < old.VSInstancesCount; i++) if (old.VSInstances[i]) old.VSInstances[i]->Release();
+ ctx->IASetPrimitiveTopology(old.PrimitiveTopology);
+ ctx->IASetIndexBuffer(old.IndexBuffer, old.IndexBufferFormat, old.IndexBufferOffset); if (old.IndexBuffer) old.IndexBuffer->Release();
+ ctx->IASetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); if (old.VertexBuffer) old.VertexBuffer->Release();
+ ctx->IASetInputLayout(old.InputLayout); if (old.InputLayout) old.InputLayout->Release();
+}
+
+static void ImGui_ImplDX11_CreateFontsTexture()
+{
+ // Build texture atlas
+ ImGuiIO& io = ImGui::GetIO();
+ unsigned char* pixels;
+ int width, height;
+ io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
+
+ // Upload texture to graphics system
+ {
+ D3D11_TEXTURE2D_DESC desc;
+ ZeroMemory(&desc, sizeof(desc));
+ desc.Width = width;
+ desc.Height = height;
+ desc.MipLevels = 1;
+ desc.ArraySize = 1;
+ desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ desc.SampleDesc.Count = 1;
+ desc.Usage = D3D11_USAGE_DEFAULT;
+ desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
+ desc.CPUAccessFlags = 0;
+
+ ID3D11Texture2D* pTexture = NULL;
+ D3D11_SUBRESOURCE_DATA subResource;
+ subResource.pSysMem = pixels;
+ subResource.SysMemPitch = desc.Width * 4;
+ subResource.SysMemSlicePitch = 0;
+ g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
+
+ // Create texture view
+ D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
+ ZeroMemory(&srvDesc, sizeof(srvDesc));
+ srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
+ srvDesc.Texture2D.MipLevels = desc.MipLevels;
+ srvDesc.Texture2D.MostDetailedMip = 0;
+ g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &g_pFontTextureView);
+ pTexture->Release();
+ }
+
+ // Store our identifier
+ io.Fonts->SetTexID((ImTextureID)g_pFontTextureView);
+
+ // Create texture sampler
+ {
+ D3D11_SAMPLER_DESC desc;
+ ZeroMemory(&desc, sizeof(desc));
+ desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
+ desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
+ desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
+ desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
+ desc.MipLODBias = 0.f;
+ desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
+ desc.MinLOD = 0.f;
+ desc.MaxLOD = 0.f;
+ g_pd3dDevice->CreateSamplerState(&desc, &g_pFontSampler);
+ }
+}
+
+bool ImGui_ImplDX11_CreateDeviceObjects()
+{
+ if (!g_pd3dDevice)
+ return false;
+ if (g_pFontSampler)
+ ImGui_ImplDX11_InvalidateDeviceObjects();
+
+ // By using D3DCompile() from <d3dcompiler.h> / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A)
+ // If you would like to use this DX11 sample code but remove this dependency you can:
+ // 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [preferred solution]
+ // 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL.
+ // See https://github.com/ocornut/imgui/pull/638 for sources and details.
+
+ // Create the vertex shader
+ {
+ static const char* vertexShader =
+ "cbuffer vertexBuffer : register(b0) \
+ {\
+ float4x4 ProjectionMatrix; \
+ };\
+ struct VS_INPUT\
+ {\
+ float2 pos : POSITION;\
+ float4 col : COLOR0;\
+ float2 uv : TEXCOORD0;\
+ };\
+ \
+ struct PS_INPUT\
+ {\
+ float4 pos : SV_POSITION;\
+ float4 col : COLOR0;\
+ float2 uv : TEXCOORD0;\
+ };\
+ \
+ PS_INPUT main(VS_INPUT input)\
+ {\
+ PS_INPUT output;\
+ output.pos = mul( ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));\
+ output.col = input.col;\
+ output.uv = input.uv;\
+ return output;\
+ }";
+
+ ID3DBlob* vertexShaderBlob;
+ if (FAILED(D3DCompile(vertexShader, strlen(vertexShader), NULL, NULL, NULL, "main", "vs_4_0", 0, 0, &vertexShaderBlob, NULL)))
+ return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
+ if (g_pd3dDevice->CreateVertexShader(vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), NULL, &g_pVertexShader) != S_OK)
+ {
+ vertexShaderBlob->Release();
+ return false;
+ }
+
+ // Create the input layout
+ D3D11_INPUT_ELEMENT_DESC local_layout[] =
+ {
+ { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)IM_OFFSETOF(ImDrawVert, pos), D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)IM_OFFSETOF(ImDrawVert, uv), D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (UINT)IM_OFFSETOF(ImDrawVert, col), D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ };
+ if (g_pd3dDevice->CreateInputLayout(local_layout, 3, vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), &g_pInputLayout) != S_OK)
+ {
+ vertexShaderBlob->Release();
+ return false;
+ }
+ vertexShaderBlob->Release();
+
+ // Create the constant buffer
+ {
+ D3D11_BUFFER_DESC desc;
+ desc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER);
+ desc.Usage = D3D11_USAGE_DYNAMIC;
+ desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
+ desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ desc.MiscFlags = 0;
+ g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pVertexConstantBuffer);
+ }
+ }
+
+ // Create the pixel shader
+ {
+ static const char* pixelShader =
+ "struct PS_INPUT\
+ {\
+ float4 pos : SV_POSITION;\
+ float4 col : COLOR0;\
+ float2 uv : TEXCOORD0;\
+ };\
+ sampler sampler0;\
+ Texture2D texture0;\
+ \
+ float4 main(PS_INPUT input) : SV_Target\
+ {\
+ float4 out_col = input.col * texture0.Sample(sampler0, input.uv); \
+ return out_col; \
+ }";
+
+ ID3DBlob* pixelShaderBlob;
+ if (FAILED(D3DCompile(pixelShader, strlen(pixelShader), NULL, NULL, NULL, "main", "ps_4_0", 0, 0, &pixelShaderBlob, NULL)))
+ return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
+ if (g_pd3dDevice->CreatePixelShader(pixelShaderBlob->GetBufferPointer(), pixelShaderBlob->GetBufferSize(), NULL, &g_pPixelShader) != S_OK)
+ {
+ pixelShaderBlob->Release();
+ return false;
+ }
+ pixelShaderBlob->Release();
+ }
+
+ // Create the blending setup
+ {
+ D3D11_BLEND_DESC desc;
+ ZeroMemory(&desc, sizeof(desc));
+ desc.AlphaToCoverageEnable = false;
+ desc.RenderTarget[0].BlendEnable = true;
+ desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
+ desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
+ desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
+ desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
+ desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
+ desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
+ desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
+ g_pd3dDevice->CreateBlendState(&desc, &g_pBlendState);
+ }
+
+ // Create the rasterizer state
+ {
+ D3D11_RASTERIZER_DESC desc;
+ ZeroMemory(&desc, sizeof(desc));
+ desc.FillMode = D3D11_FILL_SOLID;
+ desc.CullMode = D3D11_CULL_NONE;
+ desc.ScissorEnable = true;
+ desc.DepthClipEnable = true;
+ g_pd3dDevice->CreateRasterizerState(&desc, &g_pRasterizerState);
+ }
+
+ // Create depth-stencil State
+ {
+ D3D11_DEPTH_STENCIL_DESC desc;
+ ZeroMemory(&desc, sizeof(desc));
+ desc.DepthEnable = false;
+ desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
+ desc.DepthFunc = D3D11_COMPARISON_ALWAYS;
+ desc.StencilEnable = false;
+ desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
+ desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
+ desc.BackFace = desc.FrontFace;
+ g_pd3dDevice->CreateDepthStencilState(&desc, &g_pDepthStencilState);
+ }
+
+ ImGui_ImplDX11_CreateFontsTexture();
+
+ return true;
+}
+
+void ImGui_ImplDX11_InvalidateDeviceObjects()
+{
+ if (!g_pd3dDevice)
+ return;
+
+ if (g_pFontSampler) { g_pFontSampler->Release(); g_pFontSampler = NULL; }
+ if (g_pFontTextureView) { g_pFontTextureView->Release(); g_pFontTextureView = NULL; ImGui::GetIO().Fonts->SetTexID(NULL); } // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well.
+ if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
+ if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
+
+ if (g_pBlendState) { g_pBlendState->Release(); g_pBlendState = NULL; }
+ if (g_pDepthStencilState) { g_pDepthStencilState->Release(); g_pDepthStencilState = NULL; }
+ if (g_pRasterizerState) { g_pRasterizerState->Release(); g_pRasterizerState = NULL; }
+ if (g_pPixelShader) { g_pPixelShader->Release(); g_pPixelShader = NULL; }
+ if (g_pVertexConstantBuffer) { g_pVertexConstantBuffer->Release(); g_pVertexConstantBuffer = NULL; }
+ if (g_pInputLayout) { g_pInputLayout->Release(); g_pInputLayout = NULL; }
+ if (g_pVertexShader) { g_pVertexShader->Release(); g_pVertexShader = NULL; }
+}
+
+bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context)
+{
+ // Setup backend capabilities flags
+ ImGuiIO& io = ImGui::GetIO();
+ io.BackendRendererName = "imgui_impl_dx11";
+ io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
+
+ // Get factory from device
+ IDXGIDevice* pDXGIDevice = NULL;
+ IDXGIAdapter* pDXGIAdapter = NULL;
+ IDXGIFactory* pFactory = NULL;
+
+ if (device->QueryInterface(IID_PPV_ARGS(&pDXGIDevice)) == S_OK)
+ if (pDXGIDevice->GetParent(IID_PPV_ARGS(&pDXGIAdapter)) == S_OK)
+ if (pDXGIAdapter->GetParent(IID_PPV_ARGS(&pFactory)) == S_OK)
+ {
+ g_pd3dDevice = device;
+ g_pd3dDeviceContext = device_context;
+ g_pFactory = pFactory;
+ }
+ if (pDXGIDevice) pDXGIDevice->Release();
+ if (pDXGIAdapter) pDXGIAdapter->Release();
+ g_pd3dDevice->AddRef();
+ g_pd3dDeviceContext->AddRef();
+
+ return true;
+}
+
+void ImGui_ImplDX11_Shutdown()
+{
+ ImGui_ImplDX11_InvalidateDeviceObjects();
+ if (g_pFactory) { g_pFactory->Release(); g_pFactory = NULL; }
+ if (g_pd3dDevice) { g_pd3dDevice->Release(); g_pd3dDevice = NULL; }
+ if (g_pd3dDeviceContext) { g_pd3dDeviceContext->Release(); g_pd3dDeviceContext = NULL; }
+}
+
+void ImGui_ImplDX11_NewFrame()
+{
+ if (!g_pFontSampler)
+ ImGui_ImplDX11_CreateDeviceObjects();
+}
diff --git a/3rdparty/imgui/backend/imgui_impl_dx11.h b/3rdparty/imgui/backend/imgui_impl_dx11.h
new file mode 100644
index 0000000..03fee14
--- /dev/null
+++ b/3rdparty/imgui/backend/imgui_impl_dx11.h
@@ -0,0 +1,25 @@
+// dear imgui: Renderer Backend for DirectX11
+// This needs to be used along with a Platform Backend (e.g. Win32)
+
+// Implemented features:
+// [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID!
+// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
+
+// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
+// Read online: https://github.com/ocornut/imgui/tree/master/docs
+
+#pragma once
+#include "imgui.h" // IMGUI_IMPL_API
+
+struct ID3D11Device;
+struct ID3D11DeviceContext;
+
+IMGUI_IMPL_API bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context);
+IMGUI_IMPL_API void ImGui_ImplDX11_Shutdown();
+IMGUI_IMPL_API void ImGui_ImplDX11_NewFrame();
+IMGUI_IMPL_API void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data);
+
+// Use if you want to reset your rendering device without losing Dear ImGui state.
+IMGUI_IMPL_API void ImGui_ImplDX11_InvalidateDeviceObjects();
+IMGUI_IMPL_API bool ImGui_ImplDX11_CreateDeviceObjects();
diff --git a/3rdparty/imgui/backend/imgui_impl_dx12.cpp b/3rdparty/imgui/backend/imgui_impl_dx12.cpp
new file mode 100644
index 0000000..860fe66
--- /dev/null
+++ b/3rdparty/imgui/backend/imgui_impl_dx12.cpp
@@ -0,0 +1,700 @@
+// dear imgui: Renderer Backend for DirectX12
+// This needs to be used along with a Platform Backend (e.g. Win32)
+
+// Implemented features:
+// [X] Renderer: User texture binding. Use 'D3D12_GPU_DESCRIPTOR_HANDLE' as ImTextureID. Read the FAQ about ImTextureID!
+// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
+
+// Important: to compile on 32-bit systems, this backend requires code to be compiled with '#define ImTextureID ImU64'.
+// This is because we need ImTextureID to carry a 64-bit value and by default ImTextureID is defined as void*.
+// This define is set in the example .vcxproj file and need to be replicated in your app or by adding it to your imconfig.h file.
+
+// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
+// Read online: https://github.com/ocornut/imgui/tree/master/docs
+
+// CHANGELOG
+// (minor and older changes stripped away, please see git history for details)
+// 2021-02-18: DirectX12: Change blending equation to preserve alpha in output buffer.
+// 2021-01-11: DirectX12: Improve Windows 7 compatibility (for D3D12On7) by loading d3d12.dll dynamically.
+// 2020-09-16: DirectX12: Avoid rendering calls with zero-sized scissor rectangle since it generates a validation layer warning.
+// 2020-09-08: DirectX12: Clarified support for building on 32-bit systems by redefining ImTextureID.
+// 2019-10-18: DirectX12: *BREAKING CHANGE* Added extra ID3D12DescriptorHeap parameter to ImGui_ImplDX12_Init() function.
+// 2019-05-29: DirectX12: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
+// 2019-04-30: DirectX12: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
+// 2019-03-29: Misc: Various minor tidying up.
+// 2018-12-03: Misc: Added #pragma comment statement to automatically link with d3dcompiler.lib when using D3DCompile().
+// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
+// 2018-06-12: DirectX12: Moved the ID3D12GraphicsCommandList* parameter from NewFrame() to RenderDrawData().
+// 2018-06-08: Misc: Extracted imgui_impl_dx12.cpp/.h away from the old combined DX12+Win32 example.
+// 2018-06-08: DirectX12: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle (to ease support for future multi-viewport).
+// 2018-02-22: Merged into master with all Win32 code synchronized to other examples.
+
+#include "imgui.h"
+#include "imgui_impl_dx12.h"
+
+// DirectX
+#include <d3d12.h>
+#include <dxgi1_4.h>
+#include <d3dcompiler.h>
+#ifdef _MSC_VER
+#pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below.
+#endif
+
+// DirectX data
+static ID3D12Device* g_pd3dDevice = NULL;
+static ID3D12RootSignature* g_pRootSignature = NULL;
+static ID3D12PipelineState* g_pPipelineState = NULL;
+static DXGI_FORMAT g_RTVFormat = DXGI_FORMAT_UNKNOWN;
+static ID3D12Resource* g_pFontTextureResource = NULL;
+static D3D12_CPU_DESCRIPTOR_HANDLE g_hFontSrvCpuDescHandle = {};
+static D3D12_GPU_DESCRIPTOR_HANDLE g_hFontSrvGpuDescHandle = {};
+
+struct FrameResources
+{
+ ID3D12Resource* IndexBuffer;
+ ID3D12Resource* VertexBuffer;
+ int IndexBufferSize;
+ int VertexBufferSize;
+};
+static FrameResources* g_pFrameResources = NULL;
+static UINT g_numFramesInFlight = 0;
+static UINT g_frameIndex = UINT_MAX;
+
+template<typename T>
+static void SafeRelease(T*& res)
+{
+ if (res)
+ res->Release();
+ res = NULL;
+}
+
+struct VERTEX_CONSTANT_BUFFER
+{
+ float mvp[4][4];
+};
+
+static void ImGui_ImplDX12_SetupRenderState(ImDrawData* draw_data, ID3D12GraphicsCommandList* ctx, FrameResources* fr)
+{
+ // Setup orthographic projection matrix into our constant buffer
+ // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right).
+ VERTEX_CONSTANT_BUFFER vertex_constant_buffer;
+ {
+ float L = draw_data->DisplayPos.x;
+ float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
+ float T = draw_data->DisplayPos.y;
+ float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
+ float mvp[4][4] =
+ {
+ { 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
+ { 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
+ { 0.0f, 0.0f, 0.5f, 0.0f },
+ { (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f },
+ };
+ memcpy(&vertex_constant_buffer.mvp, mvp, sizeof(mvp));
+ }
+
+ // Setup viewport
+ D3D12_VIEWPORT vp;
+ memset(&vp, 0, sizeof(D3D12_VIEWPORT));
+ vp.Width = draw_data->DisplaySize.x;
+ vp.Height = draw_data->DisplaySize.y;
+ vp.MinDepth = 0.0f;
+ vp.MaxDepth = 1.0f;
+ vp.TopLeftX = vp.TopLeftY = 0.0f;
+ ctx->RSSetViewports(1, &vp);
+
+ // Bind shader and vertex buffers
+ unsigned int stride = sizeof(ImDrawVert);
+ unsigned int offset = 0;
+ D3D12_VERTEX_BUFFER_VIEW vbv;
+ memset(&vbv, 0, sizeof(D3D12_VERTEX_BUFFER_VIEW));
+ vbv.BufferLocation = fr->VertexBuffer->GetGPUVirtualAddress() + offset;
+ vbv.SizeInBytes = fr->VertexBufferSize * stride;
+ vbv.StrideInBytes = stride;
+ ctx->IASetVertexBuffers(0, 1, &vbv);
+ D3D12_INDEX_BUFFER_VIEW ibv;
+ memset(&ibv, 0, sizeof(D3D12_INDEX_BUFFER_VIEW));
+ ibv.BufferLocation = fr->IndexBuffer->GetGPUVirtualAddress();
+ ibv.SizeInBytes = fr->IndexBufferSize * sizeof(ImDrawIdx);
+ ibv.Format = sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT;
+ ctx->IASetIndexBuffer(&ibv);
+ ctx->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
+ ctx->SetPipelineState(g_pPipelineState);
+ ctx->SetGraphicsRootSignature(g_pRootSignature);
+ ctx->SetGraphicsRoot32BitConstants(0, 16, &vertex_constant_buffer, 0);
+
+ // Setup blend factor
+ const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f };
+ ctx->OMSetBlendFactor(blend_factor);
+}
+
+// Render function
+void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandList* ctx)
+{
+ // Avoid rendering when minimized
+ if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
+ return;
+
+ // FIXME: I'm assuming that this only gets called once per frame!
+ // If not, we can't just re-allocate the IB or VB, we'll have to do a proper allocator.
+ g_frameIndex = g_frameIndex + 1;
+ FrameResources* fr = &g_pFrameResources[g_frameIndex % g_numFramesInFlight];
+
+ // Create and grow vertex/index buffers if needed
+ if (fr->VertexBuffer == NULL || fr->VertexBufferSize < draw_data->TotalVtxCount)
+ {
+ SafeRelease(fr->VertexBuffer);
+ fr->VertexBufferSize = draw_data->TotalVtxCount + 5000;
+ D3D12_HEAP_PROPERTIES props;
+ memset(&props, 0, sizeof(D3D12_HEAP_PROPERTIES));
+ props.Type = D3D12_HEAP_TYPE_UPLOAD;
+ props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
+ props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
+ D3D12_RESOURCE_DESC desc;
+ memset(&desc, 0, sizeof(D3D12_RESOURCE_DESC));
+ desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
+ desc.Width = fr->VertexBufferSize * sizeof(ImDrawVert);
+ desc.Height = 1;
+ desc.DepthOrArraySize = 1;
+ desc.MipLevels = 1;
+ desc.Format = DXGI_FORMAT_UNKNOWN;
+ desc.SampleDesc.Count = 1;
+ desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
+ desc.Flags = D3D12_RESOURCE_FLAG_NONE;
+ if (g_pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL, IID_PPV_ARGS(&fr->VertexBuffer)) < 0)
+ return;
+ }
+ if (fr->IndexBuffer == NULL || fr->IndexBufferSize < draw_data->TotalIdxCount)
+ {
+ SafeRelease(fr->IndexBuffer);
+ fr->IndexBufferSize = draw_data->TotalIdxCount + 10000;
+ D3D12_HEAP_PROPERTIES props;
+ memset(&props, 0, sizeof(D3D12_HEAP_PROPERTIES));
+ props.Type = D3D12_HEAP_TYPE_UPLOAD;
+ props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
+ props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
+ D3D12_RESOURCE_DESC desc;
+ memset(&desc, 0, sizeof(D3D12_RESOURCE_DESC));
+ desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
+ desc.Width = fr->IndexBufferSize * sizeof(ImDrawIdx);
+ desc.Height = 1;
+ desc.DepthOrArraySize = 1;
+ desc.MipLevels = 1;
+ desc.Format = DXGI_FORMAT_UNKNOWN;
+ desc.SampleDesc.Count = 1;
+ desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
+ desc.Flags = D3D12_RESOURCE_FLAG_NONE;
+ if (g_pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL, IID_PPV_ARGS(&fr->IndexBuffer)) < 0)
+ return;
+ }
+
+ // Upload vertex/index data into a single contiguous GPU buffer
+ void* vtx_resource, *idx_resource;
+ D3D12_RANGE range;
+ memset(&range, 0, sizeof(D3D12_RANGE));
+ if (fr->VertexBuffer->Map(0, &range, &vtx_resource) != S_OK)
+ return;
+ if (fr->IndexBuffer->Map(0, &range, &idx_resource) != S_OK)
+ return;
+ ImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource;
+ ImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource;
+ for (int n = 0; n < draw_data->CmdListsCount; n++)
+ {
+ const ImDrawList* cmd_list = draw_data->CmdLists[n];
+ memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
+ memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
+ vtx_dst += cmd_list->VtxBuffer.Size;
+ idx_dst += cmd_list->IdxBuffer.Size;
+ }
+ fr->VertexBuffer->Unmap(0, &range);
+ fr->IndexBuffer->Unmap(0, &range);
+
+ // Setup desired DX state
+ ImGui_ImplDX12_SetupRenderState(draw_data, ctx, fr);
+
+ // Render command lists
+ // (Because we merged all buffers into a single one, we maintain our own offset into them)
+ int global_vtx_offset = 0;
+ int global_idx_offset = 0;
+ ImVec2 clip_off = draw_data->DisplayPos;
+ for (int n = 0; n < draw_data->CmdListsCount; n++)
+ {
+ const ImDrawList* cmd_list = draw_data->CmdLists[n];
+ for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
+ {
+ const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
+ if (pcmd->UserCallback != NULL)
+ {
+ // User callback, registered via ImDrawList::AddCallback()
+ // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
+ if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
+ ImGui_ImplDX12_SetupRenderState(draw_data, ctx, fr);
+ else
+ pcmd->UserCallback(cmd_list, pcmd);
+ }
+ else
+ {
+ // Apply Scissor, Bind texture, Draw
+ const D3D12_RECT r = { (LONG)(pcmd->ClipRect.x - clip_off.x), (LONG)(pcmd->ClipRect.y - clip_off.y), (LONG)(pcmd->ClipRect.z - clip_off.x), (LONG)(pcmd->ClipRect.w - clip_off.y) };
+ if (r.right > r.left && r.bottom > r.top)
+ {
+ ctx->SetGraphicsRootDescriptorTable(1, *(D3D12_GPU_DESCRIPTOR_HANDLE*)&pcmd->TextureId);
+ ctx->RSSetScissorRects(1, &r);
+ ctx->DrawIndexedInstanced(pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0);
+ }
+ }
+ }
+ global_idx_offset += cmd_list->IdxBuffer.Size;
+ global_vtx_offset += cmd_list->VtxBuffer.Size;
+ }
+}
+
+static void ImGui_ImplDX12_CreateFontsTexture()
+{
+ // Build texture atlas
+ ImGuiIO& io = ImGui::GetIO();
+ unsigned char* pixels;
+ int width, height;
+ io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
+
+ // Upload texture to graphics system
+ {
+ D3D12_HEAP_PROPERTIES props;
+ memset(&props, 0, sizeof(D3D12_HEAP_PROPERTIES));
+ props.Type = D3D12_HEAP_TYPE_DEFAULT;
+ props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
+ props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
+
+ D3D12_RESOURCE_DESC desc;
+ ZeroMemory(&desc, sizeof(desc));
+ desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
+ desc.Alignment = 0;
+ desc.Width = width;
+ desc.Height = height;
+ desc.DepthOrArraySize = 1;
+ desc.MipLevels = 1;
+ desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ desc.SampleDesc.Count = 1;
+ desc.SampleDesc.Quality = 0;
+ desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
+ desc.Flags = D3D12_RESOURCE_FLAG_NONE;
+
+ ID3D12Resource* pTexture = NULL;
+ g_pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc,
+ D3D12_RESOURCE_STATE_COPY_DEST, NULL, IID_PPV_ARGS(&pTexture));
+
+ UINT uploadPitch = (width * 4 + D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u) & ~(D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u);
+ UINT uploadSize = height * uploadPitch;
+ desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
+ desc.Alignment = 0;
+ desc.Width = uploadSize;
+ desc.Height = 1;
+ desc.DepthOrArraySize = 1;
+ desc.MipLevels = 1;
+ desc.Format = DXGI_FORMAT_UNKNOWN;
+ desc.SampleDesc.Count = 1;
+ desc.SampleDesc.Quality = 0;
+ desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
+ desc.Flags = D3D12_RESOURCE_FLAG_NONE;
+
+ props.Type = D3D12_HEAP_TYPE_UPLOAD;
+ props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
+ props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
+
+ ID3D12Resource* uploadBuffer = NULL;
+ HRESULT hr = g_pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc,
+ D3D12_RESOURCE_STATE_GENERIC_READ, NULL, IID_PPV_ARGS(&uploadBuffer));
+ IM_ASSERT(SUCCEEDED(hr));
+
+ void* mapped = NULL;
+ D3D12_RANGE range = { 0, uploadSize };
+ hr = uploadBuffer->Map(0, &range, &mapped);
+ IM_ASSERT(SUCCEEDED(hr));
+ for (int y = 0; y < height; y++)
+ memcpy((void*) ((uintptr_t) mapped + y * uploadPitch), pixels + y * width * 4, width * 4);
+ uploadBuffer->Unmap(0, &range);
+
+ D3D12_TEXTURE_COPY_LOCATION srcLocation = {};
+ srcLocation.pResource = uploadBuffer;
+ srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
+ srcLocation.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ srcLocation.PlacedFootprint.Footprint.Width = width;
+ srcLocation.PlacedFootprint.Footprint.Height = height;
+ srcLocation.PlacedFootprint.Footprint.Depth = 1;
+ srcLocation.PlacedFootprint.Footprint.RowPitch = uploadPitch;
+
+ D3D12_TEXTURE_COPY_LOCATION dstLocation = {};
+ dstLocation.pResource = pTexture;
+ dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
+ dstLocation.SubresourceIndex = 0;
+
+ D3D12_RESOURCE_BARRIER barrier = {};
+ barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
+ barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
+ barrier.Transition.pResource = pTexture;
+ barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
+ barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
+ barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
+
+ ID3D12Fence* fence = NULL;
+ hr = g_pd3dDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence));
+ IM_ASSERT(SUCCEEDED(hr));
+
+ HANDLE event = CreateEvent(0, 0, 0, 0);
+ IM_ASSERT(event != NULL);
+
+ D3D12_COMMAND_QUEUE_DESC queueDesc = {};
+ queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
+ queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
+ queueDesc.NodeMask = 1;
+
+ ID3D12CommandQueue* cmdQueue = NULL;
+ hr = g_pd3dDevice->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&cmdQueue));
+ IM_ASSERT(SUCCEEDED(hr));
+
+ ID3D12CommandAllocator* cmdAlloc = NULL;
+ hr = g_pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&cmdAlloc));
+ IM_ASSERT(SUCCEEDED(hr));
+
+ ID3D12GraphicsCommandList* cmdList = NULL;
+ hr = g_pd3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, cmdAlloc, NULL, IID_PPV_ARGS(&cmdList));
+ IM_ASSERT(SUCCEEDED(hr));
+
+ cmdList->CopyTextureRegion(&dstLocation, 0, 0, 0, &srcLocation, NULL);
+ cmdList->ResourceBarrier(1, &barrier);
+
+ hr = cmdList->Close();
+ IM_ASSERT(SUCCEEDED(hr));
+
+ cmdQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&cmdList);
+ hr = cmdQueue->Signal(fence, 1);
+ IM_ASSERT(SUCCEEDED(hr));
+
+ fence->SetEventOnCompletion(1, event);
+ WaitForSingleObject(event, INFINITE);
+
+ cmdList->Release();
+ cmdAlloc->Release();
+ cmdQueue->Release();
+ CloseHandle(event);
+ fence->Release();
+ uploadBuffer->Release();
+
+ // Create texture view
+ D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc;
+ ZeroMemory(&srvDesc, sizeof(srvDesc));
+ srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
+ srvDesc.Texture2D.MipLevels = desc.MipLevels;
+ srvDesc.Texture2D.MostDetailedMip = 0;
+ srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
+ g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, g_hFontSrvCpuDescHandle);
+ SafeRelease(g_pFontTextureResource);
+ g_pFontTextureResource = pTexture;
+ }
+
+ // Store our identifier
+ static_assert(sizeof(ImTextureID) >= sizeof(g_hFontSrvGpuDescHandle.ptr), "Can't pack descriptor handle into TexID, 32-bit not supported yet.");
+ io.Fonts->SetTexID((ImTextureID)g_hFontSrvGpuDescHandle.ptr);
+}
+
+bool ImGui_ImplDX12_CreateDeviceObjects()
+{
+ if (!g_pd3dDevice)
+ return false;
+ if (g_pPipelineState)
+ ImGui_ImplDX12_InvalidateDeviceObjects();
+
+ // Create the root signature
+ {
+ D3D12_DESCRIPTOR_RANGE descRange = {};
+ descRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
+ descRange.NumDescriptors = 1;
+ descRange.BaseShaderRegister = 0;
+ descRange.RegisterSpace = 0;
+ descRange.OffsetInDescriptorsFromTableStart = 0;
+
+ D3D12_ROOT_PARAMETER param[2] = {};
+
+ param[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
+ param[0].Constants.ShaderRegister = 0;
+ param[0].Constants.RegisterSpace = 0;
+ param[0].Constants.Num32BitValues = 16;
+ param[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX;
+
+ param[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
+ param[1].DescriptorTable.NumDescriptorRanges = 1;
+ param[1].DescriptorTable.pDescriptorRanges = &descRange;
+ param[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
+
+ D3D12_STATIC_SAMPLER_DESC staticSampler = {};
+ staticSampler.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
+ staticSampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
+ staticSampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
+ staticSampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
+ staticSampler.MipLODBias = 0.f;
+ staticSampler.MaxAnisotropy = 0;
+ staticSampler.ComparisonFunc = D3D12_COMPARISON_FUNC_ALWAYS;
+ staticSampler.BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK;
+ staticSampler.MinLOD = 0.f;
+ staticSampler.MaxLOD = 0.f;
+ staticSampler.ShaderRegister = 0;
+ staticSampler.RegisterSpace = 0;
+ staticSampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
+
+ D3D12_ROOT_SIGNATURE_DESC desc = {};
+ desc.NumParameters = _countof(param);
+ desc.pParameters = param;
+ desc.NumStaticSamplers = 1;
+ desc.pStaticSamplers = &staticSampler;
+ desc.Flags =
+ D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |
+ D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS |
+ D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |
+ D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS;
+
+ // Load d3d12.dll and D3D12SerializeRootSignature() function address dynamically to facilitate using with D3D12On7.
+ // See if any version of d3d12.dll is already loaded in the process. If so, give preference to that.
+ static HINSTANCE d3d12_dll = ::GetModuleHandleA("d3d12.dll");
+ if (d3d12_dll == NULL)
+ {
+ // Attempt to load d3d12.dll from local directories. This will only succeed if
+ // (1) the current OS is Windows 7, and
+ // (2) there exists a version of d3d12.dll for Windows 7 (D3D12On7) in one of the following directories.
+ // See https://github.com/ocornut/imgui/pull/3696 for details.
+ const char* localD3d12Paths[] = { ".\\d3d12.dll", ".\\d3d12on7\\d3d12.dll", ".\\12on7\\d3d12.dll" }; // A. current directory, B. used by some games, C. used in Microsoft D3D12On7 sample
+ for (int i = 0; i < IM_ARRAYSIZE(localD3d12Paths); i++)
+ if ((d3d12_dll = ::LoadLibraryA(localD3d12Paths[i])) != NULL)
+ break;
+
+ // If failed, we are on Windows >= 10.
+ if (d3d12_dll == NULL)
+ d3d12_dll = ::LoadLibraryA("d3d12.dll");
+
+ if (d3d12_dll == NULL)
+ return false;
+ }
+
+ PFN_D3D12_SERIALIZE_ROOT_SIGNATURE D3D12SerializeRootSignatureFn = (PFN_D3D12_SERIALIZE_ROOT_SIGNATURE)::GetProcAddress(d3d12_dll, "D3D12SerializeRootSignature");
+ if (D3D12SerializeRootSignatureFn == NULL)
+ return false;
+
+ ID3DBlob* blob = NULL;
+ if (D3D12SerializeRootSignatureFn(&desc, D3D_ROOT_SIGNATURE_VERSION_1, &blob, NULL) != S_OK)
+ return false;
+
+ g_pd3dDevice->CreateRootSignature(0, blob->GetBufferPointer(), blob->GetBufferSize(), IID_PPV_ARGS(&g_pRootSignature));
+ blob->Release();
+ }
+
+ // By using D3DCompile() from <d3dcompiler.h> / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A)
+ // If you would like to use this DX12 sample code but remove this dependency you can:
+ // 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [preferred solution]
+ // 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL.
+ // See https://github.com/ocornut/imgui/pull/638 for sources and details.
+
+ D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc;
+ memset(&psoDesc, 0, sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC));
+ psoDesc.NodeMask = 1;
+ psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
+ psoDesc.pRootSignature = g_pRootSignature;
+ psoDesc.SampleMask = UINT_MAX;
+ psoDesc.NumRenderTargets = 1;
+ psoDesc.RTVFormats[0] = g_RTVFormat;
+ psoDesc.SampleDesc.Count = 1;
+ psoDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
+
+ ID3DBlob* vertexShaderBlob;
+ ID3DBlob* pixelShaderBlob;
+
+ // Create the vertex shader
+ {
+ static const char* vertexShader =
+ "cbuffer vertexBuffer : register(b0) \
+ {\
+ float4x4 ProjectionMatrix; \
+ };\
+ struct VS_INPUT\
+ {\
+ float2 pos : POSITION;\
+ float4 col : COLOR0;\
+ float2 uv : TEXCOORD0;\
+ };\
+ \
+ struct PS_INPUT\
+ {\
+ float4 pos : SV_POSITION;\
+ float4 col : COLOR0;\
+ float2 uv : TEXCOORD0;\
+ };\
+ \
+ PS_INPUT main(VS_INPUT input)\
+ {\
+ PS_INPUT output;\
+ output.pos = mul( ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));\
+ output.col = input.col;\
+ output.uv = input.uv;\
+ return output;\
+ }";
+
+ if (FAILED(D3DCompile(vertexShader, strlen(vertexShader), NULL, NULL, NULL, "main", "vs_5_0", 0, 0, &vertexShaderBlob, NULL)))
+ return false; // NB: Pass ID3D10Blob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
+ psoDesc.VS = { vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize() };
+
+ // Create the input layout
+ static D3D12_INPUT_ELEMENT_DESC local_layout[] =
+ {
+ { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)IM_OFFSETOF(ImDrawVert, pos), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
+ { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)IM_OFFSETOF(ImDrawVert, uv), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
+ { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (UINT)IM_OFFSETOF(ImDrawVert, col), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
+ };
+ psoDesc.InputLayout = { local_layout, 3 };
+ }
+
+ // Create the pixel shader
+ {
+ static const char* pixelShader =
+ "struct PS_INPUT\
+ {\
+ float4 pos : SV_POSITION;\
+ float4 col : COLOR0;\
+ float2 uv : TEXCOORD0;\
+ };\
+ SamplerState sampler0 : register(s0);\
+ Texture2D texture0 : register(t0);\
+ \
+ float4 main(PS_INPUT input) : SV_Target\
+ {\
+ float4 out_col = input.col * texture0.Sample(sampler0, input.uv); \
+ return out_col; \
+ }";
+
+ if (FAILED(D3DCompile(pixelShader, strlen(pixelShader), NULL, NULL, NULL, "main", "ps_5_0", 0, 0, &pixelShaderBlob, NULL)))
+ {
+ vertexShaderBlob->Release();
+ return false; // NB: Pass ID3D10Blob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
+ }
+ psoDesc.PS = { pixelShaderBlob->GetBufferPointer(), pixelShaderBlob->GetBufferSize() };
+ }
+
+ // Create the blending setup
+ {
+ D3D12_BLEND_DESC& desc = psoDesc.BlendState;
+ desc.AlphaToCoverageEnable = false;
+ desc.RenderTarget[0].BlendEnable = true;
+ desc.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA;
+ desc.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
+ desc.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD;
+ desc.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE;
+ desc.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA;
+ desc.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD;
+ desc.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
+ }
+
+ // Create the rasterizer state
+ {
+ D3D12_RASTERIZER_DESC& desc = psoDesc.RasterizerState;
+ desc.FillMode = D3D12_FILL_MODE_SOLID;
+ desc.CullMode = D3D12_CULL_MODE_NONE;
+ desc.FrontCounterClockwise = FALSE;
+ desc.DepthBias = D3D12_DEFAULT_DEPTH_BIAS;
+ desc.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP;
+ desc.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS;
+ desc.DepthClipEnable = true;
+ desc.MultisampleEnable = FALSE;
+ desc.AntialiasedLineEnable = FALSE;
+ desc.ForcedSampleCount = 0;
+ desc.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
+ }
+
+ // Create depth-stencil State
+ {
+ D3D12_DEPTH_STENCIL_DESC& desc = psoDesc.DepthStencilState;
+ desc.DepthEnable = false;
+ desc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
+ desc.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS;
+ desc.StencilEnable = false;
+ desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D12_STENCIL_OP_KEEP;
+ desc.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS;
+ desc.BackFace = desc.FrontFace;
+ }
+
+ HRESULT result_pipeline_state = g_pd3dDevice->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&g_pPipelineState));
+ vertexShaderBlob->Release();
+ pixelShaderBlob->Release();
+ if (result_pipeline_state != S_OK)
+ return false;
+
+ ImGui_ImplDX12_CreateFontsTexture();
+
+ return true;
+}
+
+void ImGui_ImplDX12_InvalidateDeviceObjects()
+{
+ if (!g_pd3dDevice)
+ return;
+
+ SafeRelease(g_pRootSignature);
+ SafeRelease(g_pPipelineState);
+ SafeRelease(g_pFontTextureResource);
+
+ ImGuiIO& io = ImGui::GetIO();
+ io.Fonts->SetTexID(NULL); // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well.
+
+ for (UINT i = 0; i < g_numFramesInFlight; i++)
+ {
+ FrameResources* fr = &g_pFrameResources[i];
+ SafeRelease(fr->IndexBuffer);
+ SafeRelease(fr->VertexBuffer);
+ }
+}
+
+bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, ID3D12DescriptorHeap* cbv_srv_heap,
+ D3D12_CPU_DESCRIPTOR_HANDLE font_srv_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE font_srv_gpu_desc_handle)
+{
+ // Setup backend capabilities flags
+ ImGuiIO& io = ImGui::GetIO();
+ io.BackendRendererName = "imgui_impl_dx12";
+ io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
+
+ g_pd3dDevice = device;
+ g_RTVFormat = rtv_format;
+ g_hFontSrvCpuDescHandle = font_srv_cpu_desc_handle;
+ g_hFontSrvGpuDescHandle = font_srv_gpu_desc_handle;
+ g_pFrameResources = new FrameResources[num_frames_in_flight];
+ g_numFramesInFlight = num_frames_in_flight;
+ g_frameIndex = UINT_MAX;
+ IM_UNUSED(cbv_srv_heap); // Unused in master branch (will be used by multi-viewports)
+
+ // Create buffers with a default size (they will later be grown as needed)
+ for (int i = 0; i < num_frames_in_flight; i++)
+ {
+ FrameResources* fr = &g_pFrameResources[i];
+ fr->IndexBuffer = NULL;
+ fr->VertexBuffer = NULL;
+ fr->IndexBufferSize = 10000;
+ fr->VertexBufferSize = 5000;
+ }
+
+ return true;
+}
+
+void ImGui_ImplDX12_Shutdown()
+{
+ ImGui_ImplDX12_InvalidateDeviceObjects();
+ delete[] g_pFrameResources;
+ g_pFrameResources = NULL;
+ g_pd3dDevice = NULL;
+ g_hFontSrvCpuDescHandle.ptr = 0;
+ g_hFontSrvGpuDescHandle.ptr = 0;
+ g_numFramesInFlight = 0;
+ g_frameIndex = UINT_MAX;
+}
+
+void ImGui_ImplDX12_NewFrame()
+{
+ if (!g_pPipelineState)
+ ImGui_ImplDX12_CreateDeviceObjects();
+}
diff --git a/3rdparty/imgui/backend/imgui_impl_dx12.h b/3rdparty/imgui/backend/imgui_impl_dx12.h
new file mode 100644
index 0000000..7051962
--- /dev/null
+++ b/3rdparty/imgui/backend/imgui_impl_dx12.h
@@ -0,0 +1,48 @@
+// dear imgui: Renderer Backend for DirectX12
+// This needs to be used along with a Platform Backend (e.g. Win32)
+
+// Implemented features:
+// [X] Renderer: User texture binding. Use 'D3D12_GPU_DESCRIPTOR_HANDLE' as ImTextureID. Read the FAQ about ImTextureID!
+// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
+
+// Important: to compile on 32-bit systems, this backend requires code to be compiled with '#define ImTextureID ImU64'.
+// This is because we need ImTextureID to carry a 64-bit value and by default ImTextureID is defined as void*.
+// This define is set in the example .vcxproj file and need to be replicated in your app or by adding it to your imconfig.h file.
+
+// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
+// Read online: https://github.com/ocornut/imgui/tree/master/docs
+
+#pragma once
+#include "imgui.h" // IMGUI_IMPL_API
+
+#ifdef _MSC_VER
+#pragma warning (push)
+#pragma warning (disable: 4471) // a forward declaration of an unscoped enumeration must have an underlying type
+#endif
+
+enum DXGI_FORMAT;
+struct ID3D12Device;
+struct ID3D12DescriptorHeap;
+struct ID3D12GraphicsCommandList;
+struct D3D12_CPU_DESCRIPTOR_HANDLE;
+struct D3D12_GPU_DESCRIPTOR_HANDLE;
+
+// cmd_list is the command list that the implementation will use to render imgui draw lists.
+// Before calling the render function, caller must prepare cmd_list by resetting it and setting the appropriate
+// render target and descriptor heap that contains font_srv_cpu_desc_handle/font_srv_gpu_desc_handle.
+// font_srv_cpu_desc_handle and font_srv_gpu_desc_handle are handles to a single SRV descriptor to use for the internal font texture.
+IMGUI_IMPL_API bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, ID3D12DescriptorHeap* cbv_srv_heap,
+ D3D12_CPU_DESCRIPTOR_HANDLE font_srv_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE font_srv_gpu_desc_handle);
+IMGUI_IMPL_API void ImGui_ImplDX12_Shutdown();
+IMGUI_IMPL_API void ImGui_ImplDX12_NewFrame();
+IMGUI_IMPL_API void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandList* graphics_command_list);
+
+// Use if you want to reset your rendering device without losing Dear ImGui state.
+IMGUI_IMPL_API void ImGui_ImplDX12_InvalidateDeviceObjects();
+IMGUI_IMPL_API bool ImGui_ImplDX12_CreateDeviceObjects();
+
+#ifdef _MSC_VER
+#pragma warning (pop)
+#endif
+
diff --git a/3rdparty/imgui/backend/imgui_impl_glfw.cpp b/3rdparty/imgui/backend/imgui_impl_glfw.cpp
new file mode 100644
index 0000000..cd0f51d
--- /dev/null
+++ b/3rdparty/imgui/backend/imgui_impl_glfw.cpp
@@ -0,0 +1,374 @@
+// dear imgui: Platform Backend for GLFW
+// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan, WebGPU..)
+// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
+// (Requires: GLFW 3.1+)
+
+// Implemented features:
+// [X] Platform: Clipboard support.
+// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
+// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+).
+// [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE).
+
+// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
+// Read online: https://github.com/ocornut/imgui/tree/master/docs
+
+// CHANGELOG
+// (minor and older changes stripped away, please see git history for details)
+// 2020-01-17: Inputs: Disable error callback while assigning mouse cursors because some X11 setup don't have them and it generates errors.
+// 2019-12-05: Inputs: Added support for new mouse cursors added in GLFW 3.4+ (resizing cursors, not allowed cursor).
+// 2019-10-18: Misc: Previously installed user callbacks are now restored on shutdown.
+// 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
+// 2019-05-11: Inputs: Don't filter value from character callback before calling AddInputCharacter().
+// 2019-03-12: Misc: Preserve DisplayFramebufferScale when main window is minimized.
+// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
+// 2018-11-07: Inputs: When installing our GLFW callbacks, we save user's previously installed ones - if any - and chain call them.
+// 2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls.
+// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
+// 2018-06-08: Misc: Extracted imgui_impl_glfw.cpp/.h away from the old combined GLFW+OpenGL/Vulkan examples.
+// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag.
+// 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value, passed to glfwSetCursor()).
+// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
+// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
+// 2018-01-25: Inputs: Added gamepad support if ImGuiConfigFlags_NavEnableGamepad is set.
+// 2018-01-25: Inputs: Honoring the io.WantSetMousePos by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set).
+// 2018-01-20: Inputs: Added Horizontal Mouse Wheel support.
+// 2018-01-18: Inputs: Added mapping for ImGuiKey_Insert.
+// 2017-08-25: Inputs: MousePos set to -FLT_MAX,-FLT_MAX when mouse is unavailable/missing (instead of -1,-1).
+// 2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers.
+
+#include "imgui.h"
+#include "imgui_impl_glfw.h"
+
+// GLFW
+#include <GLFW/glfw3.h>
+#ifdef _WIN32
+#undef APIENTRY
+#define GLFW_EXPOSE_NATIVE_WIN32
+#include <GLFW/glfw3native.h> // for glfwGetWin32Window
+#endif
+#define GLFW_HAS_WINDOW_TOPMOST (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ GLFW_FLOATING
+#define GLFW_HAS_WINDOW_HOVERED (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ GLFW_HOVERED
+#define GLFW_HAS_WINDOW_ALPHA (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwSetWindowOpacity
+#define GLFW_HAS_PER_MONITOR_DPI (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwGetMonitorContentScale
+#define GLFW_HAS_VULKAN (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ glfwCreateWindowSurface
+#ifdef GLFW_RESIZE_NESW_CURSOR // let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2019-11-29 (cursors defines) // FIXME: Remove when GLFW 3.4 is released?
+#define GLFW_HAS_NEW_CURSORS (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3400) // 3.4+ GLFW_RESIZE_ALL_CURSOR, GLFW_RESIZE_NESW_CURSOR, GLFW_RESIZE_NWSE_CURSOR, GLFW_NOT_ALLOWED_CURSOR
+#else
+#define GLFW_HAS_NEW_CURSORS (0)
+#endif
+
+// Data
+enum GlfwClientApi
+{
+ GlfwClientApi_Unknown,
+ GlfwClientApi_OpenGL,
+ GlfwClientApi_Vulkan
+};
+static GLFWwindow* g_Window = NULL; // Main window
+static GlfwClientApi g_ClientApi = GlfwClientApi_Unknown;
+static double g_Time = 0.0;
+static bool g_MouseJustPressed[ImGuiMouseButton_COUNT] = {};
+static GLFWcursor* g_MouseCursors[ImGuiMouseCursor_COUNT] = {};
+static bool g_InstalledCallbacks = false;
+
+// Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
+static GLFWmousebuttonfun g_PrevUserCallbackMousebutton = NULL;
+static GLFWscrollfun g_PrevUserCallbackScroll = NULL;
+static GLFWkeyfun g_PrevUserCallbackKey = NULL;
+static GLFWcharfun g_PrevUserCallbackChar = NULL;
+
+static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data)
+{
+ return glfwGetClipboardString((GLFWwindow*)user_data);
+}
+
+static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text)
+{
+ glfwSetClipboardString((GLFWwindow*)user_data, text);
+}
+
+void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
+{
+ if (g_PrevUserCallbackMousebutton != NULL)
+ g_PrevUserCallbackMousebutton(window, button, action, mods);
+
+ if (action == GLFW_PRESS && button >= 0 && button < IM_ARRAYSIZE(g_MouseJustPressed))
+ g_MouseJustPressed[button] = true;
+}
+
+void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset)
+{
+ if (g_PrevUserCallbackScroll != NULL)
+ g_PrevUserCallbackScroll(window, xoffset, yoffset);
+
+ ImGuiIO& io = ImGui::GetIO();
+ io.MouseWheelH += (float)xoffset;
+ io.MouseWheel += (float)yoffset;
+}
+
+void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
+{
+ if (g_PrevUserCallbackKey != NULL)
+ g_PrevUserCallbackKey(window, key, scancode, action, mods);
+
+ ImGuiIO& io = ImGui::GetIO();
+ if (action == GLFW_PRESS)
+ io.KeysDown[key] = true;
+ if (action == GLFW_RELEASE)
+ io.KeysDown[key] = false;
+
+ // Modifiers are not reliable across systems
+ io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL];
+ io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT];
+ io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT];
+#ifdef _WIN32
+ io.KeySuper = false;
+#else
+ io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER];
+#endif
+}
+
+void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c)
+{
+ if (g_PrevUserCallbackChar != NULL)
+ g_PrevUserCallbackChar(window, c);
+
+ ImGuiIO& io = ImGui::GetIO();
+ io.AddInputCharacter(c);
+}
+
+static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api)
+{
+ g_Window = window;
+ g_Time = 0.0;
+
+ // Setup backend capabilities flags
+ ImGuiIO& io = ImGui::GetIO();
+ io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
+ io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
+ io.BackendPlatformName = "imgui_impl_glfw";
+
+ // Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array.
+ io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB;
+ io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT;
+ io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT;
+ io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP;
+ io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN;
+ io.KeyMap[ImGuiKey_PageUp] = GLFW_KEY_PAGE_UP;
+ io.KeyMap[ImGuiKey_PageDown] = GLFW_KEY_PAGE_DOWN;
+ io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME;
+ io.KeyMap[ImGuiKey_End] = GLFW_KEY_END;
+ io.KeyMap[ImGuiKey_Insert] = GLFW_KEY_INSERT;
+ io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE;
+ io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE;
+ io.KeyMap[ImGuiKey_Space] = GLFW_KEY_SPACE;
+ io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER;
+ io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE;
+ io.KeyMap[ImGuiKey_KeyPadEnter] = GLFW_KEY_KP_ENTER;
+ io.KeyMap[ImGuiKey_A] = GLFW_KEY_A;
+ io.KeyMap[ImGuiKey_C] = GLFW_KEY_C;
+ io.KeyMap[ImGuiKey_V] = GLFW_KEY_V;
+ io.KeyMap[ImGuiKey_X] = GLFW_KEY_X;
+ io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y;
+ io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z;
+
+ io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText;
+ io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText;
+ io.ClipboardUserData = g_Window;
+#if defined(_WIN32)
+ io.ImeWindowHandle = (void*)glfwGetWin32Window(g_Window);
+#endif
+
+ // Create mouse cursors
+ // (By design, on X11 cursors are user configurable and some cursors may be missing. When a cursor doesn't exist,
+ // GLFW will emit an error which will often be printed by the app, so we temporarily disable error reporting.
+ // Missing cursors will return NULL and our _UpdateMouseCursor() function will use the Arrow cursor instead.)
+ GLFWerrorfun prev_error_callback = glfwSetErrorCallback(NULL);
+ g_MouseCursors[ImGuiMouseCursor_Arrow] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
+ g_MouseCursors[ImGuiMouseCursor_TextInput] = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR);
+ g_MouseCursors[ImGuiMouseCursor_ResizeNS] = glfwCreateStandardCursor(GLFW_VRESIZE_CURSOR);
+ g_MouseCursors[ImGuiMouseCursor_ResizeEW] = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR);
+ g_MouseCursors[ImGuiMouseCursor_Hand] = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
+#if GLFW_HAS_NEW_CURSORS
+ g_MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_RESIZE_ALL_CURSOR);
+ g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_RESIZE_NESW_CURSOR);
+ g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_RESIZE_NWSE_CURSOR);
+ g_MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_NOT_ALLOWED_CURSOR);
+#else
+ g_MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
+ g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
+ g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
+ g_MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
+#endif
+ glfwSetErrorCallback(prev_error_callback);
+
+ // Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
+ g_PrevUserCallbackMousebutton = NULL;
+ g_PrevUserCallbackScroll = NULL;
+ g_PrevUserCallbackKey = NULL;
+ g_PrevUserCallbackChar = NULL;
+ if (install_callbacks)
+ {
+ g_InstalledCallbacks = true;
+ g_PrevUserCallbackMousebutton = glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback);
+ g_PrevUserCallbackScroll = glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback);
+ g_PrevUserCallbackKey = glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback);
+ g_PrevUserCallbackChar = glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback);
+ }
+
+ g_ClientApi = client_api;
+ return true;
+}
+
+bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks)
+{
+ return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_OpenGL);
+}
+
+bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks)
+{
+ return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Vulkan);
+}
+
+bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool install_callbacks)
+{
+ return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Unknown);
+}
+
+void ImGui_ImplGlfw_Shutdown()
+{
+ if (g_InstalledCallbacks)
+ {
+ glfwSetMouseButtonCallback(g_Window, g_PrevUserCallbackMousebutton);
+ glfwSetScrollCallback(g_Window, g_PrevUserCallbackScroll);
+ glfwSetKeyCallback(g_Window, g_PrevUserCallbackKey);
+ glfwSetCharCallback(g_Window, g_PrevUserCallbackChar);
+ g_InstalledCallbacks = false;
+ }
+
+ for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++)
+ {
+ glfwDestroyCursor(g_MouseCursors[cursor_n]);
+ g_MouseCursors[cursor_n] = NULL;
+ }
+ g_ClientApi = GlfwClientApi_Unknown;
+}
+
+static void ImGui_ImplGlfw_UpdateMousePosAndButtons()
+{
+ // Update buttons
+ ImGuiIO& io = ImGui::GetIO();
+ for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++)
+ {
+ // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
+ io.MouseDown[i] = g_MouseJustPressed[i] || glfwGetMouseButton(g_Window, i) != 0;
+ g_MouseJustPressed[i] = false;
+ }
+
+ // Update mouse position
+ const ImVec2 mouse_pos_backup = io.MousePos;
+ io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
+#ifdef __EMSCRIPTEN__
+ const bool focused = true; // Emscripten
+#else
+ const bool focused = glfwGetWindowAttrib(g_Window, GLFW_FOCUSED) != 0;
+#endif
+ if (focused)
+ {
+ if (io.WantSetMousePos)
+ {
+ glfwSetCursorPos(g_Window, (double)mouse_pos_backup.x, (double)mouse_pos_backup.y);
+ }
+ else
+ {
+ double mouse_x, mouse_y;
+ glfwGetCursorPos(g_Window, &mouse_x, &mouse_y);
+ io.MousePos = ImVec2((float)mouse_x, (float)mouse_y);
+ }
+ }
+}
+
+static void ImGui_ImplGlfw_UpdateMouseCursor()
+{
+ ImGuiIO& io = ImGui::GetIO();
+ if ((io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) || glfwGetInputMode(g_Window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED)
+ return;
+
+ ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
+ if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor)
+ {
+ // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
+ glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
+ }
+ else
+ {
+ // Show OS mouse cursor
+ // FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here.
+ glfwSetCursor(g_Window, g_MouseCursors[imgui_cursor] ? g_MouseCursors[imgui_cursor] : g_MouseCursors[ImGuiMouseCursor_Arrow]);
+ glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
+ }
+}
+
+static void ImGui_ImplGlfw_UpdateGamepads()
+{
+ ImGuiIO& io = ImGui::GetIO();
+ memset(io.NavInputs, 0, sizeof(io.NavInputs));
+ if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
+ return;
+
+ // Update gamepad inputs
+ #define MAP_BUTTON(NAV_NO, BUTTON_NO) { if (buttons_count > BUTTON_NO && buttons[BUTTON_NO] == GLFW_PRESS) io.NavInputs[NAV_NO] = 1.0f; }
+ #define MAP_ANALOG(NAV_NO, AXIS_NO, V0, V1) { float v = (axes_count > AXIS_NO) ? axes[AXIS_NO] : V0; v = (v - V0) / (V1 - V0); if (v > 1.0f) v = 1.0f; if (io.NavInputs[NAV_NO] < v) io.NavInputs[NAV_NO] = v; }
+ int axes_count = 0, buttons_count = 0;
+ const float* axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1, &axes_count);
+ const unsigned char* buttons = glfwGetJoystickButtons(GLFW_JOYSTICK_1, &buttons_count);
+ MAP_BUTTON(ImGuiNavInput_Activate, 0); // Cross / A
+ MAP_BUTTON(ImGuiNavInput_Cancel, 1); // Circle / B
+ MAP_BUTTON(ImGuiNavInput_Menu, 2); // Square / X
+ MAP_BUTTON(ImGuiNavInput_Input, 3); // Triangle / Y
+ MAP_BUTTON(ImGuiNavInput_DpadLeft, 13); // D-Pad Left
+ MAP_BUTTON(ImGuiNavInput_DpadRight, 11); // D-Pad Right
+ MAP_BUTTON(ImGuiNavInput_DpadUp, 10); // D-Pad Up
+ MAP_BUTTON(ImGuiNavInput_DpadDown, 12); // D-Pad Down
+ MAP_BUTTON(ImGuiNavInput_FocusPrev, 4); // L1 / LB
+ MAP_BUTTON(ImGuiNavInput_FocusNext, 5); // R1 / RB
+ MAP_BUTTON(ImGuiNavInput_TweakSlow, 4); // L1 / LB
+ MAP_BUTTON(ImGuiNavInput_TweakFast, 5); // R1 / RB
+ MAP_ANALOG(ImGuiNavInput_LStickLeft, 0, -0.3f, -0.9f);
+ MAP_ANALOG(ImGuiNavInput_LStickRight,0, +0.3f, +0.9f);
+ MAP_ANALOG(ImGuiNavInput_LStickUp, 1, +0.3f, +0.9f);
+ MAP_ANALOG(ImGuiNavInput_LStickDown, 1, -0.3f, -0.9f);
+ #undef MAP_BUTTON
+ #undef MAP_ANALOG
+ if (axes_count > 0 && buttons_count > 0)
+ io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
+ else
+ io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
+}
+
+void ImGui_ImplGlfw_NewFrame()
+{
+ ImGuiIO& io = ImGui::GetIO();
+ IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer backend. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame().");
+
+ // Setup display size (every frame to accommodate for window resizing)
+ int w, h;
+ int display_w, display_h;
+ glfwGetWindowSize(g_Window, &w, &h);
+ glfwGetFramebufferSize(g_Window, &display_w, &display_h);
+ io.DisplaySize = ImVec2((float)w, (float)h);
+ if (w > 0 && h > 0)
+ io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h);
+
+ // Setup time step
+ double current_time = glfwGetTime();
+ io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f / 60.0f);
+ g_Time = current_time;
+
+ ImGui_ImplGlfw_UpdateMousePosAndButtons();
+ ImGui_ImplGlfw_UpdateMouseCursor();
+
+ // Update game controllers (if enabled and available)
+ ImGui_ImplGlfw_UpdateGamepads();
+}
diff --git a/3rdparty/imgui/backend/imgui_impl_glfw.h b/3rdparty/imgui/backend/imgui_impl_glfw.h
new file mode 100644
index 0000000..018f1a1
--- /dev/null
+++ b/3rdparty/imgui/backend/imgui_impl_glfw.h
@@ -0,0 +1,36 @@
+// dear imgui: Platform Backend for GLFW
+// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan, WebGPU..)
+// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
+
+// Implemented features:
+// [X] Platform: Clipboard support.
+// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
+// [x] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: 3 cursors types are missing from GLFW.
+// [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE).
+
+// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
+// Read online: https://github.com/ocornut/imgui/tree/master/docs
+
+// About GLSL version:
+// The 'glsl_version' initialization parameter defaults to "#version 150" if NULL.
+// Only override if your GL version doesn't handle this GLSL version. Keep NULL if unsure!
+
+#pragma once
+#include "imgui.h" // IMGUI_IMPL_API
+
+struct GLFWwindow;
+
+IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks);
+IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks);
+IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool install_callbacks);
+IMGUI_IMPL_API void ImGui_ImplGlfw_Shutdown();
+IMGUI_IMPL_API void ImGui_ImplGlfw_NewFrame();
+
+// GLFW callbacks
+// - When calling Init with 'install_callbacks=true': GLFW callbacks will be installed for you. They will call user's previously installed callbacks, if any.
+// - When calling Init with 'install_callbacks=false': GLFW callbacks won't be installed. You will need to call those function yourself from your own GLFW callbacks.
+IMGUI_IMPL_API void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods);
+IMGUI_IMPL_API void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset);
+IMGUI_IMPL_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
+IMGUI_IMPL_API void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c);
diff --git a/3rdparty/imgui/backend/imgui_impl_metal.h b/3rdparty/imgui/backend/imgui_impl_metal.h
new file mode 100644
index 0000000..1db7d87
--- /dev/null
+++ b/3rdparty/imgui/backend/imgui_impl_metal.h
@@ -0,0 +1,28 @@
+// dear imgui: Renderer Backend for Metal
+// This needs to be used along with a Platform Backend (e.g. OSX)
+
+// Implemented features:
+// [X] Renderer: User texture binding. Use 'MTLTexture' as ImTextureID. Read the FAQ about ImTextureID!
+// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
+
+// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
+// Read online: https://github.com/ocornut/imgui/tree/master/docs
+
+#include "imgui.h" // IMGUI_IMPL_API
+
+@class MTLRenderPassDescriptor;
+@protocol MTLDevice, MTLCommandBuffer, MTLRenderCommandEncoder;
+
+IMGUI_IMPL_API bool ImGui_ImplMetal_Init(id<MTLDevice> device);
+IMGUI_IMPL_API void ImGui_ImplMetal_Shutdown();
+IMGUI_IMPL_API void ImGui_ImplMetal_NewFrame(MTLRenderPassDescriptor* renderPassDescriptor);
+IMGUI_IMPL_API void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data,
+ id<MTLCommandBuffer> commandBuffer,
+ id<MTLRenderCommandEncoder> commandEncoder);
+
+// Called by Init/NewFrame/Shutdown
+IMGUI_IMPL_API bool ImGui_ImplMetal_CreateFontsTexture(id<MTLDevice> device);
+IMGUI_IMPL_API void ImGui_ImplMetal_DestroyFontsTexture();
+IMGUI_IMPL_API bool ImGui_ImplMetal_CreateDeviceObjects(id<MTLDevice> device);
+IMGUI_IMPL_API void ImGui_ImplMetal_DestroyDeviceObjects();
diff --git a/3rdparty/imgui/backend/imgui_impl_metal.mm b/3rdparty/imgui/backend/imgui_impl_metal.mm
new file mode 100644
index 0000000..cb57c12
--- /dev/null
+++ b/3rdparty/imgui/backend/imgui_impl_metal.mm
@@ -0,0 +1,552 @@
+// dear imgui: Renderer Backend for Metal
+// This needs to be used along with a Platform Backend (e.g. OSX)
+
+// Implemented features:
+// [X] Renderer: User texture binding. Use 'MTLTexture' as ImTextureID. Read the FAQ about ImTextureID!
+// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
+
+// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
+// Read online: https://github.com/ocornut/imgui/tree/master/docs
+
+// CHANGELOG
+// (minor and older changes stripped away, please see git history for details)
+// 2021-02-18: Metal: Change blending equation to preserve alpha in output buffer.
+// 2021-01-25: Metal: Fixed texture storage mode when building on Mac Catalyst.
+// 2019-05-29: Metal: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
+// 2019-04-30: Metal: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
+// 2019-02-11: Metal: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display.
+// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
+// 2018-07-05: Metal: Added new Metal backend implementation.
+
+#include "imgui.h"
+#include "imgui_impl_metal.h"
+
+#import <Metal/Metal.h>
+// #import <QuartzCore/CAMetalLayer.h> // Not supported in XCode 9.2. Maybe a macro to detect the SDK version can be used (something like #if MACOS_SDK >= 10.13 ...)
+#import <simd/simd.h>
+
+#pragma mark - Support classes
+
+// A wrapper around a MTLBuffer object that knows the last time it was reused
+@interface MetalBuffer : NSObject
+@property (nonatomic, strong) id<MTLBuffer> buffer;
+@property (nonatomic, assign) NSTimeInterval lastReuseTime;
+- (instancetype)initWithBuffer:(id<MTLBuffer>)buffer;
+@end
+
+// An object that encapsulates the data necessary to uniquely identify a
+// render pipeline state. These are used as cache keys.
+@interface FramebufferDescriptor : NSObject<NSCopying>
+@property (nonatomic, assign) unsigned long sampleCount;
+@property (nonatomic, assign) MTLPixelFormat colorPixelFormat;
+@property (nonatomic, assign) MTLPixelFormat depthPixelFormat;
+@property (nonatomic, assign) MTLPixelFormat stencilPixelFormat;
+- (instancetype)initWithRenderPassDescriptor:(MTLRenderPassDescriptor *)renderPassDescriptor;
+@end
+
+// A singleton that stores long-lived objects that are needed by the Metal
+// renderer backend. Stores the render pipeline state cache and the default
+// font texture, and manages the reusable buffer cache.
+@interface MetalContext : NSObject
+@property (nonatomic, strong) id<MTLDepthStencilState> depthStencilState;
+@property (nonatomic, strong) FramebufferDescriptor *framebufferDescriptor; // framebuffer descriptor for current frame; transient
+@property (nonatomic, strong) NSMutableDictionary *renderPipelineStateCache; // pipeline cache; keyed on framebuffer descriptors
+@property (nonatomic, strong, nullable) id<MTLTexture> fontTexture;
+@property (nonatomic, strong) NSMutableArray<MetalBuffer *> *bufferCache;
+@property (nonatomic, assign) NSTimeInterval lastBufferCachePurge;
+- (void)makeDeviceObjectsWithDevice:(id<MTLDevice>)device;
+- (void)makeFontTextureWithDevice:(id<MTLDevice>)device;
+- (MetalBuffer *)dequeueReusableBufferOfLength:(NSUInteger)length device:(id<MTLDevice>)device;
+- (void)enqueueReusableBuffer:(MetalBuffer *)buffer;
+- (id<MTLRenderPipelineState>)renderPipelineStateForFrameAndDevice:(id<MTLDevice>)device;
+- (void)emptyRenderPipelineStateCache;
+- (void)setupRenderState:(ImDrawData *)drawData
+ commandBuffer:(id<MTLCommandBuffer>)commandBuffer
+ commandEncoder:(id<MTLRenderCommandEncoder>)commandEncoder
+ renderPipelineState:(id<MTLRenderPipelineState>)renderPipelineState
+ vertexBuffer:(MetalBuffer *)vertexBuffer
+ vertexBufferOffset:(size_t)vertexBufferOffset;
+- (void)renderDrawData:(ImDrawData *)drawData
+ commandBuffer:(id<MTLCommandBuffer>)commandBuffer
+ commandEncoder:(id<MTLRenderCommandEncoder>)commandEncoder;
+@end
+
+static MetalContext *g_sharedMetalContext = nil;
+
+#pragma mark - ImGui API implementation
+
+bool ImGui_ImplMetal_Init(id<MTLDevice> device)
+{
+ ImGuiIO& io = ImGui::GetIO();
+ io.BackendRendererName = "imgui_impl_metal";
+ io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
+
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ g_sharedMetalContext = [[MetalContext alloc] init];
+ });
+
+ ImGui_ImplMetal_CreateDeviceObjects(device);
+
+ return true;
+}
+
+void ImGui_ImplMetal_Shutdown()
+{
+ ImGui_ImplMetal_DestroyDeviceObjects();
+}
+
+void ImGui_ImplMetal_NewFrame(MTLRenderPassDescriptor *renderPassDescriptor)
+{
+ IM_ASSERT(g_sharedMetalContext != nil && "No Metal context. Did you call ImGui_ImplMetal_Init() ?");
+
+ g_sharedMetalContext.framebufferDescriptor = [[FramebufferDescriptor alloc] initWithRenderPassDescriptor:renderPassDescriptor];
+}
+
+// Metal Render function.
+void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data, id<MTLCommandBuffer> commandBuffer, id<MTLRenderCommandEncoder> commandEncoder)
+{
+ [g_sharedMetalContext renderDrawData:draw_data commandBuffer:commandBuffer commandEncoder:commandEncoder];
+}
+
+bool ImGui_ImplMetal_CreateFontsTexture(id<MTLDevice> device)
+{
+ [g_sharedMetalContext makeFontTextureWithDevice:device];
+
+ ImGuiIO& io = ImGui::GetIO();
+ io.Fonts->SetTexID((__bridge void *)g_sharedMetalContext.fontTexture); // ImTextureID == void*
+
+ return (g_sharedMetalContext.fontTexture != nil);
+}
+
+void ImGui_ImplMetal_DestroyFontsTexture()
+{
+ ImGuiIO& io = ImGui::GetIO();
+ g_sharedMetalContext.fontTexture = nil;
+ io.Fonts->SetTexID(nullptr);
+}
+
+bool ImGui_ImplMetal_CreateDeviceObjects(id<MTLDevice> device)
+{
+ [g_sharedMetalContext makeDeviceObjectsWithDevice:device];
+
+ ImGui_ImplMetal_CreateFontsTexture(device);
+
+ return true;
+}
+
+void ImGui_ImplMetal_DestroyDeviceObjects()
+{
+ ImGui_ImplMetal_DestroyFontsTexture();
+ [g_sharedMetalContext emptyRenderPipelineStateCache];
+}
+
+#pragma mark - MetalBuffer implementation
+
+@implementation MetalBuffer
+- (instancetype)initWithBuffer:(id<MTLBuffer>)buffer
+{
+ if ((self = [super init]))
+ {
+ _buffer = buffer;
+ _lastReuseTime = [NSDate date].timeIntervalSince1970;
+ }
+ return self;
+}
+@end
+
+#pragma mark - FramebufferDescriptor implementation
+
+@implementation FramebufferDescriptor
+- (instancetype)initWithRenderPassDescriptor:(MTLRenderPassDescriptor *)renderPassDescriptor
+{
+ if ((self = [super init]))
+ {
+ _sampleCount = renderPassDescriptor.colorAttachments[0].texture.sampleCount;
+ _colorPixelFormat = renderPassDescriptor.colorAttachments[0].texture.pixelFormat;
+ _depthPixelFormat = renderPassDescriptor.depthAttachment.texture.pixelFormat;
+ _stencilPixelFormat = renderPassDescriptor.stencilAttachment.texture.pixelFormat;
+ }
+ return self;
+}
+
+- (nonnull id)copyWithZone:(nullable NSZone *)zone
+{
+ FramebufferDescriptor *copy = [[FramebufferDescriptor allocWithZone:zone] init];
+ copy.sampleCount = self.sampleCount;
+ copy.colorPixelFormat = self.colorPixelFormat;
+ copy.depthPixelFormat = self.depthPixelFormat;
+ copy.stencilPixelFormat = self.stencilPixelFormat;
+ return copy;
+}
+
+- (NSUInteger)hash
+{
+ NSUInteger sc = _sampleCount & 0x3;
+ NSUInteger cf = _colorPixelFormat & 0x3FF;
+ NSUInteger df = _depthPixelFormat & 0x3FF;
+ NSUInteger sf = _stencilPixelFormat & 0x3FF;
+ NSUInteger hash = (sf << 22) | (df << 12) | (cf << 2) | sc;
+ return hash;
+}
+
+- (BOOL)isEqual:(id)object
+{
+ FramebufferDescriptor *other = object;
+ if (![other isKindOfClass:[FramebufferDescriptor class]])
+ return NO;
+ return other.sampleCount == self.sampleCount &&
+ other.colorPixelFormat == self.colorPixelFormat &&
+ other.depthPixelFormat == self.depthPixelFormat &&
+ other.stencilPixelFormat == self.stencilPixelFormat;
+}
+
+@end
+
+#pragma mark - MetalContext implementation
+
+@implementation MetalContext
+- (instancetype)init {
+ if ((self = [super init]))
+ {
+ _renderPipelineStateCache = [NSMutableDictionary dictionary];
+ _bufferCache = [NSMutableArray array];
+ _lastBufferCachePurge = [NSDate date].timeIntervalSince1970;
+ }
+ return self;
+}
+
+- (void)makeDeviceObjectsWithDevice:(id<MTLDevice>)device
+{
+ MTLDepthStencilDescriptor *depthStencilDescriptor = [[MTLDepthStencilDescriptor alloc] init];
+ depthStencilDescriptor.depthWriteEnabled = NO;
+ depthStencilDescriptor.depthCompareFunction = MTLCompareFunctionAlways;
+ self.depthStencilState = [device newDepthStencilStateWithDescriptor:depthStencilDescriptor];
+}
+
+// We are retrieving and uploading the font atlas as a 4-channels RGBA texture here.
+// In theory we could call GetTexDataAsAlpha8() and upload a 1-channel texture to save on memory access bandwidth.
+// However, using a shader designed for 1-channel texture would make it less obvious to use the ImTextureID facility to render users own textures.
+// You can make that change in your implementation.
+- (void)makeFontTextureWithDevice:(id<MTLDevice>)device
+{
+ ImGuiIO &io = ImGui::GetIO();
+ unsigned char* pixels;
+ int width, height;
+ io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
+ MTLTextureDescriptor *textureDescriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm
+ width:(NSUInteger)width
+ height:(NSUInteger)height
+ mipmapped:NO];
+ textureDescriptor.usage = MTLTextureUsageShaderRead;
+#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
+ textureDescriptor.storageMode = MTLStorageModeManaged;
+#else
+ textureDescriptor.storageMode = MTLStorageModeShared;
+#endif
+ id <MTLTexture> texture = [device newTextureWithDescriptor:textureDescriptor];
+ [texture replaceRegion:MTLRegionMake2D(0, 0, (NSUInteger)width, (NSUInteger)height) mipmapLevel:0 withBytes:pixels bytesPerRow:(NSUInteger)width * 4];
+ self.fontTexture = texture;
+}
+
+- (MetalBuffer *)dequeueReusableBufferOfLength:(NSUInteger)length device:(id<MTLDevice>)device
+{
+ NSTimeInterval now = [NSDate date].timeIntervalSince1970;
+
+ // Purge old buffers that haven't been useful for a while
+ if (now - self.lastBufferCachePurge > 1.0)
+ {
+ NSMutableArray *survivors = [NSMutableArray array];
+ for (MetalBuffer *candidate in self.bufferCache)
+ {
+ if (candidate.lastReuseTime > self.lastBufferCachePurge)
+ {
+ [survivors addObject:candidate];
+ }
+ }
+ self.bufferCache = [survivors mutableCopy];
+ self.lastBufferCachePurge = now;
+ }
+
+ // See if we have a buffer we can reuse
+ MetalBuffer *bestCandidate = nil;
+ for (MetalBuffer *candidate in self.bufferCache)
+ if (candidate.buffer.length >= length && (bestCandidate == nil || bestCandidate.lastReuseTime > candidate.lastReuseTime))
+ bestCandidate = candidate;
+
+ if (bestCandidate != nil)
+ {
+ [self.bufferCache removeObject:bestCandidate];
+ bestCandidate.lastReuseTime = now;
+ return bestCandidate;
+ }
+
+ // No luck; make a new buffer
+ id<MTLBuffer> backing = [device newBufferWithLength:length options:MTLResourceStorageModeShared];
+ return [[MetalBuffer alloc] initWithBuffer:backing];
+}
+
+- (void)enqueueReusableBuffer:(MetalBuffer *)buffer
+{
+ [self.bufferCache addObject:buffer];
+}
+
+- (_Nullable id<MTLRenderPipelineState>)renderPipelineStateForFrameAndDevice:(id<MTLDevice>)device
+{
+ // Try to retrieve a render pipeline state that is compatible with the framebuffer config for this frame
+ // The hit rate for this cache should be very near 100%.
+ id<MTLRenderPipelineState> renderPipelineState = self.renderPipelineStateCache[self.framebufferDescriptor];
+
+ if (renderPipelineState == nil)
+ {
+ // No luck; make a new render pipeline state
+ renderPipelineState = [self _renderPipelineStateForFramebufferDescriptor:self.framebufferDescriptor device:device];
+ // Cache render pipeline state for later reuse
+ self.renderPipelineStateCache[self.framebufferDescriptor] = renderPipelineState;
+ }
+
+ return renderPipelineState;
+}
+
+- (id<MTLRenderPipelineState>)_renderPipelineStateForFramebufferDescriptor:(FramebufferDescriptor *)descriptor device:(id<MTLDevice>)device
+{
+ NSError *error = nil;
+
+ NSString *shaderSource = @""
+ "#include <metal_stdlib>\n"
+ "using namespace metal;\n"
+ "\n"
+ "struct Uniforms {\n"
+ " float4x4 projectionMatrix;\n"
+ "};\n"
+ "\n"
+ "struct VertexIn {\n"
+ " float2 position [[attribute(0)]];\n"
+ " float2 texCoords [[attribute(1)]];\n"
+ " uchar4 color [[attribute(2)]];\n"
+ "};\n"
+ "\n"
+ "struct VertexOut {\n"
+ " float4 position [[position]];\n"
+ " float2 texCoords;\n"
+ " float4 color;\n"
+ "};\n"
+ "\n"
+ "vertex VertexOut vertex_main(VertexIn in [[stage_in]],\n"
+ " constant Uniforms &uniforms [[buffer(1)]]) {\n"
+ " VertexOut out;\n"
+ " out.position = uniforms.projectionMatrix * float4(in.position, 0, 1);\n"
+ " out.texCoords = in.texCoords;\n"
+ " out.color = float4(in.color) / float4(255.0);\n"
+ " return out;\n"
+ "}\n"
+ "\n"
+ "fragment half4 fragment_main(VertexOut in [[stage_in]],\n"
+ " texture2d<half, access::sample> texture [[texture(0)]]) {\n"
+ " constexpr sampler linearSampler(coord::normalized, min_filter::linear, mag_filter::linear, mip_filter::linear);\n"
+ " half4 texColor = texture.sample(linearSampler, in.texCoords);\n"
+ " return half4(in.color) * texColor;\n"
+ "}\n";
+
+ id<MTLLibrary> library = [device newLibraryWithSource:shaderSource options:nil error:&error];
+ if (library == nil)
+ {
+ NSLog(@"Error: failed to create Metal library: %@", error);
+ return nil;
+ }
+
+ id<MTLFunction> vertexFunction = [library newFunctionWithName:@"vertex_main"];
+ id<MTLFunction> fragmentFunction = [library newFunctionWithName:@"fragment_main"];
+
+ if (vertexFunction == nil || fragmentFunction == nil)
+ {
+ NSLog(@"Error: failed to find Metal shader functions in library: %@", error);
+ return nil;
+ }
+
+ MTLVertexDescriptor *vertexDescriptor = [MTLVertexDescriptor vertexDescriptor];
+ vertexDescriptor.attributes[0].offset = IM_OFFSETOF(ImDrawVert, pos);
+ vertexDescriptor.attributes[0].format = MTLVertexFormatFloat2; // position
+ vertexDescriptor.attributes[0].bufferIndex = 0;
+ vertexDescriptor.attributes[1].offset = IM_OFFSETOF(ImDrawVert, uv);
+ vertexDescriptor.attributes[1].format = MTLVertexFormatFloat2; // texCoords
+ vertexDescriptor.attributes[1].bufferIndex = 0;
+ vertexDescriptor.attributes[2].offset = IM_OFFSETOF(ImDrawVert, col);
+ vertexDescriptor.attributes[2].format = MTLVertexFormatUChar4; // color
+ vertexDescriptor.attributes[2].bufferIndex = 0;
+ vertexDescriptor.layouts[0].stepRate = 1;
+ vertexDescriptor.layouts[0].stepFunction = MTLVertexStepFunctionPerVertex;
+ vertexDescriptor.layouts[0].stride = sizeof(ImDrawVert);
+
+ MTLRenderPipelineDescriptor *pipelineDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
+ pipelineDescriptor.vertexFunction = vertexFunction;
+ pipelineDescriptor.fragmentFunction = fragmentFunction;
+ pipelineDescriptor.vertexDescriptor = vertexDescriptor;
+ pipelineDescriptor.sampleCount = self.framebufferDescriptor.sampleCount;
+ pipelineDescriptor.colorAttachments[0].pixelFormat = self.framebufferDescriptor.colorPixelFormat;
+ pipelineDescriptor.colorAttachments[0].blendingEnabled = YES;
+ pipelineDescriptor.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd;
+ pipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha;
+ pipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
+ pipelineDescriptor.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd;
+ pipelineDescriptor.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorOne;
+ pipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
+ pipelineDescriptor.depthAttachmentPixelFormat = self.framebufferDescriptor.depthPixelFormat;
+ pipelineDescriptor.stencilAttachmentPixelFormat = self.framebufferDescriptor.stencilPixelFormat;
+
+ id<MTLRenderPipelineState> renderPipelineState = [device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:&error];
+ if (error != nil)
+ {
+ NSLog(@"Error: failed to create Metal pipeline state: %@", error);
+ }
+
+ return renderPipelineState;
+}
+
+- (void)emptyRenderPipelineStateCache
+{
+ [self.renderPipelineStateCache removeAllObjects];
+}
+
+- (void)setupRenderState:(ImDrawData *)drawData
+ commandBuffer:(id<MTLCommandBuffer>)commandBuffer
+ commandEncoder:(id<MTLRenderCommandEncoder>)commandEncoder
+ renderPipelineState:(id<MTLRenderPipelineState>)renderPipelineState
+ vertexBuffer:(MetalBuffer *)vertexBuffer
+ vertexBufferOffset:(size_t)vertexBufferOffset
+{
+ [commandEncoder setCullMode:MTLCullModeNone];
+ [commandEncoder setDepthStencilState:g_sharedMetalContext.depthStencilState];
+
+ // Setup viewport, orthographic projection matrix
+ // Our visible imgui space lies from draw_data->DisplayPos (top left) to
+ // draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayMin is typically (0,0) for single viewport apps.
+ MTLViewport viewport =
+ {
+ .originX = 0.0,
+ .originY = 0.0,
+ .width = (double)(drawData->DisplaySize.x * drawData->FramebufferScale.x),
+ .height = (double)(drawData->DisplaySize.y * drawData->FramebufferScale.y),
+ .znear = 0.0,
+ .zfar = 1.0
+ };
+ [commandEncoder setViewport:viewport];
+
+ float L = drawData->DisplayPos.x;
+ float R = drawData->DisplayPos.x + drawData->DisplaySize.x;
+ float T = drawData->DisplayPos.y;
+ float B = drawData->DisplayPos.y + drawData->DisplaySize.y;
+ float N = (float)viewport.znear;
+ float F = (float)viewport.zfar;
+ const float ortho_projection[4][4] =
+ {
+ { 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
+ { 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
+ { 0.0f, 0.0f, 1/(F-N), 0.0f },
+ { (R+L)/(L-R), (T+B)/(B-T), N/(F-N), 1.0f },
+ };
+ [commandEncoder setVertexBytes:&ortho_projection length:sizeof(ortho_projection) atIndex:1];
+
+ [commandEncoder setRenderPipelineState:renderPipelineState];
+
+ [commandEncoder setVertexBuffer:vertexBuffer.buffer offset:0 atIndex:0];
+ [commandEncoder setVertexBufferOffset:vertexBufferOffset atIndex:0];
+}
+
+- (void)renderDrawData:(ImDrawData *)drawData
+ commandBuffer:(id<MTLCommandBuffer>)commandBuffer
+ commandEncoder:(id<MTLRenderCommandEncoder>)commandEncoder
+{
+ // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
+ int fb_width = (int)(drawData->DisplaySize.x * drawData->FramebufferScale.x);
+ int fb_height = (int)(drawData->DisplaySize.y * drawData->FramebufferScale.y);
+ if (fb_width <= 0 || fb_height <= 0 || drawData->CmdListsCount == 0)
+ return;
+
+ id<MTLRenderPipelineState> renderPipelineState = [self renderPipelineStateForFrameAndDevice:commandBuffer.device];
+
+ size_t vertexBufferLength = (size_t)drawData->TotalVtxCount * sizeof(ImDrawVert);
+ size_t indexBufferLength = (size_t)drawData->TotalIdxCount * sizeof(ImDrawIdx);
+ MetalBuffer* vertexBuffer = [self dequeueReusableBufferOfLength:vertexBufferLength device:commandBuffer.device];
+ MetalBuffer* indexBuffer = [self dequeueReusableBufferOfLength:indexBufferLength device:commandBuffer.device];
+
+ [self setupRenderState:drawData commandBuffer:commandBuffer commandEncoder:commandEncoder renderPipelineState:renderPipelineState vertexBuffer:vertexBuffer vertexBufferOffset:0];
+
+ // Will project scissor/clipping rectangles into framebuffer space
+ ImVec2 clip_off = drawData->DisplayPos; // (0,0) unless using multi-viewports
+ ImVec2 clip_scale = drawData->FramebufferScale; // (1,1) unless using retina display which are often (2,2)
+
+ // Render command lists
+ size_t vertexBufferOffset = 0;
+ size_t indexBufferOffset = 0;
+ for (int n = 0; n < drawData->CmdListsCount; n++)
+ {
+ const ImDrawList* cmd_list = drawData->CmdLists[n];
+
+ memcpy((char *)vertexBuffer.buffer.contents + vertexBufferOffset, cmd_list->VtxBuffer.Data, (size_t)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
+ memcpy((char *)indexBuffer.buffer.contents + indexBufferOffset, cmd_list->IdxBuffer.Data, (size_t)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
+
+ for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
+ {
+ const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
+ if (pcmd->UserCallback)
+ {
+ // User callback, registered via ImDrawList::AddCallback()
+ // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
+ if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
+ [self setupRenderState:drawData commandBuffer:commandBuffer commandEncoder:commandEncoder renderPipelineState:renderPipelineState vertexBuffer:vertexBuffer vertexBufferOffset:vertexBufferOffset];
+ else
+ pcmd->UserCallback(cmd_list, pcmd);
+ }
+ else
+ {
+ // Project scissor/clipping rectangles into framebuffer space
+ ImVec4 clip_rect;
+ clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x;
+ clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y;
+ clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x;
+ clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y;
+
+ if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f)
+ {
+ // Apply scissor/clipping rectangle
+ MTLScissorRect scissorRect =
+ {
+ .x = NSUInteger(clip_rect.x),
+ .y = NSUInteger(clip_rect.y),
+ .width = NSUInteger(clip_rect.z - clip_rect.x),
+ .height = NSUInteger(clip_rect.w - clip_rect.y)
+ };
+ [commandEncoder setScissorRect:scissorRect];
+
+
+ // Bind texture, Draw
+ if (pcmd->TextureId != NULL)
+ [commandEncoder setFragmentTexture:(__bridge id<MTLTexture>)(pcmd->TextureId) atIndex:0];
+
+ [commandEncoder setVertexBufferOffset:(vertexBufferOffset + pcmd->VtxOffset * sizeof(ImDrawVert)) atIndex:0];
+ [commandEncoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle
+ indexCount:pcmd->ElemCount
+ indexType:sizeof(ImDrawIdx) == 2 ? MTLIndexTypeUInt16 : MTLIndexTypeUInt32
+ indexBuffer:indexBuffer.buffer
+ indexBufferOffset:indexBufferOffset + pcmd->IdxOffset * sizeof(ImDrawIdx)];
+ }
+ }
+ }
+
+ vertexBufferOffset += (size_t)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert);
+ indexBufferOffset += (size_t)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx);
+ }
+
+ __weak id weakSelf = self;
+ [commandBuffer addCompletedHandler:^(id<MTLCommandBuffer>)
+ {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [weakSelf enqueueReusableBuffer:vertexBuffer];
+ [weakSelf enqueueReusableBuffer:indexBuffer];
+ });
+ }];
+}
+
+@end
diff --git a/3rdparty/imgui/backend/imgui_impl_opengl2.cpp b/3rdparty/imgui/backend/imgui_impl_opengl2.cpp
new file mode 100644
index 0000000..5771049
--- /dev/null
+++ b/3rdparty/imgui/backend/imgui_impl_opengl2.cpp
@@ -0,0 +1,258 @@
+// dear imgui: Renderer Backend for OpenGL2 (legacy OpenGL, fixed pipeline)
+// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
+
+// Implemented features:
+// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
+
+// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
+// Read online: https://github.com/ocornut/imgui/tree/master/docs
+
+// **DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL (SHADERS, VBO, VAO, etc.)**
+// **Prefer using the code in imgui_impl_opengl3.cpp**
+// This code is mostly provided as a reference to learn how ImGui integration works, because it is shorter to read.
+// If your code is using GL3+ context or any semi modern OpenGL calls, using this is likely to make everything more
+// complicated, will require your code to reset every single OpenGL attributes to their initial state, and might
+// confuse your GPU driver.
+// The GL2 code is unable to reset attributes or even call e.g. "glUseProgram(0)" because they don't exist in that API.
+
+// CHANGELOG
+// (minor and older changes stripped away, please see git history for details)
+// 2021-01-03: OpenGL: Backup, setup and restore GL_SHADE_MODEL state, disable GL_STENCIL_TEST and disable GL_NORMAL_ARRAY client state to increase compatibility with legacy OpenGL applications.
+// 2020-01-23: OpenGL: Backup, setup and restore GL_TEXTURE_ENV to increase compatibility with legacy OpenGL applications.
+// 2019-04-30: OpenGL: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
+// 2019-02-11: OpenGL: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display.
+// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
+// 2018-08-03: OpenGL: Disabling/restoring GL_LIGHTING and GL_COLOR_MATERIAL to increase compatibility with legacy OpenGL applications.
+// 2018-06-08: Misc: Extracted imgui_impl_opengl2.cpp/.h away from the old combined GLFW/SDL+OpenGL2 examples.
+// 2018-06-08: OpenGL: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
+// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplOpenGL2_RenderDrawData() in the .h file so you can call it yourself.
+// 2017-09-01: OpenGL: Save and restore current polygon mode.
+// 2016-09-10: OpenGL: Uploading font texture as RGBA32 to increase compatibility with users shaders (not ideal).
+// 2016-09-05: OpenGL: Fixed save and restore of current scissor rectangle.
+
+#include "imgui.h"
+#include "imgui_impl_opengl2.h"
+#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier
+#include <stddef.h> // intptr_t
+#else
+#include <stdint.h> // intptr_t
+#endif
+
+// Include OpenGL header (without an OpenGL loader) requires a bit of fiddling
+#if defined(_WIN32) && !defined(APIENTRY)
+#define APIENTRY __stdcall // It is customary to use APIENTRY for OpenGL function pointer declarations on all platforms. Additionally, the Windows OpenGL header needs APIENTRY.
+#endif
+#if defined(_WIN32) && !defined(WINGDIAPI)
+#define WINGDIAPI __declspec(dllimport) // Some Windows OpenGL headers need this
+#endif
+#if defined(__APPLE__)
+#define GL_SILENCE_DEPRECATION
+#include <OpenGL/gl.h>
+#else
+#include <GL/gl.h>
+#endif
+
+// OpenGL Data
+static GLuint g_FontTexture = 0;
+
+// Functions
+bool ImGui_ImplOpenGL2_Init()
+{
+ // Setup backend capabilities flags
+ ImGuiIO& io = ImGui::GetIO();
+ io.BackendRendererName = "imgui_impl_opengl2";
+ return true;
+}
+
+void ImGui_ImplOpenGL2_Shutdown()
+{
+ ImGui_ImplOpenGL2_DestroyDeviceObjects();
+}
+
+void ImGui_ImplOpenGL2_NewFrame()
+{
+ if (!g_FontTexture)
+ ImGui_ImplOpenGL2_CreateDeviceObjects();
+}
+
+static void ImGui_ImplOpenGL2_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height)
+{
+ // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers, polygon fill.
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ //glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); // In order to composite our output buffer we need to preserve alpha
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_STENCIL_TEST);
+ glDisable(GL_LIGHTING);
+ glDisable(GL_COLOR_MATERIAL);
+ glEnable(GL_SCISSOR_TEST);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glEnableClientState(GL_COLOR_ARRAY);
+ glDisableClientState(GL_NORMAL_ARRAY);
+ glEnable(GL_TEXTURE_2D);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ glShadeModel(GL_SMOOTH);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+ // If you are using this code with non-legacy OpenGL header/contexts (which you should not, prefer using imgui_impl_opengl3.cpp!!),
+ // you may need to backup/reset/restore other state, e.g. for current shader using the commented lines below.
+ // (DO NOT MODIFY THIS FILE! Add the code in your calling function)
+ // GLint last_program;
+ // glGetIntegerv(GL_CURRENT_PROGRAM, &last_program);
+ // glUseProgram(0);
+ // ImGui_ImplOpenGL2_RenderDrawData(...);
+ // glUseProgram(last_program)
+ // There are potentially many more states you could need to clear/setup that we can't access from default headers.
+ // e.g. glBindBuffer(GL_ARRAY_BUFFER, 0), glDisable(GL_TEXTURE_CUBE_MAP).
+
+ // Setup viewport, orthographic projection matrix
+ // 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.
+ glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height);
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ glOrtho(draw_data->DisplayPos.x, draw_data->DisplayPos.x + draw_data->DisplaySize.x, draw_data->DisplayPos.y + draw_data->DisplaySize.y, draw_data->DisplayPos.y, -1.0f, +1.0f);
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+}
+
+// OpenGL2 Render function.
+// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly.
+// This is in order to be able to run within an OpenGL engine that doesn't do so.
+void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data)
+{
+ // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
+ int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);
+ int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y);
+ if (fb_width == 0 || fb_height == 0)
+ return;
+
+ // Backup GL state
+ GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
+ GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode);
+ GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport);
+ GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box);
+ GLint last_shade_model; glGetIntegerv(GL_SHADE_MODEL, &last_shade_model);
+ GLint last_tex_env_mode; glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &last_tex_env_mode);
+ glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT);
+
+ // Setup desired GL state
+ ImGui_ImplOpenGL2_SetupRenderState(draw_data, fb_width, fb_height);
+
+ // Will project scissor/clipping rectangles into framebuffer space
+ ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
+ ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2)
+
+ // Render command lists
+ for (int n = 0; n < draw_data->CmdListsCount; n++)
+ {
+ const ImDrawList* cmd_list = draw_data->CmdLists[n];
+ const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data;
+ const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data;
+ glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, pos)));
+ glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, uv)));
+ glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, col)));
+
+ for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
+ {
+ const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
+ if (pcmd->UserCallback)
+ {
+ // User callback, registered via ImDrawList::AddCallback()
+ // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
+ if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
+ ImGui_ImplOpenGL2_SetupRenderState(draw_data, fb_width, fb_height);
+ else
+ pcmd->UserCallback(cmd_list, pcmd);
+ }
+ else
+ {
+ // Project scissor/clipping rectangles into framebuffer space
+ ImVec4 clip_rect;
+ clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x;
+ clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y;
+ clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x;
+ clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y;
+
+ if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f)
+ {
+ // Apply scissor/clipping rectangle
+ glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y));
+
+ // Bind texture, Draw
+ glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);
+ glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer);
+ }
+ }
+ idx_buffer += pcmd->ElemCount;
+ }
+ }
+
+ // Restore modified GL state
+ glDisableClientState(GL_COLOR_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glBindTexture(GL_TEXTURE_2D, (GLuint)last_texture);
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glPopAttrib();
+ glPolygonMode(GL_FRONT, (GLenum)last_polygon_mode[0]); glPolygonMode(GL_BACK, (GLenum)last_polygon_mode[1]);
+ glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]);
+ glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]);
+ glShadeModel(last_shade_model);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, last_tex_env_mode);
+}
+
+bool ImGui_ImplOpenGL2_CreateFontsTexture()
+{
+ // Build texture atlas
+ ImGuiIO& io = ImGui::GetIO();
+ unsigned char* pixels;
+ int width, height;
+ io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
+
+ // Upload texture to graphics system
+ GLint last_texture;
+ glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
+ glGenTextures(1, &g_FontTexture);
+ glBindTexture(GL_TEXTURE_2D, g_FontTexture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+
+ // Store our identifier
+ io.Fonts->SetTexID((ImTextureID)(intptr_t)g_FontTexture);
+
+ // Restore state
+ glBindTexture(GL_TEXTURE_2D, last_texture);
+
+ return true;
+}
+
+void ImGui_ImplOpenGL2_DestroyFontsTexture()
+{
+ if (g_FontTexture)
+ {
+ ImGuiIO& io = ImGui::GetIO();
+ glDeleteTextures(1, &g_FontTexture);
+ io.Fonts->SetTexID(0);
+ g_FontTexture = 0;
+ }
+}
+
+bool ImGui_ImplOpenGL2_CreateDeviceObjects()
+{
+ return ImGui_ImplOpenGL2_CreateFontsTexture();
+}
+
+void ImGui_ImplOpenGL2_DestroyDeviceObjects()
+{
+ ImGui_ImplOpenGL2_DestroyFontsTexture();
+}
diff --git a/3rdparty/imgui/backend/imgui_impl_opengl2.h b/3rdparty/imgui/backend/imgui_impl_opengl2.h
new file mode 100644
index 0000000..c0e2976
--- /dev/null
+++ b/3rdparty/imgui/backend/imgui_impl_opengl2.h
@@ -0,0 +1,31 @@
+// dear imgui: Renderer Backend for OpenGL2 (legacy OpenGL, fixed pipeline)
+// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
+
+// Implemented features:
+// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
+
+// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
+// Read online: https://github.com/ocornut/imgui/tree/master/docs
+
+// **DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL (SHADERS, VBO, VAO, etc.)**
+// **Prefer using the code in imgui_impl_opengl3.cpp**
+// This code is mostly provided as a reference to learn how ImGui integration works, because it is shorter to read.
+// If your code is using GL3+ context or any semi modern OpenGL calls, using this is likely to make everything more
+// complicated, will require your code to reset every single OpenGL attributes to their initial state, and might
+// confuse your GPU driver.
+// The GL2 code is unable to reset attributes or even call e.g. "glUseProgram(0)" because they don't exist in that API.
+
+#pragma once
+#include "imgui.h" // IMGUI_IMPL_API
+
+IMGUI_IMPL_API bool ImGui_ImplOpenGL2_Init();
+IMGUI_IMPL_API void ImGui_ImplOpenGL2_Shutdown();
+IMGUI_IMPL_API void ImGui_ImplOpenGL2_NewFrame();
+IMGUI_IMPL_API void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data);
+
+// Called by Init/NewFrame/Shutdown
+IMGUI_IMPL_API bool ImGui_ImplOpenGL2_CreateFontsTexture();
+IMGUI_IMPL_API void ImGui_ImplOpenGL2_DestroyFontsTexture();
+IMGUI_IMPL_API bool ImGui_ImplOpenGL2_CreateDeviceObjects();
+IMGUI_IMPL_API void ImGui_ImplOpenGL2_DestroyDeviceObjects();
diff --git a/3rdparty/imgui/backend/imgui_impl_opengl3.cpp b/3rdparty/imgui/backend/imgui_impl_opengl3.cpp
new file mode 100644
index 0000000..b582851
--- /dev/null
+++ b/3rdparty/imgui/backend/imgui_impl_opengl3.cpp
@@ -0,0 +1,720 @@
+// dear imgui: Renderer Backend for modern OpenGL with shaders / programmatic pipeline
+// - Desktop GL: 2.x 3.x 4.x
+// - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0)
+// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
+
+// Implemented features:
+// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
+// [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices.
+
+// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
+// Read online: https://github.com/ocornut/imgui/tree/master/docs
+
+// CHANGELOG
+// (minor and older changes stripped away, please see git history for details)
+// 2021-02-18: OpenGL: Change blending equation to preserve alpha in output buffer.
+// 2021-01-03: OpenGL: Backup, setup and restore GL_STENCIL_TEST state.
+// 2020-10-23: OpenGL: Backup, setup and restore GL_PRIMITIVE_RESTART state.
+// 2020-10-15: OpenGL: Use glGetString(GL_VERSION) instead of glGetIntegerv(GL_MAJOR_VERSION, ...) when the later returns zero (e.g. Desktop GL 2.x)
+// 2020-09-17: OpenGL: Fix to avoid compiling/calling glBindSampler() on ES or pre 3.3 context which have the defines set by a loader.
+// 2020-07-10: OpenGL: Added support for glad2 OpenGL loader.
+// 2020-05-08: OpenGL: Made default GLSL version 150 (instead of 130) on OSX.
+// 2020-04-21: OpenGL: Fixed handling of glClipControl(GL_UPPER_LEFT) by inverting projection matrix.
+// 2020-04-12: OpenGL: Fixed context version check mistakenly testing for 4.0+ instead of 3.2+ to enable ImGuiBackendFlags_RendererHasVtxOffset.
+// 2020-03-24: OpenGL: Added support for glbinding 2.x OpenGL loader.
+// 2020-01-07: OpenGL: Added support for glbinding 3.x OpenGL loader.
+// 2019-10-25: OpenGL: Using a combination of GL define and runtime GL version to decide whether to use glDrawElementsBaseVertex(). Fix building with pre-3.2 GL loaders.
+// 2019-09-22: OpenGL: Detect default GL loader using __has_include compiler facility.
+// 2019-09-16: OpenGL: Tweak initialization code to allow application calling ImGui_ImplOpenGL3_CreateFontsTexture() before the first NewFrame() call.
+// 2019-05-29: OpenGL: Desktop GL only: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
+// 2019-04-30: OpenGL: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
+// 2019-03-29: OpenGL: Not calling glBindBuffer more than necessary in the render loop.
+// 2019-03-15: OpenGL: Added a GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized GL function loaders early.
+// 2019-03-03: OpenGL: Fix support for ES 2.0 (WebGL 1.0).
+// 2019-02-20: OpenGL: Fix for OSX not supporting OpenGL 4.5, we don't try to read GL_CLIP_ORIGIN even if defined by the headers/loader.
+// 2019-02-11: OpenGL: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display.
+// 2019-02-01: OpenGL: Using GLSL 410 shaders for any version over 410 (e.g. 430, 450).
+// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
+// 2018-11-13: OpenGL: Support for GL 4.5's glClipControl(GL_UPPER_LEFT) / GL_CLIP_ORIGIN.
+// 2018-08-29: OpenGL: Added support for more OpenGL loaders: glew and glad, with comments indicative that any loader can be used.
+// 2018-08-09: OpenGL: Default to OpenGL ES 3 on iOS and Android. GLSL version default to "#version 300 ES".
+// 2018-07-30: OpenGL: Support for GLSL 300 ES and 410 core. Fixes for Emscripten compilation.
+// 2018-07-10: OpenGL: Support for more GLSL versions (based on the GLSL version string). Added error output when shaders fail to compile/link.
+// 2018-06-08: Misc: Extracted imgui_impl_opengl3.cpp/.h away from the old combined GLFW/SDL+OpenGL3 examples.
+// 2018-06-08: OpenGL: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
+// 2018-05-25: OpenGL: Removed unnecessary backup/restore of GL_ELEMENT_ARRAY_BUFFER_BINDING since this is part of the VAO state.
+// 2018-05-14: OpenGL: Making the call to glBindSampler() optional so 3.2 context won't fail if the function is a NULL pointer.
+// 2018-03-06: OpenGL: Added const char* glsl_version parameter to ImGui_ImplOpenGL3_Init() so user can override the GLSL version e.g. "#version 150".
+// 2018-02-23: OpenGL: Create the VAO in the render function so the setup can more easily be used with multiple shared GL context.
+// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplSdlGL3_RenderDrawData() in the .h file so you can call it yourself.
+// 2018-01-07: OpenGL: Changed GLSL shader version from 330 to 150.
+// 2017-09-01: OpenGL: Save and restore current bound sampler. Save and restore current polygon mode.
+// 2017-05-01: OpenGL: Fixed save and restore of current blend func state.
+// 2017-05-01: OpenGL: Fixed save and restore of current GL_ACTIVE_TEXTURE.
+// 2016-09-05: OpenGL: Fixed save and restore of current scissor rectangle.
+// 2016-07-29: OpenGL: Explicitly setting GL_UNPACK_ROW_LENGTH to reduce issues because SDL changes it. (#752)
+
+//----------------------------------------
+// OpenGL GLSL GLSL
+// version version string
+//----------------------------------------
+// 2.0 110 "#version 110"
+// 2.1 120 "#version 120"
+// 3.0 130 "#version 130"
+// 3.1 140 "#version 140"
+// 3.2 150 "#version 150"
+// 3.3 330 "#version 330 core"
+// 4.0 400 "#version 400 core"
+// 4.1 410 "#version 410 core"
+// 4.2 420 "#version 410 core"
+// 4.3 430 "#version 430 core"
+// ES 2.0 100 "#version 100" = WebGL 1.0
+// ES 3.0 300 "#version 300 es" = WebGL 2.0
+//----------------------------------------
+
+#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+
+#include "imgui.h"
+#include "imgui_impl_opengl3.h"
+#include <stdio.h>
+#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier
+#include <stddef.h> // intptr_t
+#else
+#include <stdint.h> // intptr_t
+#endif
+
+// GL includes
+#if defined(IMGUI_IMPL_OPENGL_ES2)
+#include <GLES2/gl2.h>
+#elif defined(IMGUI_IMPL_OPENGL_ES3)
+#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV))
+#include <OpenGLES/ES3/gl.h> // Use GL ES 3
+#else
+#include <GLES3/gl3.h> // Use GL ES 3
+#endif
+#else
+// About Desktop OpenGL function loaders:
+// Modern desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers.
+// Helper libraries are often used for this purpose! Here we are supporting a few common ones (gl3w, glew, glad).
+// You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own.
+#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W)
+#include <GL/gl3w.h> // Needs to be initialized with gl3wInit() in user's code
+#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW)
+#include <GL/glew.h> // Needs to be initialized with glewInit() in user's code.
+#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD)
+#include <glad/glad.h> // Needs to be initialized with gladLoadGL() in user's code.
+#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2)
+#include <glad/gl.h> // Needs to be initialized with gladLoadGL(...) or gladLoaderLoadGL() in user's code.
+#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2)
+#ifndef GLFW_INCLUDE_NONE
+#define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors.
+#endif
+#include <glbinding/Binding.h> // Needs to be initialized with glbinding::Binding::initialize() in user's code.
+#include <glbinding/gl/gl.h>
+using namespace gl;
+#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3)
+#ifndef GLFW_INCLUDE_NONE
+#define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors.
+#endif
+#include <glbinding/glbinding.h>// Needs to be initialized with glbinding::initialize() in user's code.
+#include <glbinding/gl/gl.h>
+using namespace gl;
+#else
+#include IMGUI_IMPL_OPENGL_LOADER_CUSTOM
+#endif
+#endif
+
+// Desktop GL 3.2+ has glDrawElementsBaseVertex() which GL ES and WebGL don't have.
+#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && defined(GL_VERSION_3_2)
+#define IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
+#endif
+
+// Desktop GL 3.3+ has glBindSampler()
+#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && defined(GL_VERSION_3_3)
+#define IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
+#endif
+
+// Desktop GL 3.1+ has GL_PRIMITIVE_RESTART state
+#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && defined(GL_VERSION_3_1)
+#define IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
+#endif
+
+// OpenGL Data
+static GLuint g_GlVersion = 0; // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries (e.g. 320 for GL 3.2)
+static char g_GlslVersionString[32] = ""; // Specified by user or detected based on compile time GL settings.
+static GLuint g_FontTexture = 0;
+static GLuint g_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0;
+static GLint g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0; // Uniforms location
+static GLuint g_AttribLocationVtxPos = 0, g_AttribLocationVtxUV = 0, g_AttribLocationVtxColor = 0; // Vertex attributes location
+static unsigned int g_VboHandle = 0, g_ElementsHandle = 0;
+
+// Functions
+bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
+{
+ // Query for GL version (e.g. 320 for GL 3.2)
+#if !defined(IMGUI_IMPL_OPENGL_ES2)
+ GLint major = 0;
+ GLint minor = 0;
+ glGetIntegerv(GL_MAJOR_VERSION, &major);
+ glGetIntegerv(GL_MINOR_VERSION, &minor);
+ if (major == 0 && minor == 0)
+ {
+ // Query GL_VERSION in desktop GL 2.x, the string will start with "<major>.<minor>"
+ const char* gl_version = (const char*)glGetString(GL_VERSION);
+ sscanf(gl_version, "%d.%d", &major, &minor);
+ }
+ g_GlVersion = (GLuint)(major * 100 + minor * 10);
+#else
+ g_GlVersion = 200; // GLES 2
+#endif
+
+ // Setup backend capabilities flags
+ ImGuiIO& io = ImGui::GetIO();
+ io.BackendRendererName = "imgui_impl_opengl3";
+#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
+ if (g_GlVersion >= 320)
+ io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
+#endif
+
+ // Store GLSL version string so we can refer to it later in case we recreate shaders.
+ // Note: GLSL version is NOT the same as GL version. Leave this to NULL if unsure.
+#if defined(IMGUI_IMPL_OPENGL_ES2)
+ if (glsl_version == NULL)
+ glsl_version = "#version 100";
+#elif defined(IMGUI_IMPL_OPENGL_ES3)
+ if (glsl_version == NULL)
+ glsl_version = "#version 300 es";
+#elif defined(__APPLE__)
+ if (glsl_version == NULL)
+ glsl_version = "#version 150";
+#else
+ if (glsl_version == NULL)
+ glsl_version = "#version 130";
+#endif
+ IM_ASSERT((int)strlen(glsl_version) + 2 < IM_ARRAYSIZE(g_GlslVersionString));
+ strcpy(g_GlslVersionString, glsl_version);
+ strcat(g_GlslVersionString, "\n");
+
+ // Debugging construct to make it easily visible in the IDE and debugger which GL loader has been selected.
+ // The code actually never uses the 'gl_loader' variable! It is only here so you can read it!
+ // If auto-detection fails or doesn't select the same GL loader file as used by your application,
+ // you are likely to get a crash below.
+ // You can explicitly select a loader by using '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line.
+ const char* gl_loader = "Unknown";
+ IM_UNUSED(gl_loader);
+#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W)
+ gl_loader = "GL3W";
+#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW)
+ gl_loader = "GLEW";
+#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD)
+ gl_loader = "GLAD";
+#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2)
+ gl_loader = "GLAD2";
+#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2)
+ gl_loader = "glbinding2";
+#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3)
+ gl_loader = "glbinding3";
+#elif defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM)
+ gl_loader = "custom";
+#else
+ gl_loader = "none";
+#endif
+
+ // Make an arbitrary GL call (we don't actually need the result)
+ // IF YOU GET A CRASH HERE: it probably means that you haven't initialized the OpenGL function loader used by this code.
+ // Desktop OpenGL 3/4 need a function loader. See the IMGUI_IMPL_OPENGL_LOADER_xxx explanation above.
+ GLint current_texture;
+ glGetIntegerv(GL_TEXTURE_BINDING_2D, &current_texture);
+
+ return true;
+}
+
+void ImGui_ImplOpenGL3_Shutdown()
+{
+ ImGui_ImplOpenGL3_DestroyDeviceObjects();
+}
+
+void ImGui_ImplOpenGL3_NewFrame()
+{
+ if (!g_ShaderHandle)
+ ImGui_ImplOpenGL3_CreateDeviceObjects();
+}
+
+static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object)
+{
+ // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill
+ glEnable(GL_BLEND);
+ glBlendEquation(GL_FUNC_ADD);
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_STENCIL_TEST);
+ glEnable(GL_SCISSOR_TEST);
+#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
+ if (g_GlVersion >= 310)
+ glDisable(GL_PRIMITIVE_RESTART);
+#endif
+#ifdef GL_POLYGON_MODE
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+#endif
+
+ // Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT)
+#if defined(GL_CLIP_ORIGIN) && !defined(__APPLE__)
+ bool clip_origin_lower_left = true;
+ GLenum current_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)&current_clip_origin);
+ if (current_clip_origin == GL_UPPER_LEFT)
+ clip_origin_lower_left = false;
+#endif
+
+ // Setup viewport, orthographic projection matrix
+ // 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.
+ glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height);
+ float L = draw_data->DisplayPos.x;
+ float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
+ float T = draw_data->DisplayPos.y;
+ float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
+#if defined(GL_CLIP_ORIGIN) && !defined(__APPLE__)
+ if (!clip_origin_lower_left) { float tmp = T; T = B; B = tmp; } // Swap top and bottom if origin is upper left
+#endif
+ const float ortho_projection[4][4] =
+ {
+ { 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
+ { 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
+ { 0.0f, 0.0f, -1.0f, 0.0f },
+ { (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f },
+ };
+ glUseProgram(g_ShaderHandle);
+ glUniform1i(g_AttribLocationTex, 0);
+ glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
+
+#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
+ if (g_GlVersion >= 330)
+ glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 may set that otherwise.
+#endif
+
+ (void)vertex_array_object;
+#ifndef IMGUI_IMPL_OPENGL_ES2
+ glBindVertexArray(vertex_array_object);
+#endif
+
+ // Bind vertex/index buffers and setup attributes for ImDrawVert
+ glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_ElementsHandle);
+ glEnableVertexAttribArray(g_AttribLocationVtxPos);
+ glEnableVertexAttribArray(g_AttribLocationVtxUV);
+ glEnableVertexAttribArray(g_AttribLocationVtxColor);
+ glVertexAttribPointer(g_AttribLocationVtxPos, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, pos));
+ glVertexAttribPointer(g_AttribLocationVtxUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, uv));
+ glVertexAttribPointer(g_AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, col));
+}
+
+// OpenGL3 Render function.
+// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly.
+// This is in order to be able to run within an OpenGL engine that doesn't do so.
+void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
+{
+ // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
+ int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);
+ int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y);
+ if (fb_width <= 0 || fb_height <= 0)
+ return;
+
+ // Backup GL state
+ GLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint*)&last_active_texture);
+ glActiveTexture(GL_TEXTURE0);
+ GLuint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&last_program);
+ GLuint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&last_texture);
+#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
+ GLuint last_sampler; if (g_GlVersion >= 330) { glGetIntegerv(GL_SAMPLER_BINDING, (GLint*)&last_sampler); } else { last_sampler = 0; }
+#endif
+ GLuint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, (GLint*)&last_array_buffer);
+#ifndef IMGUI_IMPL_OPENGL_ES2
+ GLuint last_vertex_array_object; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, (GLint*)&last_vertex_array_object);
+#endif
+#ifdef GL_POLYGON_MODE
+ GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode);
+#endif
+ GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport);
+ GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box);
+ GLenum last_blend_src_rgb; glGetIntegerv(GL_BLEND_SRC_RGB, (GLint*)&last_blend_src_rgb);
+ GLenum last_blend_dst_rgb; glGetIntegerv(GL_BLEND_DST_RGB, (GLint*)&last_blend_dst_rgb);
+ GLenum last_blend_src_alpha; glGetIntegerv(GL_BLEND_SRC_ALPHA, (GLint*)&last_blend_src_alpha);
+ GLenum last_blend_dst_alpha; glGetIntegerv(GL_BLEND_DST_ALPHA, (GLint*)&last_blend_dst_alpha);
+ GLenum last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, (GLint*)&last_blend_equation_rgb);
+ GLenum last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, (GLint*)&last_blend_equation_alpha);
+ GLboolean last_enable_blend = glIsEnabled(GL_BLEND);
+ GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE);
+ GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST);
+ GLboolean last_enable_stencil_test = glIsEnabled(GL_STENCIL_TEST);
+ GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
+#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
+ GLboolean last_enable_primitive_restart = (g_GlVersion >= 310) ? glIsEnabled(GL_PRIMITIVE_RESTART) : GL_FALSE;
+#endif
+
+ // Setup desired GL state
+ // Recreate the VAO every time (this is to easily allow multiple GL contexts to be rendered to. VAO are not shared among GL contexts)
+ // The renderer would actually work without any VAO bound, but then our VertexAttrib calls would overwrite the default one currently bound.
+ GLuint vertex_array_object = 0;
+#ifndef IMGUI_IMPL_OPENGL_ES2
+ glGenVertexArrays(1, &vertex_array_object);
+#endif
+ ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
+
+ // Will project scissor/clipping rectangles into framebuffer space
+ ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
+ ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2)
+
+ // Render command lists
+ for (int n = 0; n < draw_data->CmdListsCount; n++)
+ {
+ const ImDrawList* cmd_list = draw_data->CmdLists[n];
+
+ // Upload vertex/index buffers
+ glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)cmd_list->VtxBuffer.Size * (int)sizeof(ImDrawVert), (const GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)cmd_list->IdxBuffer.Size * (int)sizeof(ImDrawIdx), (const GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW);
+
+ for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
+ {
+ const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
+ if (pcmd->UserCallback != NULL)
+ {
+ // User callback, registered via ImDrawList::AddCallback()
+ // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
+ if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
+ ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
+ else
+ pcmd->UserCallback(cmd_list, pcmd);
+ }
+ else
+ {
+ // Project scissor/clipping rectangles into framebuffer space
+ ImVec4 clip_rect;
+ clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x;
+ clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y;
+ clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x;
+ clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y;
+
+ if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f)
+ {
+ // Apply scissor/clipping rectangle
+ glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y));
+
+ // Bind texture, Draw
+ glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);
+#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
+ if (g_GlVersion >= 320)
+ glDrawElementsBaseVertex(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)), (GLint)pcmd->VtxOffset);
+ else
+#endif
+ glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)));
+ }
+ }
+ }
+ }
+
+ // Destroy the temporary VAO
+#ifndef IMGUI_IMPL_OPENGL_ES2
+ glDeleteVertexArrays(1, &vertex_array_object);
+#endif
+
+ // Restore modified GL state
+ glUseProgram(last_program);
+ glBindTexture(GL_TEXTURE_2D, last_texture);
+#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
+ if (g_GlVersion >= 330)
+ glBindSampler(0, last_sampler);
+#endif
+ glActiveTexture(last_active_texture);
+#ifndef IMGUI_IMPL_OPENGL_ES2
+ glBindVertexArray(last_vertex_array_object);
+#endif
+ glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
+ glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha);
+ glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha);
+ if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND);
+ if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE);
+ if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST);
+ if (last_enable_stencil_test) glEnable(GL_STENCIL_TEST); else glDisable(GL_STENCIL_TEST);
+ if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST);
+#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
+ if (g_GlVersion >= 310) { if (last_enable_primitive_restart) glEnable(GL_PRIMITIVE_RESTART); else glDisable(GL_PRIMITIVE_RESTART); }
+#endif
+
+#ifdef GL_POLYGON_MODE
+ glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]);
+#endif
+ glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]);
+ glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]);
+}
+
+bool ImGui_ImplOpenGL3_CreateFontsTexture()
+{
+ // Build texture atlas
+ ImGuiIO& io = ImGui::GetIO();
+ unsigned char* pixels;
+ int width, height;
+ io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
+
+ // Upload texture to graphics system
+ GLint last_texture;
+ glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
+ glGenTextures(1, &g_FontTexture);
+ glBindTexture(GL_TEXTURE_2D, g_FontTexture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+#ifdef GL_UNPACK_ROW_LENGTH
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+#endif
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+
+ // Store our identifier
+ io.Fonts->SetTexID((ImTextureID)(intptr_t)g_FontTexture);
+
+ // Restore state
+ glBindTexture(GL_TEXTURE_2D, last_texture);
+
+ return true;
+}
+
+void ImGui_ImplOpenGL3_DestroyFontsTexture()
+{
+ if (g_FontTexture)
+ {
+ ImGuiIO& io = ImGui::GetIO();
+ glDeleteTextures(1, &g_FontTexture);
+ io.Fonts->SetTexID(0);
+ g_FontTexture = 0;
+ }
+}
+
+// If you get an error please report on github. You may try different GL context version or GLSL version. See GL<>GLSL version table at the top of this file.
+static bool CheckShader(GLuint handle, const char* desc)
+{
+ GLint status = 0, log_length = 0;
+ glGetShaderiv(handle, GL_COMPILE_STATUS, &status);
+ glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &log_length);
+ if ((GLboolean)status == GL_FALSE)
+ fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to compile %s!\n", desc);
+ if (log_length > 1)
+ {
+ ImVector<char> buf;
+ buf.resize((int)(log_length + 1));
+ glGetShaderInfoLog(handle, log_length, NULL, (GLchar*)buf.begin());
+ fprintf(stderr, "%s\n", buf.begin());
+ }
+ return (GLboolean)status == GL_TRUE;
+}
+
+// If you get an error please report on GitHub. You may try different GL context version or GLSL version.
+static bool CheckProgram(GLuint handle, const char* desc)
+{
+ GLint status = 0, log_length = 0;
+ glGetProgramiv(handle, GL_LINK_STATUS, &status);
+ glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &log_length);
+ if ((GLboolean)status == GL_FALSE)
+ fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to link %s! (with GLSL '%s')\n", desc, g_GlslVersionString);
+ if (log_length > 1)
+ {
+ ImVector<char> buf;
+ buf.resize((int)(log_length + 1));
+ glGetProgramInfoLog(handle, log_length, NULL, (GLchar*)buf.begin());
+ fprintf(stderr, "%s\n", buf.begin());
+ }
+ return (GLboolean)status == GL_TRUE;
+}
+
+bool ImGui_ImplOpenGL3_CreateDeviceObjects()
+{
+ // Backup GL state
+ GLint last_texture, last_array_buffer;
+ glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
+ glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
+#ifndef IMGUI_IMPL_OPENGL_ES2
+ GLint last_vertex_array;
+ glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array);
+#endif
+
+ // Parse GLSL version string
+ int glsl_version = 130;
+ sscanf(g_GlslVersionString, "#version %d", &glsl_version);
+
+ const GLchar* vertex_shader_glsl_120 =
+ "uniform mat4 ProjMtx;\n"
+ "attribute vec2 Position;\n"
+ "attribute vec2 UV;\n"
+ "attribute vec4 Color;\n"
+ "varying vec2 Frag_UV;\n"
+ "varying vec4 Frag_Color;\n"
+ "void main()\n"
+ "{\n"
+ " Frag_UV = UV;\n"
+ " Frag_Color = Color;\n"
+ " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
+ "}\n";
+
+ const GLchar* vertex_shader_glsl_130 =
+ "uniform mat4 ProjMtx;\n"
+ "in vec2 Position;\n"
+ "in vec2 UV;\n"
+ "in vec4 Color;\n"
+ "out vec2 Frag_UV;\n"
+ "out vec4 Frag_Color;\n"
+ "void main()\n"
+ "{\n"
+ " Frag_UV = UV;\n"
+ " Frag_Color = Color;\n"
+ " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
+ "}\n";
+
+ const GLchar* vertex_shader_glsl_300_es =
+ "precision mediump float;\n"
+ "layout (location = 0) in vec2 Position;\n"
+ "layout (location = 1) in vec2 UV;\n"
+ "layout (location = 2) in vec4 Color;\n"
+ "uniform mat4 ProjMtx;\n"
+ "out vec2 Frag_UV;\n"
+ "out vec4 Frag_Color;\n"
+ "void main()\n"
+ "{\n"
+ " Frag_UV = UV;\n"
+ " Frag_Color = Color;\n"
+ " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
+ "}\n";
+
+ const GLchar* vertex_shader_glsl_410_core =
+ "layout (location = 0) in vec2 Position;\n"
+ "layout (location = 1) in vec2 UV;\n"
+ "layout (location = 2) in vec4 Color;\n"
+ "uniform mat4 ProjMtx;\n"
+ "out vec2 Frag_UV;\n"
+ "out vec4 Frag_Color;\n"
+ "void main()\n"
+ "{\n"
+ " Frag_UV = UV;\n"
+ " Frag_Color = Color;\n"
+ " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
+ "}\n";
+
+ const GLchar* fragment_shader_glsl_120 =
+ "#ifdef GL_ES\n"
+ " precision mediump float;\n"
+ "#endif\n"
+ "uniform sampler2D Texture;\n"
+ "varying vec2 Frag_UV;\n"
+ "varying vec4 Frag_Color;\n"
+ "void main()\n"
+ "{\n"
+ " gl_FragColor = Frag_Color * texture2D(Texture, Frag_UV.st);\n"
+ "}\n";
+
+ const GLchar* fragment_shader_glsl_130 =
+ "uniform sampler2D Texture;\n"
+ "in vec2 Frag_UV;\n"
+ "in vec4 Frag_Color;\n"
+ "out vec4 Out_Color;\n"
+ "void main()\n"
+ "{\n"
+ " Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
+ "}\n";
+
+ const GLchar* fragment_shader_glsl_300_es =
+ "precision mediump float;\n"
+ "uniform sampler2D Texture;\n"
+ "in vec2 Frag_UV;\n"
+ "in vec4 Frag_Color;\n"
+ "layout (location = 0) out vec4 Out_Color;\n"
+ "void main()\n"
+ "{\n"
+ " Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
+ "}\n";
+
+ const GLchar* fragment_shader_glsl_410_core =
+ "in vec2 Frag_UV;\n"
+ "in vec4 Frag_Color;\n"
+ "uniform sampler2D Texture;\n"
+ "layout (location = 0) out vec4 Out_Color;\n"
+ "void main()\n"
+ "{\n"
+ " Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
+ "}\n";
+
+ // Select shaders matching our GLSL versions
+ const GLchar* vertex_shader = NULL;
+ const GLchar* fragment_shader = NULL;
+ if (glsl_version < 130)
+ {
+ vertex_shader = vertex_shader_glsl_120;
+ fragment_shader = fragment_shader_glsl_120;
+ }
+ else if (glsl_version >= 410)
+ {
+ vertex_shader = vertex_shader_glsl_410_core;
+ fragment_shader = fragment_shader_glsl_410_core;
+ }
+ else if (glsl_version == 300)
+ {
+ vertex_shader = vertex_shader_glsl_300_es;
+ fragment_shader = fragment_shader_glsl_300_es;
+ }
+ else
+ {
+ vertex_shader = vertex_shader_glsl_130;
+ fragment_shader = fragment_shader_glsl_130;
+ }
+
+ // Create shaders
+ const GLchar* vertex_shader_with_version[2] = { g_GlslVersionString, vertex_shader };
+ g_VertHandle = glCreateShader(GL_VERTEX_SHADER);
+ glShaderSource(g_VertHandle, 2, vertex_shader_with_version, NULL);
+ glCompileShader(g_VertHandle);
+ CheckShader(g_VertHandle, "vertex shader");
+
+ const GLchar* fragment_shader_with_version[2] = { g_GlslVersionString, fragment_shader };
+ g_FragHandle = glCreateShader(GL_FRAGMENT_SHADER);
+ glShaderSource(g_FragHandle, 2, fragment_shader_with_version, NULL);
+ glCompileShader(g_FragHandle);
+ CheckShader(g_FragHandle, "fragment shader");
+
+ g_ShaderHandle = glCreateProgram();
+ glAttachShader(g_ShaderHandle, g_VertHandle);
+ glAttachShader(g_ShaderHandle, g_FragHandle);
+ glLinkProgram(g_ShaderHandle);
+ CheckProgram(g_ShaderHandle, "shader program");
+
+ g_AttribLocationTex = glGetUniformLocation(g_ShaderHandle, "Texture");
+ g_AttribLocationProjMtx = glGetUniformLocation(g_ShaderHandle, "ProjMtx");
+ g_AttribLocationVtxPos = (GLuint)glGetAttribLocation(g_ShaderHandle, "Position");
+ g_AttribLocationVtxUV = (GLuint)glGetAttribLocation(g_ShaderHandle, "UV");
+ g_AttribLocationVtxColor = (GLuint)glGetAttribLocation(g_ShaderHandle, "Color");
+
+ // Create buffers
+ glGenBuffers(1, &g_VboHandle);
+ glGenBuffers(1, &g_ElementsHandle);
+
+ ImGui_ImplOpenGL3_CreateFontsTexture();
+
+ // Restore modified GL state
+ glBindTexture(GL_TEXTURE_2D, last_texture);
+ glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
+#ifndef IMGUI_IMPL_OPENGL_ES2
+ glBindVertexArray(last_vertex_array);
+#endif
+
+ return true;
+}
+
+void ImGui_ImplOpenGL3_DestroyDeviceObjects()
+{
+ if (g_VboHandle) { glDeleteBuffers(1, &g_VboHandle); g_VboHandle = 0; }
+ if (g_ElementsHandle) { glDeleteBuffers(1, &g_ElementsHandle); g_ElementsHandle = 0; }
+ if (g_ShaderHandle && g_VertHandle) { glDetachShader(g_ShaderHandle, g_VertHandle); }
+ if (g_ShaderHandle && g_FragHandle) { glDetachShader(g_ShaderHandle, g_FragHandle); }
+ if (g_VertHandle) { glDeleteShader(g_VertHandle); g_VertHandle = 0; }
+ if (g_FragHandle) { glDeleteShader(g_FragHandle); g_FragHandle = 0; }
+ if (g_ShaderHandle) { glDeleteProgram(g_ShaderHandle); g_ShaderHandle = 0; }
+
+ ImGui_ImplOpenGL3_DestroyFontsTexture();
+}
diff --git a/3rdparty/imgui/backend/imgui_impl_opengl3.h b/3rdparty/imgui/backend/imgui_impl_opengl3.h
new file mode 100644
index 0000000..8c0126d
--- /dev/null
+++ b/3rdparty/imgui/backend/imgui_impl_opengl3.h
@@ -0,0 +1,87 @@
+// dear imgui: Renderer Backend for modern OpenGL with shaders / programmatic pipeline
+// - Desktop GL: 2.x 3.x 4.x
+// - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0)
+// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
+
+// Implemented features:
+// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
+// [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices.
+
+// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
+// Read online: https://github.com/ocornut/imgui/tree/master/docs
+
+// About Desktop OpenGL function loaders:
+// Modern Desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers.
+// Helper libraries are often used for this purpose! Here we are supporting a few common ones (gl3w, glew, glad).
+// You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own.
+
+// About GLSL version:
+// The 'glsl_version' initialization parameter should be NULL (default) or a "#version XXX" string.
+// On computer platform the GLSL version default to "#version 130". On OpenGL ES 3 platform it defaults to "#version 300 es"
+// Only override if your GL version doesn't handle this GLSL version. See GLSL version table at the top of imgui_impl_opengl3.cpp.
+
+#pragma once
+#include "imgui.h" // IMGUI_IMPL_API
+
+// Backend API
+IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version = NULL);
+IMGUI_IMPL_API void ImGui_ImplOpenGL3_Shutdown();
+IMGUI_IMPL_API void ImGui_ImplOpenGL3_NewFrame();
+IMGUI_IMPL_API void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data);
+
+// (Optional) Called by Init/NewFrame/Shutdown
+IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateFontsTexture();
+IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyFontsTexture();
+IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateDeviceObjects();
+IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects();
+
+// Specific OpenGL ES versions
+//#define IMGUI_IMPL_OPENGL_ES2 // Auto-detected on Emscripten
+//#define IMGUI_IMPL_OPENGL_ES3 // Auto-detected on iOS/Android
+
+// Attempt to auto-detect the default Desktop GL loader based on available header files.
+// If auto-detection fails or doesn't select the same GL loader file as used by your application,
+// you are likely to get a crash in ImGui_ImplOpenGL3_Init().
+// You can explicitly select a loader by using one of the '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line.
+#if !defined(IMGUI_IMPL_OPENGL_ES2) \
+ && !defined(IMGUI_IMPL_OPENGL_ES3) \
+ && !defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) \
+ && !defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) \
+ && !defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) \
+ && !defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2) \
+ && !defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2) \
+ && !defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3) \
+ && !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM)
+
+// Try to detect GLES on matching platforms
+#if defined(__APPLE__)
+#include "TargetConditionals.h"
+#endif
+#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) || (defined(__ANDROID__))
+#define IMGUI_IMPL_OPENGL_ES3 // iOS, Android -> GL ES 3, "#version 300 es"
+#elif defined(__EMSCRIPTEN__)
+#define IMGUI_IMPL_OPENGL_ES2 // Emscripten -> GL ES 2, "#version 100"
+
+// Otherwise try to detect supported Desktop OpenGL loaders..
+#elif defined(__has_include)
+#if __has_include(<GL/glew.h>)
+ #define IMGUI_IMPL_OPENGL_LOADER_GLEW
+#elif __has_include(<glad/glad.h>)
+ #define IMGUI_IMPL_OPENGL_LOADER_GLAD
+#elif __has_include(<glad/gl.h>)
+ #define IMGUI_IMPL_OPENGL_LOADER_GLAD2
+#elif __has_include(<GL/gl3w.h>)
+ #define IMGUI_IMPL_OPENGL_LOADER_GL3W
+#elif __has_include(<glbinding/glbinding.h>)
+ #define IMGUI_IMPL_OPENGL_LOADER_GLBINDING3
+#elif __has_include(<glbinding/Binding.h>)
+ #define IMGUI_IMPL_OPENGL_LOADER_GLBINDING2
+#else
+ #error "Cannot detect OpenGL loader!"
+#endif
+#else
+ #define IMGUI_IMPL_OPENGL_LOADER_GL3W // Default to GL3W embedded in our repository
+#endif
+
+#endif
diff --git a/3rdparty/imgui/backend/imgui_impl_vulkan.cpp b/3rdparty/imgui/backend/imgui_impl_vulkan.cpp
new file mode 100644
index 0000000..167687e
--- /dev/null
+++ b/3rdparty/imgui/backend/imgui_impl_vulkan.cpp
@@ -0,0 +1,1416 @@
+// dear imgui: Renderer Backend for Vulkan
+// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
+
+// Implemented features:
+// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
+// Missing features:
+// [ ] Renderer: User texture binding. Changes of ImTextureID aren't supported by this backend! See https://github.com/ocornut/imgui/pull/914
+
+// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
+// Read online: https://github.com/ocornut/imgui/tree/master/docs
+
+// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification.
+// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
+
+// Important note to the reader who wish to integrate imgui_impl_vulkan.cpp/.h in their own engine/app.
+// - Common ImGui_ImplVulkan_XXX functions and structures are used to interface with imgui_impl_vulkan.cpp/.h.
+// You will use those if you want to use this rendering backend in your engine/app.
+// - Helper ImGui_ImplVulkanH_XXX functions and structures are only used by this example (main.cpp) and by
+// the backend itself (imgui_impl_vulkan.cpp), but should PROBABLY NOT be used by your own engine/app code.
+// Read comments in imgui_impl_vulkan.h.
+
+// CHANGELOG
+// (minor and older changes stripped away, please see git history for details)
+// 2021-03-22: Vulkan: Fix mapped memory validation error when buffer sizes are not multiple of VkPhysicalDeviceLimits::nonCoherentAtomSize.
+// 2021-02-18: Vulkan: Change blending equation to preserve alpha in output buffer.
+// 2021-01-27: Vulkan: Added support for custom function load and IMGUI_IMPL_VULKAN_NO_PROTOTYPES by using ImGui_ImplVulkan_LoadFunctions().
+// 2020-11-11: Vulkan: Added support for specifying which subpass to reference during VkPipeline creation.
+// 2020-09-07: Vulkan: Added VkPipeline parameter to ImGui_ImplVulkan_RenderDrawData (default to one passed to ImGui_ImplVulkan_Init).
+// 2020-05-04: Vulkan: Fixed crash if initial frame has no vertices.
+// 2020-04-26: Vulkan: Fixed edge case where render callbacks wouldn't be called if the ImDrawData didn't have vertices.
+// 2019-08-01: Vulkan: Added support for specifying multisample count. Set ImGui_ImplVulkan_InitInfo::MSAASamples to one of the VkSampleCountFlagBits values to use, default is non-multisampled as before.
+// 2019-05-29: Vulkan: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
+// 2019-04-30: Vulkan: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
+// 2019-04-04: *BREAKING CHANGE*: Vulkan: Added ImageCount/MinImageCount fields in ImGui_ImplVulkan_InitInfo, required for initialization (was previously a hard #define IMGUI_VK_QUEUED_FRAMES 2). Added ImGui_ImplVulkan_SetMinImageCount().
+// 2019-04-04: Vulkan: Added VkInstance argument to ImGui_ImplVulkanH_CreateWindow() optional helper.
+// 2019-04-04: Vulkan: Avoid passing negative coordinates to vkCmdSetScissor, which debug validation layers do not like.
+// 2019-04-01: Vulkan: Support for 32-bit index buffer (#define ImDrawIdx unsigned int).
+// 2019-02-16: Vulkan: Viewport and clipping rectangles correctly using draw_data->FramebufferScale to allow retina display.
+// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
+// 2018-08-25: Vulkan: Fixed mishandled VkSurfaceCapabilitiesKHR::maxImageCount=0 case.
+// 2018-06-22: Inverted the parameters to ImGui_ImplVulkan_RenderDrawData() to be consistent with other backends.
+// 2018-06-08: Misc: Extracted imgui_impl_vulkan.cpp/.h away from the old combined GLFW+Vulkan example.
+// 2018-06-08: Vulkan: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
+// 2018-03-03: Vulkan: Various refactor, created a couple of ImGui_ImplVulkanH_XXX helper that the example can use and that viewport support will use.
+// 2018-03-01: Vulkan: Renamed ImGui_ImplVulkan_Init_Info to ImGui_ImplVulkan_InitInfo and fields to match more closely Vulkan terminology.
+// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback, ImGui_ImplVulkan_Render() calls ImGui_ImplVulkan_RenderDrawData() itself.
+// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
+// 2017-05-15: Vulkan: Fix scissor offset being negative. Fix new Vulkan validation warnings. Set required depth member for buffer image copy.
+// 2016-11-13: Vulkan: Fix validation layer warnings and errors and redeclare gl_PerVertex.
+// 2016-10-18: Vulkan: Add location decorators & change to use structs as in/out in glsl, update embedded spv (produced with glslangValidator -x). Null the released resources.
+// 2016-08-27: Vulkan: Fix Vulkan example for use when a depth buffer is active.
+
+#include "imgui_impl_vulkan.h"
+#include <stdio.h>
+
+// Reusable buffers used for rendering 1 current in-flight frame, for ImGui_ImplVulkan_RenderDrawData()
+// [Please zero-clear before use!]
+struct ImGui_ImplVulkanH_FrameRenderBuffers
+{
+ VkDeviceMemory VertexBufferMemory;
+ VkDeviceMemory IndexBufferMemory;
+ VkDeviceSize VertexBufferSize;
+ VkDeviceSize IndexBufferSize;
+ VkBuffer VertexBuffer;
+ VkBuffer IndexBuffer;
+};
+
+// Each viewport will hold 1 ImGui_ImplVulkanH_WindowRenderBuffers
+// [Please zero-clear before use!]
+struct ImGui_ImplVulkanH_WindowRenderBuffers
+{
+ uint32_t Index;
+ uint32_t Count;
+ ImGui_ImplVulkanH_FrameRenderBuffers* FrameRenderBuffers;
+};
+
+// Vulkan data
+static ImGui_ImplVulkan_InitInfo g_VulkanInitInfo = {};
+static VkRenderPass g_RenderPass = VK_NULL_HANDLE;
+static VkDeviceSize g_BufferMemoryAlignment = 256;
+static VkPipelineCreateFlags g_PipelineCreateFlags = 0x00;
+static VkDescriptorSetLayout g_DescriptorSetLayout = VK_NULL_HANDLE;
+static VkPipelineLayout g_PipelineLayout = VK_NULL_HANDLE;
+static VkDescriptorSet g_DescriptorSet = VK_NULL_HANDLE;
+static VkPipeline g_Pipeline = VK_NULL_HANDLE;
+static uint32_t g_Subpass = 0;
+static VkShaderModule g_ShaderModuleVert;
+static VkShaderModule g_ShaderModuleFrag;
+#ifdef VK_NO_PROTOTYPES
+static bool g_FunctionsLoaded = false;
+#else
+static bool g_FunctionsLoaded = true;
+#endif
+
+// Font data
+static VkSampler g_FontSampler = VK_NULL_HANDLE;
+static VkDeviceMemory g_FontMemory = VK_NULL_HANDLE;
+static VkImage g_FontImage = VK_NULL_HANDLE;
+static VkImageView g_FontView = VK_NULL_HANDLE;
+static VkDeviceMemory g_UploadBufferMemory = VK_NULL_HANDLE;
+static VkBuffer g_UploadBuffer = VK_NULL_HANDLE;
+
+// Render buffers
+static ImGui_ImplVulkanH_WindowRenderBuffers g_MainWindowRenderBuffers;
+
+// Forward Declarations
+bool ImGui_ImplVulkan_CreateDeviceObjects();
+void ImGui_ImplVulkan_DestroyDeviceObjects();
+void ImGui_ImplVulkanH_DestroyFrame(VkDevice device, ImGui_ImplVulkanH_Frame* fd, const VkAllocationCallbacks* allocator);
+void ImGui_ImplVulkanH_DestroyFrameSemaphores(VkDevice device, ImGui_ImplVulkanH_FrameSemaphores* fsd, const VkAllocationCallbacks* allocator);
+void ImGui_ImplVulkanH_DestroyFrameRenderBuffers(VkDevice device, ImGui_ImplVulkanH_FrameRenderBuffers* buffers, const VkAllocationCallbacks* allocator);
+void ImGui_ImplVulkanH_DestroyWindowRenderBuffers(VkDevice device, ImGui_ImplVulkanH_WindowRenderBuffers* buffers, const VkAllocationCallbacks* allocator);
+void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count);
+void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator);
+
+// Vulkan prototypes for use with custom loaders
+// (see description of IMGUI_IMPL_VULKAN_NO_PROTOTYPES in imgui_impl_vulkan.h
+#ifdef VK_NO_PROTOTYPES
+#define IMGUI_VULKAN_FUNC_MAP(IMGUI_VULKAN_FUNC_MAP_MACRO) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkAllocateCommandBuffers) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkAllocateDescriptorSets) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkAllocateMemory) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkBindBufferMemory) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkBindImageMemory) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdBindDescriptorSets) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdBindIndexBuffer) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdBindPipeline) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdBindVertexBuffers) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdCopyBufferToImage) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdDrawIndexed) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdPipelineBarrier) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdPushConstants) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdSetScissor) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdSetViewport) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateBuffer) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateCommandPool) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateDescriptorSetLayout) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateFence) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateFramebuffer) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateGraphicsPipelines) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateImage) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateImageView) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreatePipelineLayout) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateRenderPass) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateSampler) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateSemaphore) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateShaderModule) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateSwapchainKHR) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyBuffer) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyCommandPool) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyDescriptorSetLayout) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyFence) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyFramebuffer) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyImage) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyImageView) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyPipeline) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyPipelineLayout) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyRenderPass) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroySampler) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroySemaphore) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyShaderModule) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroySurfaceKHR) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroySwapchainKHR) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDeviceWaitIdle) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkFlushMappedMemoryRanges) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkFreeCommandBuffers) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkFreeMemory) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetBufferMemoryRequirements) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetImageMemoryRequirements) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceMemoryProperties) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceSurfaceCapabilitiesKHR) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceSurfaceFormatsKHR) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceSurfacePresentModesKHR) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetSwapchainImagesKHR) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkMapMemory) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkUnmapMemory) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkUpdateDescriptorSets)
+
+// Define function pointers
+#define IMGUI_VULKAN_FUNC_DEF(func) static PFN_##func func;
+IMGUI_VULKAN_FUNC_MAP(IMGUI_VULKAN_FUNC_DEF)
+#undef IMGUI_VULKAN_FUNC_DEF
+#endif // VK_NO_PROTOTYPES
+
+//-----------------------------------------------------------------------------
+// SHADERS
+//-----------------------------------------------------------------------------
+
+// glsl_shader.vert, compiled with:
+// # glslangValidator -V -x -o glsl_shader.vert.u32 glsl_shader.vert
+/*
+#version 450 core
+layout(location = 0) in vec2 aPos;
+layout(location = 1) in vec2 aUV;
+layout(location = 2) in vec4 aColor;
+layout(push_constant) uniform uPushConstant { vec2 uScale; vec2 uTranslate; } pc;
+
+out gl_PerVertex { vec4 gl_Position; };
+layout(location = 0) out struct { vec4 Color; vec2 UV; } Out;
+
+void main()
+{
+ Out.Color = aColor;
+ Out.UV = aUV;
+ gl_Position = vec4(aPos * pc.uScale + pc.uTranslate, 0, 1);
+}
+*/
+static uint32_t __glsl_shader_vert_spv[] =
+{
+ 0x07230203,0x00010000,0x00080001,0x0000002e,0x00000000,0x00020011,0x00000001,0x0006000b,
+ 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001,
+ 0x000a000f,0x00000000,0x00000004,0x6e69616d,0x00000000,0x0000000b,0x0000000f,0x00000015,
+ 0x0000001b,0x0000001c,0x00030003,0x00000002,0x000001c2,0x00040005,0x00000004,0x6e69616d,
+ 0x00000000,0x00030005,0x00000009,0x00000000,0x00050006,0x00000009,0x00000000,0x6f6c6f43,
+ 0x00000072,0x00040006,0x00000009,0x00000001,0x00005655,0x00030005,0x0000000b,0x0074754f,
+ 0x00040005,0x0000000f,0x6c6f4361,0x0000726f,0x00030005,0x00000015,0x00565561,0x00060005,
+ 0x00000019,0x505f6c67,0x65567265,0x78657472,0x00000000,0x00060006,0x00000019,0x00000000,
+ 0x505f6c67,0x7469736f,0x006e6f69,0x00030005,0x0000001b,0x00000000,0x00040005,0x0000001c,
+ 0x736f5061,0x00000000,0x00060005,0x0000001e,0x73755075,0x6e6f4368,0x6e617473,0x00000074,
+ 0x00050006,0x0000001e,0x00000000,0x61635375,0x0000656c,0x00060006,0x0000001e,0x00000001,
+ 0x61725475,0x616c736e,0x00006574,0x00030005,0x00000020,0x00006370,0x00040047,0x0000000b,
+ 0x0000001e,0x00000000,0x00040047,0x0000000f,0x0000001e,0x00000002,0x00040047,0x00000015,
+ 0x0000001e,0x00000001,0x00050048,0x00000019,0x00000000,0x0000000b,0x00000000,0x00030047,
+ 0x00000019,0x00000002,0x00040047,0x0000001c,0x0000001e,0x00000000,0x00050048,0x0000001e,
+ 0x00000000,0x00000023,0x00000000,0x00050048,0x0000001e,0x00000001,0x00000023,0x00000008,
+ 0x00030047,0x0000001e,0x00000002,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,
+ 0x00030016,0x00000006,0x00000020,0x00040017,0x00000007,0x00000006,0x00000004,0x00040017,
+ 0x00000008,0x00000006,0x00000002,0x0004001e,0x00000009,0x00000007,0x00000008,0x00040020,
+ 0x0000000a,0x00000003,0x00000009,0x0004003b,0x0000000a,0x0000000b,0x00000003,0x00040015,
+ 0x0000000c,0x00000020,0x00000001,0x0004002b,0x0000000c,0x0000000d,0x00000000,0x00040020,
+ 0x0000000e,0x00000001,0x00000007,0x0004003b,0x0000000e,0x0000000f,0x00000001,0x00040020,
+ 0x00000011,0x00000003,0x00000007,0x0004002b,0x0000000c,0x00000013,0x00000001,0x00040020,
+ 0x00000014,0x00000001,0x00000008,0x0004003b,0x00000014,0x00000015,0x00000001,0x00040020,
+ 0x00000017,0x00000003,0x00000008,0x0003001e,0x00000019,0x00000007,0x00040020,0x0000001a,
+ 0x00000003,0x00000019,0x0004003b,0x0000001a,0x0000001b,0x00000003,0x0004003b,0x00000014,
+ 0x0000001c,0x00000001,0x0004001e,0x0000001e,0x00000008,0x00000008,0x00040020,0x0000001f,
+ 0x00000009,0x0000001e,0x0004003b,0x0000001f,0x00000020,0x00000009,0x00040020,0x00000021,
+ 0x00000009,0x00000008,0x0004002b,0x00000006,0x00000028,0x00000000,0x0004002b,0x00000006,
+ 0x00000029,0x3f800000,0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,
+ 0x00000005,0x0004003d,0x00000007,0x00000010,0x0000000f,0x00050041,0x00000011,0x00000012,
+ 0x0000000b,0x0000000d,0x0003003e,0x00000012,0x00000010,0x0004003d,0x00000008,0x00000016,
+ 0x00000015,0x00050041,0x00000017,0x00000018,0x0000000b,0x00000013,0x0003003e,0x00000018,
+ 0x00000016,0x0004003d,0x00000008,0x0000001d,0x0000001c,0x00050041,0x00000021,0x00000022,
+ 0x00000020,0x0000000d,0x0004003d,0x00000008,0x00000023,0x00000022,0x00050085,0x00000008,
+ 0x00000024,0x0000001d,0x00000023,0x00050041,0x00000021,0x00000025,0x00000020,0x00000013,
+ 0x0004003d,0x00000008,0x00000026,0x00000025,0x00050081,0x00000008,0x00000027,0x00000024,
+ 0x00000026,0x00050051,0x00000006,0x0000002a,0x00000027,0x00000000,0x00050051,0x00000006,
+ 0x0000002b,0x00000027,0x00000001,0x00070050,0x00000007,0x0000002c,0x0000002a,0x0000002b,
+ 0x00000028,0x00000029,0x00050041,0x00000011,0x0000002d,0x0000001b,0x0000000d,0x0003003e,
+ 0x0000002d,0x0000002c,0x000100fd,0x00010038
+};
+
+// glsl_shader.frag, compiled with:
+// # glslangValidator -V -x -o glsl_shader.frag.u32 glsl_shader.frag
+/*
+#version 450 core
+layout(location = 0) out vec4 fColor;
+layout(set=0, binding=0) uniform sampler2D sTexture;
+layout(location = 0) in struct { vec4 Color; vec2 UV; } In;
+void main()
+{
+ fColor = In.Color * texture(sTexture, In.UV.st);
+}
+*/
+static uint32_t __glsl_shader_frag_spv[] =
+{
+ 0x07230203,0x00010000,0x00080001,0x0000001e,0x00000000,0x00020011,0x00000001,0x0006000b,
+ 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001,
+ 0x0007000f,0x00000004,0x00000004,0x6e69616d,0x00000000,0x00000009,0x0000000d,0x00030010,
+ 0x00000004,0x00000007,0x00030003,0x00000002,0x000001c2,0x00040005,0x00000004,0x6e69616d,
+ 0x00000000,0x00040005,0x00000009,0x6c6f4366,0x0000726f,0x00030005,0x0000000b,0x00000000,
+ 0x00050006,0x0000000b,0x00000000,0x6f6c6f43,0x00000072,0x00040006,0x0000000b,0x00000001,
+ 0x00005655,0x00030005,0x0000000d,0x00006e49,0x00050005,0x00000016,0x78655473,0x65727574,
+ 0x00000000,0x00040047,0x00000009,0x0000001e,0x00000000,0x00040047,0x0000000d,0x0000001e,
+ 0x00000000,0x00040047,0x00000016,0x00000022,0x00000000,0x00040047,0x00000016,0x00000021,
+ 0x00000000,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00030016,0x00000006,
+ 0x00000020,0x00040017,0x00000007,0x00000006,0x00000004,0x00040020,0x00000008,0x00000003,
+ 0x00000007,0x0004003b,0x00000008,0x00000009,0x00000003,0x00040017,0x0000000a,0x00000006,
+ 0x00000002,0x0004001e,0x0000000b,0x00000007,0x0000000a,0x00040020,0x0000000c,0x00000001,
+ 0x0000000b,0x0004003b,0x0000000c,0x0000000d,0x00000001,0x00040015,0x0000000e,0x00000020,
+ 0x00000001,0x0004002b,0x0000000e,0x0000000f,0x00000000,0x00040020,0x00000010,0x00000001,
+ 0x00000007,0x00090019,0x00000013,0x00000006,0x00000001,0x00000000,0x00000000,0x00000000,
+ 0x00000001,0x00000000,0x0003001b,0x00000014,0x00000013,0x00040020,0x00000015,0x00000000,
+ 0x00000014,0x0004003b,0x00000015,0x00000016,0x00000000,0x0004002b,0x0000000e,0x00000018,
+ 0x00000001,0x00040020,0x00000019,0x00000001,0x0000000a,0x00050036,0x00000002,0x00000004,
+ 0x00000000,0x00000003,0x000200f8,0x00000005,0x00050041,0x00000010,0x00000011,0x0000000d,
+ 0x0000000f,0x0004003d,0x00000007,0x00000012,0x00000011,0x0004003d,0x00000014,0x00000017,
+ 0x00000016,0x00050041,0x00000019,0x0000001a,0x0000000d,0x00000018,0x0004003d,0x0000000a,
+ 0x0000001b,0x0000001a,0x00050057,0x00000007,0x0000001c,0x00000017,0x0000001b,0x00050085,
+ 0x00000007,0x0000001d,0x00000012,0x0000001c,0x0003003e,0x00000009,0x0000001d,0x000100fd,
+ 0x00010038
+};
+
+//-----------------------------------------------------------------------------
+// FUNCTIONS
+//-----------------------------------------------------------------------------
+
+static uint32_t ImGui_ImplVulkan_MemoryType(VkMemoryPropertyFlags properties, uint32_t type_bits)
+{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
+ VkPhysicalDeviceMemoryProperties prop;
+ vkGetPhysicalDeviceMemoryProperties(v->PhysicalDevice, &prop);
+ for (uint32_t i = 0; i < prop.memoryTypeCount; i++)
+ if ((prop.memoryTypes[i].propertyFlags & properties) == properties && type_bits & (1 << i))
+ return i;
+ return 0xFFFFFFFF; // Unable to find memoryType
+}
+
+static void check_vk_result(VkResult err)
+{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
+ if (v->CheckVkResultFn)
+ v->CheckVkResultFn(err);
+}
+
+static void CreateOrResizeBuffer(VkBuffer& buffer, VkDeviceMemory& buffer_memory, VkDeviceSize& p_buffer_size, size_t new_size, VkBufferUsageFlagBits usage)
+{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
+ VkResult err;
+ if (buffer != VK_NULL_HANDLE)
+ vkDestroyBuffer(v->Device, buffer, v->Allocator);
+ if (buffer_memory != VK_NULL_HANDLE)
+ vkFreeMemory(v->Device, buffer_memory, v->Allocator);
+
+ VkDeviceSize vertex_buffer_size_aligned = ((new_size - 1) / g_BufferMemoryAlignment + 1) * g_BufferMemoryAlignment;
+ VkBufferCreateInfo buffer_info = {};
+ buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+ buffer_info.size = vertex_buffer_size_aligned;
+ buffer_info.usage = usage;
+ buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+ err = vkCreateBuffer(v->Device, &buffer_info, v->Allocator, &buffer);
+ check_vk_result(err);
+
+ VkMemoryRequirements req;
+ vkGetBufferMemoryRequirements(v->Device, buffer, &req);
+ g_BufferMemoryAlignment = (g_BufferMemoryAlignment > req.alignment) ? g_BufferMemoryAlignment : req.alignment;
+ VkMemoryAllocateInfo alloc_info = {};
+ alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+ alloc_info.allocationSize = req.size;
+ alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits);
+ err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &buffer_memory);
+ check_vk_result(err);
+
+ err = vkBindBufferMemory(v->Device, buffer, buffer_memory, 0);
+ check_vk_result(err);
+ p_buffer_size = req.size;
+}
+
+static void ImGui_ImplVulkan_SetupRenderState(ImDrawData* draw_data, VkPipeline pipeline, VkCommandBuffer command_buffer, ImGui_ImplVulkanH_FrameRenderBuffers* rb, int fb_width, int fb_height)
+{
+ // Bind pipeline and descriptor sets:
+ {
+ vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
+ VkDescriptorSet desc_set[1] = { g_DescriptorSet };
+ vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, g_PipelineLayout, 0, 1, desc_set, 0, NULL);
+ }
+
+ // Bind Vertex And Index Buffer:
+ if (draw_data->TotalVtxCount > 0)
+ {
+ VkBuffer vertex_buffers[1] = { rb->VertexBuffer };
+ VkDeviceSize vertex_offset[1] = { 0 };
+ vkCmdBindVertexBuffers(command_buffer, 0, 1, vertex_buffers, vertex_offset);
+ vkCmdBindIndexBuffer(command_buffer, rb->IndexBuffer, 0, sizeof(ImDrawIdx) == 2 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32);
+ }
+
+ // Setup viewport:
+ {
+ VkViewport viewport;
+ viewport.x = 0;
+ viewport.y = 0;
+ viewport.width = (float)fb_width;
+ viewport.height = (float)fb_height;
+ viewport.minDepth = 0.0f;
+ viewport.maxDepth = 1.0f;
+ vkCmdSetViewport(command_buffer, 0, 1, &viewport);
+ }
+
+ // Setup scale and translation:
+ // Our visible imgui space lies from draw_data->DisplayPps (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
+ {
+ float scale[2];
+ scale[0] = 2.0f / draw_data->DisplaySize.x;
+ scale[1] = 2.0f / draw_data->DisplaySize.y;
+ float translate[2];
+ translate[0] = -1.0f - draw_data->DisplayPos.x * scale[0];
+ translate[1] = -1.0f - draw_data->DisplayPos.y * scale[1];
+ vkCmdPushConstants(command_buffer, g_PipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, sizeof(float) * 0, sizeof(float) * 2, scale);
+ vkCmdPushConstants(command_buffer, g_PipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, sizeof(float) * 2, sizeof(float) * 2, translate);
+ }
+}
+
+// Render function
+void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer, VkPipeline pipeline)
+{
+ // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
+ int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);
+ int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y);
+ if (fb_width <= 0 || fb_height <= 0)
+ return;
+
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
+ if (pipeline == VK_NULL_HANDLE)
+ pipeline = g_Pipeline;
+
+ // Allocate array to store enough vertex/index buffers
+ ImGui_ImplVulkanH_WindowRenderBuffers* wrb = &g_MainWindowRenderBuffers;
+ if (wrb->FrameRenderBuffers == NULL)
+ {
+ wrb->Index = 0;
+ wrb->Count = v->ImageCount;
+ wrb->FrameRenderBuffers = (ImGui_ImplVulkanH_FrameRenderBuffers*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_FrameRenderBuffers) * wrb->Count);
+ memset(wrb->FrameRenderBuffers, 0, sizeof(ImGui_ImplVulkanH_FrameRenderBuffers) * wrb->Count);
+ }
+ IM_ASSERT(wrb->Count == v->ImageCount);
+ wrb->Index = (wrb->Index + 1) % wrb->Count;
+ ImGui_ImplVulkanH_FrameRenderBuffers* rb = &wrb->FrameRenderBuffers[wrb->Index];
+
+ if (draw_data->TotalVtxCount > 0)
+ {
+ // Create or resize the vertex/index buffers
+ size_t vertex_size = draw_data->TotalVtxCount * sizeof(ImDrawVert);
+ size_t index_size = draw_data->TotalIdxCount * sizeof(ImDrawIdx);
+ if (rb->VertexBuffer == VK_NULL_HANDLE || rb->VertexBufferSize < vertex_size)
+ CreateOrResizeBuffer(rb->VertexBuffer, rb->VertexBufferMemory, rb->VertexBufferSize, vertex_size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
+ if (rb->IndexBuffer == VK_NULL_HANDLE || rb->IndexBufferSize < index_size)
+ CreateOrResizeBuffer(rb->IndexBuffer, rb->IndexBufferMemory, rb->IndexBufferSize, index_size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
+
+ // Upload vertex/index data into a single contiguous GPU buffer
+ ImDrawVert* vtx_dst = NULL;
+ ImDrawIdx* idx_dst = NULL;
+ VkResult err = vkMapMemory(v->Device, rb->VertexBufferMemory, 0, rb->VertexBufferSize, 0, (void**)(&vtx_dst));
+ check_vk_result(err);
+ err = vkMapMemory(v->Device, rb->IndexBufferMemory, 0, rb->IndexBufferSize, 0, (void**)(&idx_dst));
+ check_vk_result(err);
+ for (int n = 0; n < draw_data->CmdListsCount; n++)
+ {
+ const ImDrawList* cmd_list = draw_data->CmdLists[n];
+ memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
+ memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
+ vtx_dst += cmd_list->VtxBuffer.Size;
+ idx_dst += cmd_list->IdxBuffer.Size;
+ }
+ VkMappedMemoryRange range[2] = {};
+ range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
+ range[0].memory = rb->VertexBufferMemory;
+ range[0].size = VK_WHOLE_SIZE;
+ range[1].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
+ range[1].memory = rb->IndexBufferMemory;
+ range[1].size = VK_WHOLE_SIZE;
+ err = vkFlushMappedMemoryRanges(v->Device, 2, range);
+ check_vk_result(err);
+ vkUnmapMemory(v->Device, rb->VertexBufferMemory);
+ vkUnmapMemory(v->Device, rb->IndexBufferMemory);
+ }
+
+ // Setup desired Vulkan state
+ ImGui_ImplVulkan_SetupRenderState(draw_data, pipeline, command_buffer, rb, fb_width, fb_height);
+
+ // Will project scissor/clipping rectangles into framebuffer space
+ ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
+ ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2)
+
+ // Render command lists
+ // (Because we merged all buffers into a single one, we maintain our own offset into them)
+ int global_vtx_offset = 0;
+ int global_idx_offset = 0;
+ for (int n = 0; n < draw_data->CmdListsCount; n++)
+ {
+ const ImDrawList* cmd_list = draw_data->CmdLists[n];
+ for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
+ {
+ const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
+ if (pcmd->UserCallback != NULL)
+ {
+ // User callback, registered via ImDrawList::AddCallback()
+ // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
+ if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
+ ImGui_ImplVulkan_SetupRenderState(draw_data, pipeline, command_buffer, rb, fb_width, fb_height);
+ else
+ pcmd->UserCallback(cmd_list, pcmd);
+ }
+ else
+ {
+ // Project scissor/clipping rectangles into framebuffer space
+ ImVec4 clip_rect;
+ clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x;
+ clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y;
+ clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x;
+ clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y;
+
+ if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f)
+ {
+ // Negative offsets are illegal for vkCmdSetScissor
+ if (clip_rect.x < 0.0f)
+ clip_rect.x = 0.0f;
+ if (clip_rect.y < 0.0f)
+ clip_rect.y = 0.0f;
+
+ // Apply scissor/clipping rectangle
+ VkRect2D scissor;
+ scissor.offset.x = (int32_t)(clip_rect.x);
+ scissor.offset.y = (int32_t)(clip_rect.y);
+ scissor.extent.width = (uint32_t)(clip_rect.z - clip_rect.x);
+ scissor.extent.height = (uint32_t)(clip_rect.w - clip_rect.y);
+ vkCmdSetScissor(command_buffer, 0, 1, &scissor);
+
+ // Draw
+ vkCmdDrawIndexed(command_buffer, pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0);
+ }
+ }
+ }
+ global_idx_offset += cmd_list->IdxBuffer.Size;
+ global_vtx_offset += cmd_list->VtxBuffer.Size;
+ }
+}
+
+bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer)
+{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
+ ImGuiIO& io = ImGui::GetIO();
+
+ unsigned char* pixels;
+ int width, height;
+ io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
+ size_t upload_size = width * height * 4 * sizeof(char);
+
+ VkResult err;
+
+ // Create the Image:
+ {
+ VkImageCreateInfo info = {};
+ info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
+ info.imageType = VK_IMAGE_TYPE_2D;
+ info.format = VK_FORMAT_R8G8B8A8_UNORM;
+ info.extent.width = width;
+ info.extent.height = height;
+ info.extent.depth = 1;
+ info.mipLevels = 1;
+ info.arrayLayers = 1;
+ info.samples = VK_SAMPLE_COUNT_1_BIT;
+ info.tiling = VK_IMAGE_TILING_OPTIMAL;
+ info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+ info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+ info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ err = vkCreateImage(v->Device, &info, v->Allocator, &g_FontImage);
+ check_vk_result(err);
+ VkMemoryRequirements req;
+ vkGetImageMemoryRequirements(v->Device, g_FontImage, &req);
+ VkMemoryAllocateInfo alloc_info = {};
+ alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+ alloc_info.allocationSize = req.size;
+ alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, req.memoryTypeBits);
+ err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &g_FontMemory);
+ check_vk_result(err);
+ err = vkBindImageMemory(v->Device, g_FontImage, g_FontMemory, 0);
+ check_vk_result(err);
+ }
+
+ // Create the Image View:
+ {
+ VkImageViewCreateInfo info = {};
+ info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+ info.image = g_FontImage;
+ info.viewType = VK_IMAGE_VIEW_TYPE_2D;
+ info.format = VK_FORMAT_R8G8B8A8_UNORM;
+ info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ info.subresourceRange.levelCount = 1;
+ info.subresourceRange.layerCount = 1;
+ err = vkCreateImageView(v->Device, &info, v->Allocator, &g_FontView);
+ check_vk_result(err);
+ }
+
+ // Update the Descriptor Set:
+ {
+ VkDescriptorImageInfo desc_image[1] = {};
+ desc_image[0].sampler = g_FontSampler;
+ desc_image[0].imageView = g_FontView;
+ desc_image[0].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+ VkWriteDescriptorSet write_desc[1] = {};
+ write_desc[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ write_desc[0].dstSet = g_DescriptorSet;
+ write_desc[0].descriptorCount = 1;
+ write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+ write_desc[0].pImageInfo = desc_image;
+ vkUpdateDescriptorSets(v->Device, 1, write_desc, 0, NULL);
+ }
+
+ // Create the Upload Buffer:
+ {
+ VkBufferCreateInfo buffer_info = {};
+ buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+ buffer_info.size = upload_size;
+ buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
+ buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+ err = vkCreateBuffer(v->Device, &buffer_info, v->Allocator, &g_UploadBuffer);
+ check_vk_result(err);
+ VkMemoryRequirements req;
+ vkGetBufferMemoryRequirements(v->Device, g_UploadBuffer, &req);
+ g_BufferMemoryAlignment = (g_BufferMemoryAlignment > req.alignment) ? g_BufferMemoryAlignment : req.alignment;
+ VkMemoryAllocateInfo alloc_info = {};
+ alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+ alloc_info.allocationSize = req.size;
+ alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits);
+ err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &g_UploadBufferMemory);
+ check_vk_result(err);
+ err = vkBindBufferMemory(v->Device, g_UploadBuffer, g_UploadBufferMemory, 0);
+ check_vk_result(err);
+ }
+
+ // Upload to Buffer:
+ {
+ char* map = NULL;
+ err = vkMapMemory(v->Device, g_UploadBufferMemory, 0, upload_size, 0, (void**)(&map));
+ check_vk_result(err);
+ memcpy(map, pixels, upload_size);
+ VkMappedMemoryRange range[1] = {};
+ range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
+ range[0].memory = g_UploadBufferMemory;
+ range[0].size = upload_size;
+ err = vkFlushMappedMemoryRanges(v->Device, 1, range);
+ check_vk_result(err);
+ vkUnmapMemory(v->Device, g_UploadBufferMemory);
+ }
+
+ // Copy to Image:
+ {
+ VkImageMemoryBarrier copy_barrier[1] = {};
+ copy_barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+ copy_barrier[0].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+ copy_barrier[0].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ copy_barrier[0].newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
+ copy_barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ copy_barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ copy_barrier[0].image = g_FontImage;
+ copy_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ copy_barrier[0].subresourceRange.levelCount = 1;
+ copy_barrier[0].subresourceRange.layerCount = 1;
+ vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, copy_barrier);
+
+ VkBufferImageCopy region = {};
+ region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ region.imageSubresource.layerCount = 1;
+ region.imageExtent.width = width;
+ region.imageExtent.height = height;
+ region.imageExtent.depth = 1;
+ vkCmdCopyBufferToImage(command_buffer, g_UploadBuffer, g_FontImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
+
+ VkImageMemoryBarrier use_barrier[1] = {};
+ use_barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+ use_barrier[0].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+ use_barrier[0].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
+ use_barrier[0].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
+ use_barrier[0].newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+ use_barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ use_barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ use_barrier[0].image = g_FontImage;
+ use_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ use_barrier[0].subresourceRange.levelCount = 1;
+ use_barrier[0].subresourceRange.layerCount = 1;
+ vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, use_barrier);
+ }
+
+ // Store our identifier
+ io.Fonts->SetTexID((ImTextureID)(intptr_t)g_FontImage);
+
+ return true;
+}
+
+static void ImGui_ImplVulkan_CreateShaderModules(VkDevice device, const VkAllocationCallbacks* allocator)
+{
+ // Create the shader modules
+ if (g_ShaderModuleVert == NULL)
+ {
+ VkShaderModuleCreateInfo vert_info = {};
+ vert_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
+ vert_info.codeSize = sizeof(__glsl_shader_vert_spv);
+ vert_info.pCode = (uint32_t*)__glsl_shader_vert_spv;
+ VkResult err = vkCreateShaderModule(device, &vert_info, allocator, &g_ShaderModuleVert);
+ check_vk_result(err);
+ }
+ if (g_ShaderModuleFrag == NULL)
+ {
+ VkShaderModuleCreateInfo frag_info = {};
+ frag_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
+ frag_info.codeSize = sizeof(__glsl_shader_frag_spv);
+ frag_info.pCode = (uint32_t*)__glsl_shader_frag_spv;
+ VkResult err = vkCreateShaderModule(device, &frag_info, allocator, &g_ShaderModuleFrag);
+ check_vk_result(err);
+ }
+}
+
+static void ImGui_ImplVulkan_CreateFontSampler(VkDevice device, const VkAllocationCallbacks* allocator)
+{
+ if (g_FontSampler)
+ return;
+
+ VkSamplerCreateInfo info = {};
+ info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
+ info.magFilter = VK_FILTER_LINEAR;
+ info.minFilter = VK_FILTER_LINEAR;
+ info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
+ info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
+ info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
+ info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
+ info.minLod = -1000;
+ info.maxLod = 1000;
+ info.maxAnisotropy = 1.0f;
+ VkResult err = vkCreateSampler(device, &info, allocator, &g_FontSampler);
+ check_vk_result(err);
+}
+
+static void ImGui_ImplVulkan_CreateDescriptorSetLayout(VkDevice device, const VkAllocationCallbacks* allocator)
+{
+ if (g_DescriptorSetLayout)
+ return;
+
+ ImGui_ImplVulkan_CreateFontSampler(device, allocator);
+ VkSampler sampler[1] = { g_FontSampler };
+ VkDescriptorSetLayoutBinding binding[1] = {};
+ binding[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+ binding[0].descriptorCount = 1;
+ binding[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
+ binding[0].pImmutableSamplers = sampler;
+ VkDescriptorSetLayoutCreateInfo info = {};
+ info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
+ info.bindingCount = 1;
+ info.pBindings = binding;
+ VkResult err = vkCreateDescriptorSetLayout(device, &info, allocator, &g_DescriptorSetLayout);
+ check_vk_result(err);
+}
+
+static void ImGui_ImplVulkan_CreatePipelineLayout(VkDevice device, const VkAllocationCallbacks* allocator)
+{
+ if (g_PipelineLayout)
+ return;
+
+ // Constants: we are using 'vec2 offset' and 'vec2 scale' instead of a full 3d projection matrix
+ ImGui_ImplVulkan_CreateDescriptorSetLayout(device, allocator);
+ VkPushConstantRange push_constants[1] = {};
+ push_constants[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
+ push_constants[0].offset = sizeof(float) * 0;
+ push_constants[0].size = sizeof(float) * 4;
+ VkDescriptorSetLayout set_layout[1] = { g_DescriptorSetLayout };
+ VkPipelineLayoutCreateInfo layout_info = {};
+ layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+ layout_info.setLayoutCount = 1;
+ layout_info.pSetLayouts = set_layout;
+ layout_info.pushConstantRangeCount = 1;
+ layout_info.pPushConstantRanges = push_constants;
+ VkResult err = vkCreatePipelineLayout(device, &layout_info, allocator, &g_PipelineLayout);
+ check_vk_result(err);
+}
+
+static void ImGui_ImplVulkan_CreatePipeline(VkDevice device, const VkAllocationCallbacks* allocator, VkPipelineCache pipelineCache, VkRenderPass renderPass, VkSampleCountFlagBits MSAASamples, VkPipeline* pipeline, uint32_t subpass)
+{
+ ImGui_ImplVulkan_CreateShaderModules(device, allocator);
+
+ VkPipelineShaderStageCreateInfo stage[2] = {};
+ stage[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ stage[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
+ stage[0].module = g_ShaderModuleVert;
+ stage[0].pName = "main";
+ stage[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ stage[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
+ stage[1].module = g_ShaderModuleFrag;
+ stage[1].pName = "main";
+
+ VkVertexInputBindingDescription binding_desc[1] = {};
+ binding_desc[0].stride = sizeof(ImDrawVert);
+ binding_desc[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
+
+ VkVertexInputAttributeDescription attribute_desc[3] = {};
+ attribute_desc[0].location = 0;
+ attribute_desc[0].binding = binding_desc[0].binding;
+ attribute_desc[0].format = VK_FORMAT_R32G32_SFLOAT;
+ attribute_desc[0].offset = IM_OFFSETOF(ImDrawVert, pos);
+ attribute_desc[1].location = 1;
+ attribute_desc[1].binding = binding_desc[0].binding;
+ attribute_desc[1].format = VK_FORMAT_R32G32_SFLOAT;
+ attribute_desc[1].offset = IM_OFFSETOF(ImDrawVert, uv);
+ attribute_desc[2].location = 2;
+ attribute_desc[2].binding = binding_desc[0].binding;
+ attribute_desc[2].format = VK_FORMAT_R8G8B8A8_UNORM;
+ attribute_desc[2].offset = IM_OFFSETOF(ImDrawVert, col);
+
+ VkPipelineVertexInputStateCreateInfo vertex_info = {};
+ vertex_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
+ vertex_info.vertexBindingDescriptionCount = 1;
+ vertex_info.pVertexBindingDescriptions = binding_desc;
+ vertex_info.vertexAttributeDescriptionCount = 3;
+ vertex_info.pVertexAttributeDescriptions = attribute_desc;
+
+ VkPipelineInputAssemblyStateCreateInfo ia_info = {};
+ ia_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
+ ia_info.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
+
+ VkPipelineViewportStateCreateInfo viewport_info = {};
+ viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
+ viewport_info.viewportCount = 1;
+ viewport_info.scissorCount = 1;
+
+ VkPipelineRasterizationStateCreateInfo raster_info = {};
+ raster_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
+ raster_info.polygonMode = VK_POLYGON_MODE_FILL;
+ raster_info.cullMode = VK_CULL_MODE_NONE;
+ raster_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
+ raster_info.lineWidth = 1.0f;
+
+ VkPipelineMultisampleStateCreateInfo ms_info = {};
+ ms_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
+ ms_info.rasterizationSamples = (MSAASamples != 0) ? MSAASamples : VK_SAMPLE_COUNT_1_BIT;
+
+ VkPipelineColorBlendAttachmentState color_attachment[1] = {};
+ color_attachment[0].blendEnable = VK_TRUE;
+ color_attachment[0].srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
+ color_attachment[0].dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+ color_attachment[0].colorBlendOp = VK_BLEND_OP_ADD;
+ color_attachment[0].srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
+ color_attachment[0].dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+ color_attachment[0].alphaBlendOp = VK_BLEND_OP_ADD;
+ color_attachment[0].colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
+
+ VkPipelineDepthStencilStateCreateInfo depth_info = {};
+ depth_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
+
+ VkPipelineColorBlendStateCreateInfo blend_info = {};
+ blend_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
+ blend_info.attachmentCount = 1;
+ blend_info.pAttachments = color_attachment;
+
+ VkDynamicState dynamic_states[2] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
+ VkPipelineDynamicStateCreateInfo dynamic_state = {};
+ dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
+ dynamic_state.dynamicStateCount = (uint32_t)IM_ARRAYSIZE(dynamic_states);
+ dynamic_state.pDynamicStates = dynamic_states;
+
+ ImGui_ImplVulkan_CreatePipelineLayout(device, allocator);
+
+ VkGraphicsPipelineCreateInfo info = {};
+ info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
+ info.flags = g_PipelineCreateFlags;
+ info.stageCount = 2;
+ info.pStages = stage;
+ info.pVertexInputState = &vertex_info;
+ info.pInputAssemblyState = &ia_info;
+ info.pViewportState = &viewport_info;
+ info.pRasterizationState = &raster_info;
+ info.pMultisampleState = &ms_info;
+ info.pDepthStencilState = &depth_info;
+ info.pColorBlendState = &blend_info;
+ info.pDynamicState = &dynamic_state;
+ info.layout = g_PipelineLayout;
+ info.renderPass = renderPass;
+ info.subpass = subpass;
+ VkResult err = vkCreateGraphicsPipelines(device, pipelineCache, 1, &info, allocator, pipeline);
+ check_vk_result(err);
+}
+
+bool ImGui_ImplVulkan_CreateDeviceObjects()
+{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
+ VkResult err;
+
+ if (!g_FontSampler)
+ {
+ VkSamplerCreateInfo info = {};
+ info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
+ info.magFilter = VK_FILTER_LINEAR;
+ info.minFilter = VK_FILTER_LINEAR;
+ info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
+ info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
+ info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
+ info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
+ info.minLod = -1000;
+ info.maxLod = 1000;
+ info.maxAnisotropy = 1.0f;
+ err = vkCreateSampler(v->Device, &info, v->Allocator, &g_FontSampler);
+ check_vk_result(err);
+ }
+
+ if (!g_DescriptorSetLayout)
+ {
+ VkSampler sampler[1] = {g_FontSampler};
+ VkDescriptorSetLayoutBinding binding[1] = {};
+ binding[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+ binding[0].descriptorCount = 1;
+ binding[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
+ binding[0].pImmutableSamplers = sampler;
+ VkDescriptorSetLayoutCreateInfo info = {};
+ info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
+ info.bindingCount = 1;
+ info.pBindings = binding;
+ err = vkCreateDescriptorSetLayout(v->Device, &info, v->Allocator, &g_DescriptorSetLayout);
+ check_vk_result(err);
+ }
+
+ // Create Descriptor Set:
+ {
+ VkDescriptorSetAllocateInfo alloc_info = {};
+ alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
+ alloc_info.descriptorPool = v->DescriptorPool;
+ alloc_info.descriptorSetCount = 1;
+ alloc_info.pSetLayouts = &g_DescriptorSetLayout;
+ err = vkAllocateDescriptorSets(v->Device, &alloc_info, &g_DescriptorSet);
+ check_vk_result(err);
+ }
+
+ if (!g_PipelineLayout)
+ {
+ // Constants: we are using 'vec2 offset' and 'vec2 scale' instead of a full 3d projection matrix
+ VkPushConstantRange push_constants[1] = {};
+ push_constants[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
+ push_constants[0].offset = sizeof(float) * 0;
+ push_constants[0].size = sizeof(float) * 4;
+ VkDescriptorSetLayout set_layout[1] = { g_DescriptorSetLayout };
+ VkPipelineLayoutCreateInfo layout_info = {};
+ layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+ layout_info.setLayoutCount = 1;
+ layout_info.pSetLayouts = set_layout;
+ layout_info.pushConstantRangeCount = 1;
+ layout_info.pPushConstantRanges = push_constants;
+ err = vkCreatePipelineLayout(v->Device, &layout_info, v->Allocator, &g_PipelineLayout);
+ check_vk_result(err);
+ }
+
+ ImGui_ImplVulkan_CreatePipeline(v->Device, v->Allocator, v->PipelineCache, g_RenderPass, v->MSAASamples, &g_Pipeline, g_Subpass);
+
+ return true;
+}
+
+void ImGui_ImplVulkan_DestroyFontUploadObjects()
+{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
+ if (g_UploadBuffer)
+ {
+ vkDestroyBuffer(v->Device, g_UploadBuffer, v->Allocator);
+ g_UploadBuffer = VK_NULL_HANDLE;
+ }
+ if (g_UploadBufferMemory)
+ {
+ vkFreeMemory(v->Device, g_UploadBufferMemory, v->Allocator);
+ g_UploadBufferMemory = VK_NULL_HANDLE;
+ }
+}
+
+void ImGui_ImplVulkan_DestroyDeviceObjects()
+{
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
+ ImGui_ImplVulkanH_DestroyWindowRenderBuffers(v->Device, &g_MainWindowRenderBuffers, v->Allocator);
+ ImGui_ImplVulkan_DestroyFontUploadObjects();
+
+ if (g_ShaderModuleVert) { vkDestroyShaderModule(v->Device, g_ShaderModuleVert, v->Allocator); g_ShaderModuleVert = VK_NULL_HANDLE; }
+ if (g_ShaderModuleFrag) { vkDestroyShaderModule(v->Device, g_ShaderModuleFrag, v->Allocator); g_ShaderModuleFrag = VK_NULL_HANDLE; }
+ if (g_FontView) { vkDestroyImageView(v->Device, g_FontView, v->Allocator); g_FontView = VK_NULL_HANDLE; }
+ if (g_FontImage) { vkDestroyImage(v->Device, g_FontImage, v->Allocator); g_FontImage = VK_NULL_HANDLE; }
+ if (g_FontMemory) { vkFreeMemory(v->Device, g_FontMemory, v->Allocator); g_FontMemory = VK_NULL_HANDLE; }
+ if (g_FontSampler) { vkDestroySampler(v->Device, g_FontSampler, v->Allocator); g_FontSampler = VK_NULL_HANDLE; }
+ if (g_DescriptorSetLayout) { vkDestroyDescriptorSetLayout(v->Device, g_DescriptorSetLayout, v->Allocator); g_DescriptorSetLayout = VK_NULL_HANDLE; }
+ if (g_PipelineLayout) { vkDestroyPipelineLayout(v->Device, g_PipelineLayout, v->Allocator); g_PipelineLayout = VK_NULL_HANDLE; }
+ if (g_Pipeline) { vkDestroyPipeline(v->Device, g_Pipeline, v->Allocator); g_Pipeline = VK_NULL_HANDLE; }
+}
+
+bool ImGui_ImplVulkan_LoadFunctions(PFN_vkVoidFunction(*loader_func)(const char* function_name, void* user_data), void* user_data)
+{
+ // Load function pointers
+ // You can use the default Vulkan loader using:
+ // ImGui_ImplVulkan_LoadFunctions([](const char* function_name, void*) { return vkGetInstanceProcAddr(your_vk_isntance, function_name); });
+ // But this would be equivalent to not setting VK_NO_PROTOTYPES.
+#ifdef VK_NO_PROTOTYPES
+#define IMGUI_VULKAN_FUNC_LOAD(func) \
+ func = reinterpret_cast<decltype(func)>(loader_func(#func, user_data)); \
+ if (func == NULL) \
+ return false;
+ IMGUI_VULKAN_FUNC_MAP(IMGUI_VULKAN_FUNC_LOAD)
+#undef IMGUI_VULKAN_FUNC_LOAD
+#else
+ IM_UNUSED(loader_func);
+ IM_UNUSED(user_data);
+#endif
+ g_FunctionsLoaded = true;
+ return true;
+}
+
+bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass render_pass)
+{
+ IM_ASSERT(g_FunctionsLoaded && "Need to call ImGui_ImplVulkan_LoadFunctions() if IMGUI_IMPL_VULKAN_NO_PROTOTYPES or VK_NO_PROTOTYPES are set!");
+
+ // Setup backend capabilities flags
+ ImGuiIO& io = ImGui::GetIO();
+ io.BackendRendererName = "imgui_impl_vulkan";
+ io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
+
+ IM_ASSERT(info->Instance != VK_NULL_HANDLE);
+ IM_ASSERT(info->PhysicalDevice != VK_NULL_HANDLE);
+ IM_ASSERT(info->Device != VK_NULL_HANDLE);
+ IM_ASSERT(info->Queue != VK_NULL_HANDLE);
+ IM_ASSERT(info->DescriptorPool != VK_NULL_HANDLE);
+ IM_ASSERT(info->MinImageCount >= 2);
+ IM_ASSERT(info->ImageCount >= info->MinImageCount);
+ IM_ASSERT(render_pass != VK_NULL_HANDLE);
+
+ g_VulkanInitInfo = *info;
+ g_RenderPass = render_pass;
+ g_Subpass = info->Subpass;
+
+ ImGui_ImplVulkan_CreateDeviceObjects();
+
+ return true;
+}
+
+void ImGui_ImplVulkan_Shutdown()
+{
+ ImGui_ImplVulkan_DestroyDeviceObjects();
+}
+
+void ImGui_ImplVulkan_NewFrame()
+{
+}
+
+void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count)
+{
+ IM_ASSERT(min_image_count >= 2);
+ if (g_VulkanInitInfo.MinImageCount == min_image_count)
+ return;
+
+ ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
+ VkResult err = vkDeviceWaitIdle(v->Device);
+ check_vk_result(err);
+ ImGui_ImplVulkanH_DestroyWindowRenderBuffers(v->Device, &g_MainWindowRenderBuffers, v->Allocator);
+ g_VulkanInitInfo.MinImageCount = min_image_count;
+}
+
+
+//-------------------------------------------------------------------------
+// Internal / Miscellaneous Vulkan Helpers
+// (Used by example's main.cpp. Used by multi-viewport features. PROBABLY NOT used by your own app.)
+//-------------------------------------------------------------------------
+// You probably do NOT need to use or care about those functions.
+// Those functions only exist because:
+// 1) they facilitate the readability and maintenance of the multiple main.cpp examples files.
+// 2) the upcoming multi-viewport feature will need them internally.
+// Generally we avoid exposing any kind of superfluous high-level helpers in the backends,
+// but it is too much code to duplicate everywhere so we exceptionally expose them.
+//
+// Your engine/app will likely _already_ have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
+// You may read this code to learn about Vulkan, but it is recommended you use you own custom tailored code to do equivalent work.
+// (The ImGui_ImplVulkanH_XXX functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)
+//-------------------------------------------------------------------------
+
+VkSurfaceFormatKHR ImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkFormat* request_formats, int request_formats_count, VkColorSpaceKHR request_color_space)
+{
+ IM_ASSERT(g_FunctionsLoaded && "Need to call ImGui_ImplVulkan_LoadFunctions() if IMGUI_IMPL_VULKAN_NO_PROTOTYPES or VK_NO_PROTOTYPES are set!");
+ IM_ASSERT(request_formats != NULL);
+ IM_ASSERT(request_formats_count > 0);
+
+ // Per Spec Format and View Format are expected to be the same unless VK_IMAGE_CREATE_MUTABLE_BIT was set at image creation
+ // Assuming that the default behavior is without setting this bit, there is no need for separate Swapchain image and image view format
+ // Additionally several new color spaces were introduced with Vulkan Spec v1.0.40,
+ // hence we must make sure that a format with the mostly available color space, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, is found and used.
+ uint32_t avail_count;
+ vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &avail_count, NULL);
+ ImVector<VkSurfaceFormatKHR> avail_format;
+ avail_format.resize((int)avail_count);
+ vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &avail_count, avail_format.Data);
+
+ // First check if only one format, VK_FORMAT_UNDEFINED, is available, which would imply that any format is available
+ if (avail_count == 1)
+ {
+ if (avail_format[0].format == VK_FORMAT_UNDEFINED)
+ {
+ VkSurfaceFormatKHR ret;
+ ret.format = request_formats[0];
+ ret.colorSpace = request_color_space;
+ return ret;
+ }
+ else
+ {
+ // No point in searching another format
+ return avail_format[0];
+ }
+ }
+ else
+ {
+ // Request several formats, the first found will be used
+ for (int request_i = 0; request_i < request_formats_count; request_i++)
+ for (uint32_t avail_i = 0; avail_i < avail_count; avail_i++)
+ if (avail_format[avail_i].format == request_formats[request_i] && avail_format[avail_i].colorSpace == request_color_space)
+ return avail_format[avail_i];
+
+ // If none of the requested image formats could be found, use the first available
+ return avail_format[0];
+ }
+}
+
+VkPresentModeKHR ImGui_ImplVulkanH_SelectPresentMode(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkPresentModeKHR* request_modes, int request_modes_count)
+{
+ IM_ASSERT(g_FunctionsLoaded && "Need to call ImGui_ImplVulkan_LoadFunctions() if IMGUI_IMPL_VULKAN_NO_PROTOTYPES or VK_NO_PROTOTYPES are set!");
+ IM_ASSERT(request_modes != NULL);
+ IM_ASSERT(request_modes_count > 0);
+
+ // Request a certain mode and confirm that it is available. If not use VK_PRESENT_MODE_FIFO_KHR which is mandatory
+ uint32_t avail_count = 0;
+ vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &avail_count, NULL);
+ ImVector<VkPresentModeKHR> avail_modes;
+ avail_modes.resize((int)avail_count);
+ vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &avail_count, avail_modes.Data);
+ //for (uint32_t avail_i = 0; avail_i < avail_count; avail_i++)
+ // printf("[vulkan] avail_modes[%d] = %d\n", avail_i, avail_modes[avail_i]);
+
+ for (int request_i = 0; request_i < request_modes_count; request_i++)
+ for (uint32_t avail_i = 0; avail_i < avail_count; avail_i++)
+ if (request_modes[request_i] == avail_modes[avail_i])
+ return request_modes[request_i];
+
+ return VK_PRESENT_MODE_FIFO_KHR; // Always available
+}
+
+void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator)
+{
+ IM_ASSERT(physical_device != VK_NULL_HANDLE && device != VK_NULL_HANDLE);
+ (void)physical_device;
+ (void)allocator;
+
+ // Create Command Buffers
+ VkResult err;
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
+ {
+ ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i];
+ ImGui_ImplVulkanH_FrameSemaphores* fsd = &wd->FrameSemaphores[i];
+ {
+ VkCommandPoolCreateInfo info = {};
+ info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
+ info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
+ info.queueFamilyIndex = queue_family;
+ err = vkCreateCommandPool(device, &info, allocator, &fd->CommandPool);
+ check_vk_result(err);
+ }
+ {
+ VkCommandBufferAllocateInfo info = {};
+ info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
+ info.commandPool = fd->CommandPool;
+ info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
+ info.commandBufferCount = 1;
+ err = vkAllocateCommandBuffers(device, &info, &fd->CommandBuffer);
+ check_vk_result(err);
+ }
+ {
+ VkFenceCreateInfo info = {};
+ info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
+ info.flags = VK_FENCE_CREATE_SIGNALED_BIT;
+ err = vkCreateFence(device, &info, allocator, &fd->Fence);
+ check_vk_result(err);
+ }
+ {
+ VkSemaphoreCreateInfo info = {};
+ info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
+ err = vkCreateSemaphore(device, &info, allocator, &fsd->ImageAcquiredSemaphore);
+ check_vk_result(err);
+ err = vkCreateSemaphore(device, &info, allocator, &fsd->RenderCompleteSemaphore);
+ check_vk_result(err);
+ }
+ }
+}
+
+int ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(VkPresentModeKHR present_mode)
+{
+ if (present_mode == VK_PRESENT_MODE_MAILBOX_KHR)
+ return 3;
+ if (present_mode == VK_PRESENT_MODE_FIFO_KHR || present_mode == VK_PRESENT_MODE_FIFO_RELAXED_KHR)
+ return 2;
+ if (present_mode == VK_PRESENT_MODE_IMMEDIATE_KHR)
+ return 1;
+ IM_ASSERT(0);
+ return 1;
+}
+
+// Also destroy old swap chain and in-flight frames data, if any.
+void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count)
+{
+ VkResult err;
+ VkSwapchainKHR old_swapchain = wd->Swapchain;
+ wd->Swapchain = NULL;
+ err = vkDeviceWaitIdle(device);
+ check_vk_result(err);
+
+ // We don't use ImGui_ImplVulkanH_DestroyWindow() because we want to preserve the old swapchain to create the new one.
+ // Destroy old Framebuffer
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
+ {
+ ImGui_ImplVulkanH_DestroyFrame(device, &wd->Frames[i], allocator);
+ ImGui_ImplVulkanH_DestroyFrameSemaphores(device, &wd->FrameSemaphores[i], allocator);
+ }
+ IM_FREE(wd->Frames);
+ IM_FREE(wd->FrameSemaphores);
+ wd->Frames = NULL;
+ wd->FrameSemaphores = NULL;
+ wd->ImageCount = 0;
+ if (wd->RenderPass)
+ vkDestroyRenderPass(device, wd->RenderPass, allocator);
+ if (wd->Pipeline)
+ vkDestroyPipeline(device, wd->Pipeline, allocator);
+
+ // If min image count was not specified, request different count of images dependent on selected present mode
+ if (min_image_count == 0)
+ min_image_count = ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(wd->PresentMode);
+
+ // Create Swapchain
+ {
+ VkSwapchainCreateInfoKHR info = {};
+ info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
+ info.surface = wd->Surface;
+ info.minImageCount = min_image_count;
+ info.imageFormat = wd->SurfaceFormat.format;
+ info.imageColorSpace = wd->SurfaceFormat.colorSpace;
+ info.imageArrayLayers = 1;
+ info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+ info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; // Assume that graphics family == present family
+ info.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
+ info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
+ info.presentMode = wd->PresentMode;
+ info.clipped = VK_TRUE;
+ info.oldSwapchain = old_swapchain;
+ VkSurfaceCapabilitiesKHR cap;
+ err = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, wd->Surface, &cap);
+ check_vk_result(err);
+ if (info.minImageCount < cap.minImageCount)
+ info.minImageCount = cap.minImageCount;
+ else if (cap.maxImageCount != 0 && info.minImageCount > cap.maxImageCount)
+ info.minImageCount = cap.maxImageCount;
+
+ if (cap.currentExtent.width == 0xffffffff)
+ {
+ info.imageExtent.width = wd->Width = w;
+ info.imageExtent.height = wd->Height = h;
+ }
+ else
+ {
+ info.imageExtent.width = wd->Width = cap.currentExtent.width;
+ info.imageExtent.height = wd->Height = cap.currentExtent.height;
+ }
+ err = vkCreateSwapchainKHR(device, &info, allocator, &wd->Swapchain);
+ check_vk_result(err);
+ err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->ImageCount, NULL);
+ check_vk_result(err);
+ VkImage backbuffers[16] = {};
+ IM_ASSERT(wd->ImageCount >= min_image_count);
+ IM_ASSERT(wd->ImageCount < IM_ARRAYSIZE(backbuffers));
+ err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->ImageCount, backbuffers);
+ check_vk_result(err);
+
+ IM_ASSERT(wd->Frames == NULL);
+ wd->Frames = (ImGui_ImplVulkanH_Frame*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_Frame) * wd->ImageCount);
+ wd->FrameSemaphores = (ImGui_ImplVulkanH_FrameSemaphores*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_FrameSemaphores) * wd->ImageCount);
+ memset(wd->Frames, 0, sizeof(wd->Frames[0]) * wd->ImageCount);
+ memset(wd->FrameSemaphores, 0, sizeof(wd->FrameSemaphores[0]) * wd->ImageCount);
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
+ wd->Frames[i].Backbuffer = backbuffers[i];
+ }
+ if (old_swapchain)
+ vkDestroySwapchainKHR(device, old_swapchain, allocator);
+
+ // Create the Render Pass
+ {
+ VkAttachmentDescription attachment = {};
+ attachment.format = wd->SurfaceFormat.format;
+ attachment.samples = VK_SAMPLE_COUNT_1_BIT;
+ attachment.loadOp = wd->ClearEnable ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+ attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+ attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
+ VkAttachmentReference color_attachment = {};
+ color_attachment.attachment = 0;
+ color_attachment.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+ VkSubpassDescription subpass = {};
+ subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
+ subpass.colorAttachmentCount = 1;
+ subpass.pColorAttachments = &color_attachment;
+ VkSubpassDependency dependency = {};
+ dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
+ dependency.dstSubpass = 0;
+ dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ dependency.srcAccessMask = 0;
+ dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+ VkRenderPassCreateInfo info = {};
+ info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
+ info.attachmentCount = 1;
+ info.pAttachments = &attachment;
+ info.subpassCount = 1;
+ info.pSubpasses = &subpass;
+ info.dependencyCount = 1;
+ info.pDependencies = &dependency;
+ err = vkCreateRenderPass(device, &info, allocator, &wd->RenderPass);
+ check_vk_result(err);
+
+ // We do not create a pipeline by default as this is also used by examples' main.cpp,
+ // but secondary viewport in multi-viewport mode may want to create one with:
+ //ImGui_ImplVulkan_CreatePipeline(device, allocator, VK_NULL_HANDLE, wd->RenderPass, VK_SAMPLE_COUNT_1_BIT, &wd->Pipeline, g_Subpass);
+ }
+
+ // Create The Image Views
+ {
+ VkImageViewCreateInfo info = {};
+ info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+ info.viewType = VK_IMAGE_VIEW_TYPE_2D;
+ info.format = wd->SurfaceFormat.format;
+ info.components.r = VK_COMPONENT_SWIZZLE_R;
+ info.components.g = VK_COMPONENT_SWIZZLE_G;
+ info.components.b = VK_COMPONENT_SWIZZLE_B;
+ info.components.a = VK_COMPONENT_SWIZZLE_A;
+ VkImageSubresourceRange image_range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
+ info.subresourceRange = image_range;
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
+ {
+ ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i];
+ info.image = fd->Backbuffer;
+ err = vkCreateImageView(device, &info, allocator, &fd->BackbufferView);
+ check_vk_result(err);
+ }
+ }
+
+ // Create Framebuffer
+ {
+ VkImageView attachment[1];
+ VkFramebufferCreateInfo info = {};
+ info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
+ info.renderPass = wd->RenderPass;
+ info.attachmentCount = 1;
+ info.pAttachments = attachment;
+ info.width = wd->Width;
+ info.height = wd->Height;
+ info.layers = 1;
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
+ {
+ ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i];
+ attachment[0] = fd->BackbufferView;
+ err = vkCreateFramebuffer(device, &info, allocator, &fd->Framebuffer);
+ check_vk_result(err);
+ }
+ }
+}
+
+// Create or resize window
+void ImGui_ImplVulkanH_CreateOrResizeWindow(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int width, int height, uint32_t min_image_count)
+{
+ IM_ASSERT(g_FunctionsLoaded && "Need to call ImGui_ImplVulkan_LoadFunctions() if IMGUI_IMPL_VULKAN_NO_PROTOTYPES or VK_NO_PROTOTYPES are set!");
+ (void)instance;
+ ImGui_ImplVulkanH_CreateWindowSwapChain(physical_device, device, wd, allocator, width, height, min_image_count);
+ ImGui_ImplVulkanH_CreateWindowCommandBuffers(physical_device, device, wd, queue_family, allocator);
+}
+
+void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator)
+{
+ vkDeviceWaitIdle(device); // FIXME: We could wait on the Queue if we had the queue in wd-> (otherwise VulkanH functions can't use globals)
+ //vkQueueWaitIdle(g_Queue);
+
+ for (uint32_t i = 0; i < wd->ImageCount; i++)
+ {
+ ImGui_ImplVulkanH_DestroyFrame(device, &wd->Frames[i], allocator);
+ ImGui_ImplVulkanH_DestroyFrameSemaphores(device, &wd->FrameSemaphores[i], allocator);
+ }
+ IM_FREE(wd->Frames);
+ IM_FREE(wd->FrameSemaphores);
+ wd->Frames = NULL;
+ wd->FrameSemaphores = NULL;
+ vkDestroyPipeline(device, wd->Pipeline, allocator);
+ vkDestroyRenderPass(device, wd->RenderPass, allocator);
+ vkDestroySwapchainKHR(device, wd->Swapchain, allocator);
+ vkDestroySurfaceKHR(instance, wd->Surface, allocator);
+
+ *wd = ImGui_ImplVulkanH_Window();
+}
+
+void ImGui_ImplVulkanH_DestroyFrame(VkDevice device, ImGui_ImplVulkanH_Frame* fd, const VkAllocationCallbacks* allocator)
+{
+ vkDestroyFence(device, fd->Fence, allocator);
+ vkFreeCommandBuffers(device, fd->CommandPool, 1, &fd->CommandBuffer);
+ vkDestroyCommandPool(device, fd->CommandPool, allocator);
+ fd->Fence = VK_NULL_HANDLE;
+ fd->CommandBuffer = VK_NULL_HANDLE;
+ fd->CommandPool = VK_NULL_HANDLE;
+
+ vkDestroyImageView(device, fd->BackbufferView, allocator);
+ vkDestroyFramebuffer(device, fd->Framebuffer, allocator);
+}
+
+void ImGui_ImplVulkanH_DestroyFrameSemaphores(VkDevice device, ImGui_ImplVulkanH_FrameSemaphores* fsd, const VkAllocationCallbacks* allocator)
+{
+ vkDestroySemaphore(device, fsd->ImageAcquiredSemaphore, allocator);
+ vkDestroySemaphore(device, fsd->RenderCompleteSemaphore, allocator);
+ fsd->ImageAcquiredSemaphore = fsd->RenderCompleteSemaphore = VK_NULL_HANDLE;
+}
+
+void ImGui_ImplVulkanH_DestroyFrameRenderBuffers(VkDevice device, ImGui_ImplVulkanH_FrameRenderBuffers* buffers, const VkAllocationCallbacks* allocator)
+{
+ if (buffers->VertexBuffer) { vkDestroyBuffer(device, buffers->VertexBuffer, allocator); buffers->VertexBuffer = VK_NULL_HANDLE; }
+ if (buffers->VertexBufferMemory) { vkFreeMemory(device, buffers->VertexBufferMemory, allocator); buffers->VertexBufferMemory = VK_NULL_HANDLE; }
+ if (buffers->IndexBuffer) { vkDestroyBuffer(device, buffers->IndexBuffer, allocator); buffers->IndexBuffer = VK_NULL_HANDLE; }
+ if (buffers->IndexBufferMemory) { vkFreeMemory(device, buffers->IndexBufferMemory, allocator); buffers->IndexBufferMemory = VK_NULL_HANDLE; }
+ buffers->VertexBufferSize = 0;
+ buffers->IndexBufferSize = 0;
+}
+
+void ImGui_ImplVulkanH_DestroyWindowRenderBuffers(VkDevice device, ImGui_ImplVulkanH_WindowRenderBuffers* buffers, const VkAllocationCallbacks* allocator)
+{
+ for (uint32_t n = 0; n < buffers->Count; n++)
+ ImGui_ImplVulkanH_DestroyFrameRenderBuffers(device, &buffers->FrameRenderBuffers[n], allocator);
+ IM_FREE(buffers->FrameRenderBuffers);
+ buffers->FrameRenderBuffers = NULL;
+ buffers->Index = 0;
+ buffers->Count = 0;
+}
diff --git a/3rdparty/imgui/backend/imgui_impl_vulkan.h b/3rdparty/imgui/backend/imgui_impl_vulkan.h
new file mode 100644
index 0000000..9f9010e
--- /dev/null
+++ b/3rdparty/imgui/backend/imgui_impl_vulkan.h
@@ -0,0 +1,148 @@
+// dear imgui: Renderer Backend for Vulkan
+// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
+
+// Implemented features:
+// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
+// Missing features:
+// [ ] Renderer: User texture binding. Changes of ImTextureID aren't supported by this backend! See https://github.com/ocornut/imgui/pull/914
+
+// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
+// Read online: https://github.com/ocornut/imgui/tree/master/docs
+
+// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification.
+// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
+
+// Important note to the reader who wish to integrate imgui_impl_vulkan.cpp/.h in their own engine/app.
+// - Common ImGui_ImplVulkan_XXX functions and structures are used to interface with imgui_impl_vulkan.cpp/.h.
+// You will use those if you want to use this rendering backend in your engine/app.
+// - Helper ImGui_ImplVulkanH_XXX functions and structures are only used by this example (main.cpp) and by
+// the backend itself (imgui_impl_vulkan.cpp), but should PROBABLY NOT be used by your own engine/app code.
+// Read comments in imgui_impl_vulkan.h.
+
+#pragma once
+#include "imgui.h" // IMGUI_IMPL_API
+
+// [Configuration] in order to use a custom Vulkan function loader:
+// (1) You'll need to disable default Vulkan function prototypes.
+// We provide a '#define IMGUI_IMPL_VULKAN_NO_PROTOTYPES' convenience configuration flag.
+// In order to make sure this is visible from the imgui_impl_vulkan.cpp compilation unit:
+// - Add '#define IMGUI_IMPL_VULKAN_NO_PROTOTYPES' in your imconfig.h file
+// - Or as a compilation flag in your build system
+// - Or uncomment here (not recommended because you'd be modifying imgui sources!)
+// - Do not simply add it in a .cpp file!
+// (2) Call ImGui_ImplVulkan_LoadFunctions() before ImGui_ImplVulkan_Init() with your custom function.
+// If you have no idea what this is, leave it alone!
+//#define IMGUI_IMPL_VULKAN_NO_PROTOTYPES
+
+// Vulkan includes
+#if defined(IMGUI_IMPL_VULKAN_NO_PROTOTYPES) && !defined(VK_NO_PROTOTYPES)
+#define VK_NO_PROTOTYPES
+#endif
+#include <vulkan/vulkan.h>
+
+// Initialization data, for ImGui_ImplVulkan_Init()
+// [Please zero-clear before use!]
+struct ImGui_ImplVulkan_InitInfo
+{
+ VkInstance Instance;
+ VkPhysicalDevice PhysicalDevice;
+ VkDevice Device;
+ uint32_t QueueFamily;
+ VkQueue Queue;
+ VkPipelineCache PipelineCache;
+ VkDescriptorPool DescriptorPool;
+ uint32_t Subpass;
+ uint32_t MinImageCount; // >= 2
+ uint32_t ImageCount; // >= MinImageCount
+ VkSampleCountFlagBits MSAASamples; // >= VK_SAMPLE_COUNT_1_BIT
+ const VkAllocationCallbacks* Allocator;
+ void (*CheckVkResultFn)(VkResult err);
+};
+
+// Called by user code
+IMGUI_IMPL_API bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass render_pass);
+IMGUI_IMPL_API void ImGui_ImplVulkan_Shutdown();
+IMGUI_IMPL_API void ImGui_ImplVulkan_NewFrame();
+IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer, VkPipeline pipeline = VK_NULL_HANDLE);
+IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer);
+IMGUI_IMPL_API void ImGui_ImplVulkan_DestroyFontUploadObjects();
+IMGUI_IMPL_API void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count); // To override MinImageCount after initialization (e.g. if swap chain is recreated)
+
+// Optional: load Vulkan functions with a custom function loader
+// This is only useful with IMGUI_IMPL_VULKAN_NO_PROTOTYPES / VK_NO_PROTOTYPES
+IMGUI_IMPL_API bool ImGui_ImplVulkan_LoadFunctions(PFN_vkVoidFunction(*loader_func)(const char* function_name, void* user_data), void* user_data = NULL);
+
+//-------------------------------------------------------------------------
+// Internal / Miscellaneous Vulkan Helpers
+// (Used by example's main.cpp. Used by multi-viewport features. PROBABLY NOT used by your own engine/app.)
+//-------------------------------------------------------------------------
+// You probably do NOT need to use or care about those functions.
+// Those functions only exist because:
+// 1) they facilitate the readability and maintenance of the multiple main.cpp examples files.
+// 2) the upcoming multi-viewport feature will need them internally.
+// Generally we avoid exposing any kind of superfluous high-level helpers in the backends,
+// but it is too much code to duplicate everywhere so we exceptionally expose them.
+//
+// Your engine/app will likely _already_ have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
+// You may read this code to learn about Vulkan, but it is recommended you use you own custom tailored code to do equivalent work.
+// (The ImGui_ImplVulkanH_XXX functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)
+//-------------------------------------------------------------------------
+
+struct ImGui_ImplVulkanH_Frame;
+struct ImGui_ImplVulkanH_Window;
+
+// Helpers
+IMGUI_IMPL_API void ImGui_ImplVulkanH_CreateOrResizeWindow(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wnd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count);
+IMGUI_IMPL_API void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Window* wnd, const VkAllocationCallbacks* allocator);
+IMGUI_IMPL_API VkSurfaceFormatKHR ImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkFormat* request_formats, int request_formats_count, VkColorSpaceKHR request_color_space);
+IMGUI_IMPL_API VkPresentModeKHR ImGui_ImplVulkanH_SelectPresentMode(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkPresentModeKHR* request_modes, int request_modes_count);
+IMGUI_IMPL_API int ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(VkPresentModeKHR present_mode);
+
+// Helper structure to hold the data needed by one rendering frame
+// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.)
+// [Please zero-clear before use!]
+struct ImGui_ImplVulkanH_Frame
+{
+ VkCommandPool CommandPool;
+ VkCommandBuffer CommandBuffer;
+ VkFence Fence;
+ VkImage Backbuffer;
+ VkImageView BackbufferView;
+ VkFramebuffer Framebuffer;
+};
+
+struct ImGui_ImplVulkanH_FrameSemaphores
+{
+ VkSemaphore ImageAcquiredSemaphore;
+ VkSemaphore RenderCompleteSemaphore;
+};
+
+// Helper structure to hold the data needed by one rendering context into one OS window
+// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.)
+struct ImGui_ImplVulkanH_Window
+{
+ int Width;
+ int Height;
+ VkSwapchainKHR Swapchain;
+ VkSurfaceKHR Surface;
+ VkSurfaceFormatKHR SurfaceFormat;
+ VkPresentModeKHR PresentMode;
+ VkRenderPass RenderPass;
+ VkPipeline Pipeline; // The window pipeline may uses a different VkRenderPass than the one passed in ImGui_ImplVulkan_InitInfo
+ bool ClearEnable;
+ VkClearValue ClearValue;
+ uint32_t FrameIndex; // Current frame being rendered to (0 <= FrameIndex < FrameInFlightCount)
+ uint32_t ImageCount; // Number of simultaneous in-flight frames (returned by vkGetSwapchainImagesKHR, usually derived from min_image_count)
+ uint32_t SemaphoreIndex; // Current set of swapchain wait semaphores we're using (needs to be distinct from per frame data)
+ ImGui_ImplVulkanH_Frame* Frames;
+ ImGui_ImplVulkanH_FrameSemaphores* FrameSemaphores;
+
+ ImGui_ImplVulkanH_Window()
+ {
+ memset(this, 0, sizeof(*this));
+ PresentMode = VK_PRESENT_MODE_MAX_ENUM_KHR;
+ ClearEnable = true;
+ }
+};
+