summaryrefslogtreecommitdiff
path: root/3rdparty/imgui/backend
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/imgui/backend')
-rw-r--r--3rdparty/imgui/backend/imgui_impl_dx11.cpp209
-rw-r--r--3rdparty/imgui/backend/imgui_impl_dx11.h3
-rw-r--r--3rdparty/imgui/backend/imgui_impl_dx12.cpp202
-rw-r--r--3rdparty/imgui/backend/imgui_impl_dx12.h18
-rw-r--r--3rdparty/imgui/backend/imgui_impl_glfw.cpp605
-rw-r--r--3rdparty/imgui/backend/imgui_impl_glfw.h22
-rw-r--r--3rdparty/imgui/backend/imgui_impl_metal.h41
-rw-r--r--3rdparty/imgui/backend/imgui_impl_metal.mm100
-rw-r--r--3rdparty/imgui/backend/imgui_impl_opengl2.cpp79
-rw-r--r--3rdparty/imgui/backend/imgui_impl_opengl2.h3
-rw-r--r--3rdparty/imgui/backend/imgui_impl_opengl3.cpp433
-rw-r--r--3rdparty/imgui/backend/imgui_impl_opengl3.h44
-rw-r--r--3rdparty/imgui/backend/imgui_impl_opengl3_loader.h757
-rw-r--r--3rdparty/imgui/backend/imgui_impl_vulkan.cpp412
-rw-r--r--3rdparty/imgui/backend/imgui_impl_vulkan.h31
-rw-r--r--3rdparty/imgui/backend/imgui_impl_win32.cpp914
-rw-r--r--3rdparty/imgui/backend/imgui_impl_win32.h7
17 files changed, 2756 insertions, 1124 deletions
diff --git a/3rdparty/imgui/backend/imgui_impl_dx11.cpp b/3rdparty/imgui/backend/imgui_impl_dx11.cpp
index f114cdc..3f628cb 100644
--- a/3rdparty/imgui/backend/imgui_impl_dx11.cpp
+++ b/3rdparty/imgui/backend/imgui_impl_dx11.cpp
@@ -5,12 +5,15 @@
// [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.
+// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// 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-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
+// 2021-05-19: DirectX11: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
// 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.
@@ -37,30 +40,46 @@
#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;
+// DirectX11 data
+struct ImGui_ImplDX11_Data
+{
+ ID3D11Device* pd3dDevice;
+ ID3D11DeviceContext* pd3dDeviceContext;
+ IDXGIFactory* pFactory;
+ ID3D11Buffer* pVB;
+ ID3D11Buffer* pIB;
+ ID3D11VertexShader* pVertexShader;
+ ID3D11InputLayout* pInputLayout;
+ ID3D11Buffer* pVertexConstantBuffer;
+ ID3D11PixelShader* pPixelShader;
+ ID3D11SamplerState* pFontSampler;
+ ID3D11ShaderResourceView* pFontTextureView;
+ ID3D11RasterizerState* pRasterizerState;
+ ID3D11BlendState* pBlendState;
+ ID3D11DepthStencilState* pDepthStencilState;
+ int VertexBufferSize;
+ int IndexBufferSize;
+
+ ImGui_ImplDX11_Data() { memset(this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; }
+};
struct VERTEX_CONSTANT_BUFFER
{
float mvp[4][4];
};
+// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
+// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
+static ImGui_ImplDX11_Data* ImGui_ImplDX11_GetBackendData()
+{
+ return ImGui::GetCurrentContext() ? (ImGui_ImplDX11_Data*)ImGui::GetIO().BackendRendererUserData : NULL;
+}
+
+// Functions
static void ImGui_ImplDX11_SetupRenderState(ImDrawData* draw_data, ID3D11DeviceContext* ctx)
{
+ ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
+
// Setup viewport
D3D11_VIEWPORT vp;
memset(&vp, 0, sizeof(D3D11_VIEWPORT));
@@ -74,14 +93,14 @@ static void ImGui_ImplDX11_SetupRenderState(ImDrawData* draw_data, ID3D11DeviceC
// 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->IASetInputLayout(bd->pInputLayout);
+ ctx->IASetVertexBuffers(0, 1, &bd->pVB, &stride, &offset);
+ ctx->IASetIndexBuffer(bd->pIB, sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0);
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->VSSetShader(bd->pVertexShader, NULL, 0);
+ ctx->VSSetConstantBuffers(0, 1, &bd->pVertexConstantBuffer);
+ ctx->PSSetShader(bd->pPixelShader, NULL, 0);
+ ctx->PSSetSamplers(0, 1, &bd->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..
@@ -89,9 +108,9 @@ static void ImGui_ImplDX11_SetupRenderState(ImDrawData* draw_data, ID3D11DeviceC
// 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);
+ ctx->OMSetBlendState(bd->pBlendState, blend_factor, 0xffffffff);
+ ctx->OMSetDepthStencilState(bd->pDepthStencilState, 0);
+ ctx->RSSetState(bd->pRasterizerState);
}
// Render function
@@ -101,42 +120,43 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
return;
- ID3D11DeviceContext* ctx = g_pd3dDeviceContext;
+ ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
+ ID3D11DeviceContext* ctx = bd->pd3dDeviceContext;
// Create and grow vertex/index buffers if needed
- if (!g_pVB || g_VertexBufferSize < draw_data->TotalVtxCount)
+ if (!bd->pVB || bd->VertexBufferSize < draw_data->TotalVtxCount)
{
- if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
- g_VertexBufferSize = draw_data->TotalVtxCount + 5000;
+ if (bd->pVB) { bd->pVB->Release(); bd->pVB = NULL; }
+ bd->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.ByteWidth = bd->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)
+ if (bd->pd3dDevice->CreateBuffer(&desc, NULL, &bd->pVB) < 0)
return;
}
- if (!g_pIB || g_IndexBufferSize < draw_data->TotalIdxCount)
+ if (!bd->pIB || bd->IndexBufferSize < draw_data->TotalIdxCount)
{
- if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
- g_IndexBufferSize = draw_data->TotalIdxCount + 10000;
+ if (bd->pIB) { bd->pIB->Release(); bd->pIB = NULL; }
+ bd->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.ByteWidth = bd->IndexBufferSize * sizeof(ImDrawIdx);
desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
- if (g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pIB) < 0)
+ if (bd->pd3dDevice->CreateBuffer(&desc, NULL, &bd->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)
+ if (ctx->Map(bd->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)
+ if (ctx->Map(bd->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;
@@ -148,14 +168,14 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
vtx_dst += cmd_list->VtxBuffer.Size;
idx_dst += cmd_list->IdxBuffer.Size;
}
- ctx->Unmap(g_pVB, 0);
- ctx->Unmap(g_pIB, 0);
+ ctx->Unmap(bd->pVB, 0);
+ ctx->Unmap(bd->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)
+ if (ctx->Map(bd->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;
@@ -170,7 +190,7 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
{ (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f },
};
memcpy(&constant_buffer->mvp, mvp, sizeof(mvp));
- ctx->Unmap(g_pVertexConstantBuffer, 0);
+ ctx->Unmap(bd->pVertexConstantBuffer, 0);
}
// Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!)
@@ -198,7 +218,7 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
DXGI_FORMAT IndexBufferFormat;
ID3D11InputLayout* InputLayout;
};
- BACKUP_DX11_STATE old;
+ 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);
@@ -243,12 +263,18 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
}
else
{
+ // Project scissor/clipping rectangles into framebuffer space
+ ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
+ ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
+ if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
+ continue;
+
// 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) };
+ const D3D11_RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y };
ctx->RSSetScissorRects(1, &r);
// Bind texture, Draw
- ID3D11ShaderResourceView* texture_srv = (ID3D11ShaderResourceView*)pcmd->TextureId;
+ ID3D11ShaderResourceView* texture_srv = (ID3D11ShaderResourceView*)pcmd->GetTexID();
ctx->PSSetShaderResources(0, 1, &texture_srv);
ctx->DrawIndexed(pcmd->ElemCount, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset);
}
@@ -281,6 +307,7 @@ static void ImGui_ImplDX11_CreateFontsTexture()
{
// Build texture atlas
ImGuiIO& io = ImGui::GetIO();
+ ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
unsigned char* pixels;
int width, height;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
@@ -304,7 +331,8 @@ static void ImGui_ImplDX11_CreateFontsTexture()
subResource.pSysMem = pixels;
subResource.SysMemPitch = desc.Width * 4;
subResource.SysMemSlicePitch = 0;
- g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
+ bd->pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
+ IM_ASSERT(pTexture != NULL);
// Create texture view
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
@@ -313,12 +341,12 @@ static void ImGui_ImplDX11_CreateFontsTexture()
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MipLevels = desc.MipLevels;
srvDesc.Texture2D.MostDetailedMip = 0;
- g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &g_pFontTextureView);
+ bd->pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &bd->pFontTextureView);
pTexture->Release();
}
// Store our identifier
- io.Fonts->SetTexID((ImTextureID)g_pFontTextureView);
+ io.Fonts->SetTexID((ImTextureID)bd->pFontTextureView);
// Create texture sampler
{
@@ -332,15 +360,16 @@ static void ImGui_ImplDX11_CreateFontsTexture()
desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
desc.MinLOD = 0.f;
desc.MaxLOD = 0.f;
- g_pd3dDevice->CreateSamplerState(&desc, &g_pFontSampler);
+ bd->pd3dDevice->CreateSamplerState(&desc, &bd->pFontSampler);
}
}
bool ImGui_ImplDX11_CreateDeviceObjects()
{
- if (!g_pd3dDevice)
+ ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
+ if (!bd->pd3dDevice)
return false;
- if (g_pFontSampler)
+ if (bd->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)
@@ -382,7 +411,7 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
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)
+ if (bd->pd3dDevice->CreateVertexShader(vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), NULL, &bd->pVertexShader) != S_OK)
{
vertexShaderBlob->Release();
return false;
@@ -395,7 +424,7 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
{ "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)
+ if (bd->pd3dDevice->CreateInputLayout(local_layout, 3, vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), &bd->pInputLayout) != S_OK)
{
vertexShaderBlob->Release();
return false;
@@ -410,7 +439,7 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
desc.MiscFlags = 0;
- g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pVertexConstantBuffer);
+ bd->pd3dDevice->CreateBuffer(&desc, NULL, &bd->pVertexConstantBuffer);
}
}
@@ -435,7 +464,7 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
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)
+ if (bd->pd3dDevice->CreatePixelShader(pixelShaderBlob->GetBufferPointer(), pixelShaderBlob->GetBufferSize(), NULL, &bd->pPixelShader) != S_OK)
{
pixelShaderBlob->Release();
return false;
@@ -456,7 +485,7 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
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);
+ bd->pd3dDevice->CreateBlendState(&desc, &bd->pBlendState);
}
// Create the rasterizer state
@@ -467,7 +496,7 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
desc.CullMode = D3D11_CULL_NONE;
desc.ScissorEnable = true;
desc.DepthClipEnable = true;
- g_pd3dDevice->CreateRasterizerState(&desc, &g_pRasterizerState);
+ bd->pd3dDevice->CreateRasterizerState(&desc, &bd->pRasterizerState);
}
// Create depth-stencil State
@@ -481,7 +510,7 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
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);
+ bd->pd3dDevice->CreateDepthStencilState(&desc, &bd->pDepthStencilState);
}
ImGui_ImplDX11_CreateFontsTexture();
@@ -491,27 +520,31 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
void ImGui_ImplDX11_InvalidateDeviceObjects()
{
- if (!g_pd3dDevice)
+ ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
+ if (!bd->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; }
+ if (bd->pFontSampler) { bd->pFontSampler->Release(); bd->pFontSampler = NULL; }
+ if (bd->pFontTextureView) { bd->pFontTextureView->Release(); bd->pFontTextureView = NULL; ImGui::GetIO().Fonts->SetTexID(NULL); } // We copied data->pFontTextureView to io.Fonts->TexID so let's clear that as well.
+ if (bd->pIB) { bd->pIB->Release(); bd->pIB = NULL; }
+ if (bd->pVB) { bd->pVB->Release(); bd->pVB = NULL; }
+ if (bd->pBlendState) { bd->pBlendState->Release(); bd->pBlendState = NULL; }
+ if (bd->pDepthStencilState) { bd->pDepthStencilState->Release(); bd->pDepthStencilState = NULL; }
+ if (bd->pRasterizerState) { bd->pRasterizerState->Release(); bd->pRasterizerState = NULL; }
+ if (bd->pPixelShader) { bd->pPixelShader->Release(); bd->pPixelShader = NULL; }
+ if (bd->pVertexConstantBuffer) { bd->pVertexConstantBuffer->Release(); bd->pVertexConstantBuffer = NULL; }
+ if (bd->pInputLayout) { bd->pInputLayout->Release(); bd->pInputLayout = NULL; }
+ if (bd->pVertexShader) { bd->pVertexShader->Release(); bd->pVertexShader = NULL; }
}
bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context)
{
- // Setup backend capabilities flags
ImGuiIO& io = ImGui::GetIO();
+ IM_ASSERT(io.BackendRendererUserData == NULL && "Already initialized a renderer backend!");
+
+ // Setup backend capabilities flags
+ ImGui_ImplDX11_Data* bd = IM_NEW(ImGui_ImplDX11_Data)();
+ io.BackendRendererUserData = (void*)bd;
io.BackendRendererName = "imgui_impl_dx11";
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
@@ -524,28 +557,38 @@ bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_co
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;
+ bd->pd3dDevice = device;
+ bd->pd3dDeviceContext = device_context;
+ bd->pFactory = pFactory;
}
if (pDXGIDevice) pDXGIDevice->Release();
if (pDXGIAdapter) pDXGIAdapter->Release();
- g_pd3dDevice->AddRef();
- g_pd3dDeviceContext->AddRef();
+ bd->pd3dDevice->AddRef();
+ bd->pd3dDeviceContext->AddRef();
return true;
}
void ImGui_ImplDX11_Shutdown()
{
+ ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
+ IM_ASSERT(bd != NULL && "No renderer backend to shutdown, or already shutdown?");
+ ImGuiIO& io = ImGui::GetIO();
+
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; }
+ if (bd->pFactory) { bd->pFactory->Release(); }
+ if (bd->pd3dDevice) { bd->pd3dDevice->Release(); }
+ if (bd->pd3dDeviceContext) { bd->pd3dDeviceContext->Release(); }
+ io.BackendRendererName = NULL;
+ io.BackendRendererUserData = NULL;
+ IM_DELETE(bd);
}
void ImGui_ImplDX11_NewFrame()
{
- if (!g_pFontSampler)
+ ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
+ IM_ASSERT(bd != NULL && "Did you call ImGui_ImplDX11_Init()?");
+
+ if (!bd->pFontSampler)
ImGui_ImplDX11_CreateDeviceObjects();
}
diff --git a/3rdparty/imgui/backend/imgui_impl_dx11.h b/3rdparty/imgui/backend/imgui_impl_dx11.h
index 03fee14..a83bce1 100644
--- a/3rdparty/imgui/backend/imgui_impl_dx11.h
+++ b/3rdparty/imgui/backend/imgui_impl_dx11.h
@@ -5,7 +5,8 @@
// [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.
+// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// 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
diff --git a/3rdparty/imgui/backend/imgui_impl_dx12.cpp b/3rdparty/imgui/backend/imgui_impl_dx12.cpp
index 860fe66..e9d2e96 100644
--- a/3rdparty/imgui/backend/imgui_impl_dx12.cpp
+++ b/3rdparty/imgui/backend/imgui_impl_dx12.cpp
@@ -7,14 +7,21 @@
// 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.
+// To build this on 32-bit systems:
+// - [Solution 1] IDE/msbuild: in "Properties/C++/Preprocessor Definitions" add 'ImTextureID=ImU64' (this is what we do in the 'example_win32_direct12/example_win32_direct12.vcxproj' project file)
+// - [Solution 2] IDE/msbuild: in "Properties/C++/Preprocessor Definitions" add 'IMGUI_USER_CONFIG="my_imgui_config.h"' and inside 'my_imgui_config.h' add '#define ImTextureID ImU64' and as many other options as you like.
+// - [Solution 3] IDE/msbuild: edit imconfig.h and add '#define ImTextureID ImU64' (prefer solution 2 to create your own config file!)
+// - [Solution 4] command-line: add '/D ImTextureID=ImU64' to your cl.exe command-line (this is what we do in the example_win32_direct12/build_win32.bat file)
-// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// 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-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
+// 2021-05-19: DirectX12: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
// 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.
@@ -42,40 +49,48 @@
#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
+struct ImGui_ImplDX12_RenderBuffers
{
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)
+struct ImGui_ImplDX12_Data
{
- if (res)
- res->Release();
- res = NULL;
-}
+ ID3D12Device* pd3dDevice;
+ ID3D12RootSignature* pRootSignature;
+ ID3D12PipelineState* pPipelineState;
+ DXGI_FORMAT RTVFormat;
+ ID3D12Resource* pFontTextureResource;
+ D3D12_CPU_DESCRIPTOR_HANDLE hFontSrvCpuDescHandle;
+ D3D12_GPU_DESCRIPTOR_HANDLE hFontSrvGpuDescHandle;
+
+ ImGui_ImplDX12_RenderBuffers* pFrameResources;
+ UINT numFramesInFlight;
+ UINT frameIndex;
+
+ ImGui_ImplDX12_Data() { memset(this, 0, sizeof(*this)); frameIndex = UINT_MAX; }
+};
struct VERTEX_CONSTANT_BUFFER
{
float mvp[4][4];
};
-static void ImGui_ImplDX12_SetupRenderState(ImDrawData* draw_data, ID3D12GraphicsCommandList* ctx, FrameResources* fr)
+// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
+// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
+static ImGui_ImplDX12_Data* ImGui_ImplDX12_GetBackendData()
+{
+ return ImGui::GetCurrentContext() ? (ImGui_ImplDX12_Data*)ImGui::GetIO().BackendRendererUserData : NULL;
+}
+
+// Functions
+static void ImGui_ImplDX12_SetupRenderState(ImDrawData* draw_data, ID3D12GraphicsCommandList* ctx, ImGui_ImplDX12_RenderBuffers* fr)
{
+ ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
+
// 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;
@@ -120,8 +135,8 @@ static void ImGui_ImplDX12_SetupRenderState(ImDrawData* draw_data, ID3D12Graphic
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->SetPipelineState(bd->pPipelineState);
+ ctx->SetGraphicsRootSignature(bd->pRootSignature);
ctx->SetGraphicsRoot32BitConstants(0, 16, &vertex_constant_buffer, 0);
// Setup blend factor
@@ -129,6 +144,14 @@ static void ImGui_ImplDX12_SetupRenderState(ImDrawData* draw_data, ID3D12Graphic
ctx->OMSetBlendFactor(blend_factor);
}
+template<typename T>
+static inline void SafeRelease(T*& res)
+{
+ if (res)
+ res->Release();
+ res = NULL;
+}
+
// Render function
void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandList* ctx)
{
@@ -138,8 +161,9 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL
// 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];
+ ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
+ bd->frameIndex = bd->frameIndex + 1;
+ ImGui_ImplDX12_RenderBuffers* fr = &bd->pFrameResources[bd->frameIndex % bd->numFramesInFlight];
// Create and grow vertex/index buffers if needed
if (fr->VertexBuffer == NULL || fr->VertexBufferSize < draw_data->TotalVtxCount)
@@ -162,7 +186,7 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL
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)
+ if (bd->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)
@@ -185,7 +209,7 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL
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)
+ if (bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL, IID_PPV_ARGS(&fr->IndexBuffer)) < 0)
return;
}
@@ -235,14 +259,19 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL
}
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);
- }
+ // Project scissor/clipping rectangles into framebuffer space
+ ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
+ ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
+ if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
+ continue;
+
+ // Apply Scissor/clipping rectangle, Bind texture, Draw
+ const D3D12_RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y };
+ D3D12_GPU_DESCRIPTOR_HANDLE texture_handle = {};
+ texture_handle.ptr = (UINT64)pcmd->GetTexID();
+ ctx->SetGraphicsRootDescriptorTable(1, texture_handle);
+ 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;
@@ -254,6 +283,7 @@ static void ImGui_ImplDX12_CreateFontsTexture()
{
// Build texture atlas
ImGuiIO& io = ImGui::GetIO();
+ ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
unsigned char* pixels;
int width, height;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
@@ -281,7 +311,7 @@ static void ImGui_ImplDX12_CreateFontsTexture()
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
ID3D12Resource* pTexture = NULL;
- g_pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc,
+ bd->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);
@@ -303,7 +333,7 @@ static void ImGui_ImplDX12_CreateFontsTexture()
props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
ID3D12Resource* uploadBuffer = NULL;
- HRESULT hr = g_pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc,
+ HRESULT hr = bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc,
D3D12_RESOURCE_STATE_GENERIC_READ, NULL, IID_PPV_ARGS(&uploadBuffer));
IM_ASSERT(SUCCEEDED(hr));
@@ -338,7 +368,7 @@ static void ImGui_ImplDX12_CreateFontsTexture()
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));
+ hr = bd->pd3dDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence));
IM_ASSERT(SUCCEEDED(hr));
HANDLE event = CreateEvent(0, 0, 0, 0);
@@ -350,15 +380,15 @@ static void ImGui_ImplDX12_CreateFontsTexture()
queueDesc.NodeMask = 1;
ID3D12CommandQueue* cmdQueue = NULL;
- hr = g_pd3dDevice->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&cmdQueue));
+ hr = bd->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));
+ hr = bd->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));
+ hr = bd->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);
@@ -389,21 +419,29 @@ static void ImGui_ImplDX12_CreateFontsTexture()
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;
+ bd->pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, bd->hFontSrvCpuDescHandle);
+ SafeRelease(bd->pFontTextureResource);
+ bd->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);
+ // READ THIS IF THE STATIC_ASSERT() TRIGGERS:
+ // - 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*.
+ // [Solution 1] IDE/msbuild: in "Properties/C++/Preprocessor Definitions" add 'ImTextureID=ImU64' (this is what we do in the 'example_win32_direct12/example_win32_direct12.vcxproj' project file)
+ // [Solution 2] IDE/msbuild: in "Properties/C++/Preprocessor Definitions" add 'IMGUI_USER_CONFIG="my_imgui_config.h"' and inside 'my_imgui_config.h' add '#define ImTextureID ImU64' and as many other options as you like.
+ // [Solution 3] IDE/msbuild: edit imconfig.h and add '#define ImTextureID ImU64' (prefer solution 2 to create your own config file!)
+ // [Solution 4] command-line: add '/D ImTextureID=ImU64' to your cl.exe command-line (this is what we do in the example_win32_direct12/build_win32.bat file)
+ static_assert(sizeof(ImTextureID) >= sizeof(bd->hFontSrvGpuDescHandle.ptr), "Can't pack descriptor handle into TexID, 32-bit not supported yet.");
+ io.Fonts->SetTexID((ImTextureID)bd->hFontSrvGpuDescHandle.ptr);
}
bool ImGui_ImplDX12_CreateDeviceObjects()
{
- if (!g_pd3dDevice)
+ ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
+ if (!bd || !bd->pd3dDevice)
return false;
- if (g_pPipelineState)
+ if (bd->pPipelineState)
ImGui_ImplDX12_InvalidateDeviceObjects();
// Create the root signature
@@ -484,7 +522,7 @@ bool ImGui_ImplDX12_CreateDeviceObjects()
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));
+ bd->pd3dDevice->CreateRootSignature(0, blob->GetBufferPointer(), blob->GetBufferSize(), IID_PPV_ARGS(&bd->pRootSignature));
blob->Release();
}
@@ -498,10 +536,10 @@ bool ImGui_ImplDX12_CreateDeviceObjects()
memset(&psoDesc, 0, sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC));
psoDesc.NodeMask = 1;
psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
- psoDesc.pRootSignature = g_pRootSignature;
+ psoDesc.pRootSignature = bd->pRootSignature;
psoDesc.SampleMask = UINT_MAX;
psoDesc.NumRenderTargets = 1;
- psoDesc.RTVFormats[0] = g_RTVFormat;
+ psoDesc.RTVFormats[0] = bd->RTVFormat;
psoDesc.SampleDesc.Count = 1;
psoDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
@@ -620,7 +658,7 @@ bool ImGui_ImplDX12_CreateDeviceObjects()
desc.BackFace = desc.FrontFace;
}
- HRESULT result_pipeline_state = g_pd3dDevice->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&g_pPipelineState));
+ HRESULT result_pipeline_state = bd->pd3dDevice->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&bd->pPipelineState));
vertexShaderBlob->Release();
pixelShaderBlob->Release();
if (result_pipeline_state != S_OK)
@@ -633,19 +671,19 @@ bool ImGui_ImplDX12_CreateDeviceObjects()
void ImGui_ImplDX12_InvalidateDeviceObjects()
{
- if (!g_pd3dDevice)
+ ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
+ if (!bd || !bd->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++)
+ SafeRelease(bd->pRootSignature);
+ SafeRelease(bd->pPipelineState);
+ SafeRelease(bd->pFontTextureResource);
+ io.Fonts->SetTexID(NULL); // We copied bd->pFontTextureView to io.Fonts->TexID so let's clear that as well.
+
+ for (UINT i = 0; i < bd->numFramesInFlight; i++)
{
- FrameResources* fr = &g_pFrameResources[i];
+ ImGui_ImplDX12_RenderBuffers* fr = &bd->pFrameResources[i];
SafeRelease(fr->IndexBuffer);
SafeRelease(fr->VertexBuffer);
}
@@ -654,24 +692,28 @@ void ImGui_ImplDX12_InvalidateDeviceObjects()
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();
+ IM_ASSERT(io.BackendRendererUserData == NULL && "Already initialized a renderer backend!");
+
+ // Setup backend capabilities flags
+ ImGui_ImplDX12_Data* bd = IM_NEW(ImGui_ImplDX12_Data)();
+ io.BackendRendererUserData = (void*)bd;
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;
+ bd->pd3dDevice = device;
+ bd->RTVFormat = rtv_format;
+ bd->hFontSrvCpuDescHandle = font_srv_cpu_desc_handle;
+ bd->hFontSrvGpuDescHandle = font_srv_gpu_desc_handle;
+ bd->pFrameResources = new ImGui_ImplDX12_RenderBuffers[num_frames_in_flight];
+ bd->numFramesInFlight = num_frames_in_flight;
+ bd->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];
+ ImGui_ImplDX12_RenderBuffers* fr = &bd->pFrameResources[i];
fr->IndexBuffer = NULL;
fr->VertexBuffer = NULL;
fr->IndexBufferSize = 10000;
@@ -683,18 +725,22 @@ bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FO
void ImGui_ImplDX12_Shutdown()
{
+ ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
+ IM_ASSERT(bd != NULL && "No renderer backend to shutdown, or already shutdown?");
+ ImGuiIO& io = ImGui::GetIO();
+
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;
+ delete[] bd->pFrameResources;
+ io.BackendRendererName = NULL;
+ io.BackendRendererUserData = NULL;
+ IM_DELETE(bd);
}
void ImGui_ImplDX12_NewFrame()
{
- if (!g_pPipelineState)
+ ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
+ IM_ASSERT(bd != NULL && "Did you call ImGui_ImplDX12_Init()?");
+
+ if (!bd->pPipelineState)
ImGui_ImplDX12_CreateDeviceObjects();
}
diff --git a/3rdparty/imgui/backend/imgui_impl_dx12.h b/3rdparty/imgui/backend/imgui_impl_dx12.h
index 7051962..6548f6f 100644
--- a/3rdparty/imgui/backend/imgui_impl_dx12.h
+++ b/3rdparty/imgui/backend/imgui_impl_dx12.h
@@ -6,22 +6,17 @@
// [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.
+// See imgui_impl_dx12.cpp file for details.
-// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// 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
+#include <dxgiformat.h> // DXGI_FORMAT
-#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;
@@ -41,8 +36,3 @@ IMGUI_IMPL_API void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3
// 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
index cd0f51d..516aa3c 100644
--- a/3rdparty/imgui/backend/imgui_impl_glfw.cpp
+++ b/3rdparty/imgui/backend/imgui_impl_glfw.cpp
@@ -5,16 +5,28 @@
// Implemented features:
// [X] Platform: Clipboard support.
+// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
// [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.
+// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// 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)
+// 2022-02-07: Added ImGui_ImplGlfw_InstallCallbacks()/ImGui_ImplGlfw_RestoreCallbacks() helpers to facilitate user installing callbacks after iniitializing backend.
+// 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago)with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion.
+// 2021-01-20: Inputs: calling new io.AddKeyAnalogEvent() for gamepad support, instead of writing directly to io.NavInputs[].
+// 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+).
+// 2022-01-17: Inputs: always update key mods next and before key event (not in NewFrame) to fix input queue with very low framerates.
+// 2022-01-12: *BREAKING CHANGE*: Now using glfwSetCursorPosCallback(). If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetCursorPosCallback() and forward it to the backend via ImGui_ImplGlfw_CursorPosCallback().
+// 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range.
+// 2022-01-05: Inputs: Converting GLFW untranslated keycodes back to translated keycodes (in the ImGui_ImplGlfw_KeyCallback() function) in order to match the behavior of every other backend, and facilitate the use of GLFW with lettered-shortcuts API.
+// 2021-08-17: *BREAKING CHANGE*: Now using glfwSetWindowFocusCallback() to calling io.AddFocusEvent(). If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetWindowFocusCallback() and forward it to the backend via ImGui_ImplGlfw_WindowFocusCallback().
+// 2021-07-29: *BREAKING CHANGE*: Now using glfwSetCursorEnterCallback(). MousePos is correctly reported when the host platform window is hovered but not focused. If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetWindowFocusCallback() callback and forward it to the backend via ImGui_ImplGlfw_CursorEnterCallback().
+// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
// 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.
@@ -40,6 +52,16 @@
#include "imgui.h"
#include "imgui_impl_glfw.h"
+// Clang warnings with -Weverything
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast
+#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
+#if __has_warning("-Wzero-as-null-pointer-constant")
+#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
+#endif
+#endif
+
// GLFW
#include <GLFW/glfw3.h>
#ifdef _WIN32
@@ -47,37 +69,58 @@
#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?
+#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
+#define GLFW_HAS_GAMEPAD_API (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwGetGamepadState() new api
+#define GLFW_HAS_GET_KEY_NAME (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ glfwGetKeyName()
-// Data
+// GLFW 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;
+struct ImGui_ImplGlfw_Data
+{
+ GLFWwindow* Window;
+ GlfwClientApi ClientApi;
+ double Time;
+ GLFWwindow* MouseWindow;
+ GLFWcursor* MouseCursors[ImGuiMouseCursor_COUNT];
+ ImVec2 LastValidMousePos;
+ bool InstalledCallbacks;
+
+ // Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
+ GLFWwindowfocusfun PrevUserCallbackWindowFocus;
+ GLFWcursorposfun PrevUserCallbackCursorPos;
+ GLFWcursorenterfun PrevUserCallbackCursorEnter;
+ GLFWmousebuttonfun PrevUserCallbackMousebutton;
+ GLFWscrollfun PrevUserCallbackScroll;
+ GLFWkeyfun PrevUserCallbackKey;
+ GLFWcharfun PrevUserCallbackChar;
+ GLFWmonitorfun PrevUserCallbackMonitor;
+
+ ImGui_ImplGlfw_Data() { memset(this, 0, sizeof(*this)); }
+};
+
+// Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts
+// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
+// FIXME: multi-context support is not well tested and probably dysfunctional in this backend.
+// - Because glfwPollEvents() process all windows and some events may be called outside of it, you will need to register your own callbacks
+// (passing install_callbacks=false in ImGui_ImplGlfw_InitXXX functions), set the current dear imgui context and then call our callbacks.
+// - Otherwise we may need to store a GLFWWindow* -> ImGuiContext* map and handle this in the backend, adding a little bit of extra complexity to it.
+// FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context.
+static ImGui_ImplGlfw_Data* ImGui_ImplGlfw_GetBackendData()
+{
+ return ImGui::GetCurrentContext() ? (ImGui_ImplGlfw_Data*)ImGui::GetIO().BackendPlatformUserData : NULL;
+}
+// Functions
static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data)
{
return glfwGetClipboardString((GLFWwindow*)user_data);
@@ -88,96 +131,319 @@ 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)
+static ImGuiKey ImGui_ImplGlfw_KeyToImGuiKey(int key)
{
- if (g_PrevUserCallbackMousebutton != NULL)
- g_PrevUserCallbackMousebutton(window, button, action, mods);
+ switch (key)
+ {
+ case GLFW_KEY_TAB: return ImGuiKey_Tab;
+ case GLFW_KEY_LEFT: return ImGuiKey_LeftArrow;
+ case GLFW_KEY_RIGHT: return ImGuiKey_RightArrow;
+ case GLFW_KEY_UP: return ImGuiKey_UpArrow;
+ case GLFW_KEY_DOWN: return ImGuiKey_DownArrow;
+ case GLFW_KEY_PAGE_UP: return ImGuiKey_PageUp;
+ case GLFW_KEY_PAGE_DOWN: return ImGuiKey_PageDown;
+ case GLFW_KEY_HOME: return ImGuiKey_Home;
+ case GLFW_KEY_END: return ImGuiKey_End;
+ case GLFW_KEY_INSERT: return ImGuiKey_Insert;
+ case GLFW_KEY_DELETE: return ImGuiKey_Delete;
+ case GLFW_KEY_BACKSPACE: return ImGuiKey_Backspace;
+ case GLFW_KEY_SPACE: return ImGuiKey_Space;
+ case GLFW_KEY_ENTER: return ImGuiKey_Enter;
+ case GLFW_KEY_ESCAPE: return ImGuiKey_Escape;
+ case GLFW_KEY_APOSTROPHE: return ImGuiKey_Apostrophe;
+ case GLFW_KEY_COMMA: return ImGuiKey_Comma;
+ case GLFW_KEY_MINUS: return ImGuiKey_Minus;
+ case GLFW_KEY_PERIOD: return ImGuiKey_Period;
+ case GLFW_KEY_SLASH: return ImGuiKey_Slash;
+ case GLFW_KEY_SEMICOLON: return ImGuiKey_Semicolon;
+ case GLFW_KEY_EQUAL: return ImGuiKey_Equal;
+ case GLFW_KEY_LEFT_BRACKET: return ImGuiKey_LeftBracket;
+ case GLFW_KEY_BACKSLASH: return ImGuiKey_Backslash;
+ case GLFW_KEY_RIGHT_BRACKET: return ImGuiKey_RightBracket;
+ case GLFW_KEY_GRAVE_ACCENT: return ImGuiKey_GraveAccent;
+ case GLFW_KEY_CAPS_LOCK: return ImGuiKey_CapsLock;
+ case GLFW_KEY_SCROLL_LOCK: return ImGuiKey_ScrollLock;
+ case GLFW_KEY_NUM_LOCK: return ImGuiKey_NumLock;
+ case GLFW_KEY_PRINT_SCREEN: return ImGuiKey_PrintScreen;
+ case GLFW_KEY_PAUSE: return ImGuiKey_Pause;
+ case GLFW_KEY_KP_0: return ImGuiKey_Keypad0;
+ case GLFW_KEY_KP_1: return ImGuiKey_Keypad1;
+ case GLFW_KEY_KP_2: return ImGuiKey_Keypad2;
+ case GLFW_KEY_KP_3: return ImGuiKey_Keypad3;
+ case GLFW_KEY_KP_4: return ImGuiKey_Keypad4;
+ case GLFW_KEY_KP_5: return ImGuiKey_Keypad5;
+ case GLFW_KEY_KP_6: return ImGuiKey_Keypad6;
+ case GLFW_KEY_KP_7: return ImGuiKey_Keypad7;
+ case GLFW_KEY_KP_8: return ImGuiKey_Keypad8;
+ case GLFW_KEY_KP_9: return ImGuiKey_Keypad9;
+ case GLFW_KEY_KP_DECIMAL: return ImGuiKey_KeypadDecimal;
+ case GLFW_KEY_KP_DIVIDE: return ImGuiKey_KeypadDivide;
+ case GLFW_KEY_KP_MULTIPLY: return ImGuiKey_KeypadMultiply;
+ case GLFW_KEY_KP_SUBTRACT: return ImGuiKey_KeypadSubtract;
+ case GLFW_KEY_KP_ADD: return ImGuiKey_KeypadAdd;
+ case GLFW_KEY_KP_ENTER: return ImGuiKey_KeypadEnter;
+ case GLFW_KEY_KP_EQUAL: return ImGuiKey_KeypadEqual;
+ case GLFW_KEY_LEFT_SHIFT: return ImGuiKey_LeftShift;
+ case GLFW_KEY_LEFT_CONTROL: return ImGuiKey_LeftCtrl;
+ case GLFW_KEY_LEFT_ALT: return ImGuiKey_LeftAlt;
+ case GLFW_KEY_LEFT_SUPER: return ImGuiKey_LeftSuper;
+ case GLFW_KEY_RIGHT_SHIFT: return ImGuiKey_RightShift;
+ case GLFW_KEY_RIGHT_CONTROL: return ImGuiKey_RightCtrl;
+ case GLFW_KEY_RIGHT_ALT: return ImGuiKey_RightAlt;
+ case GLFW_KEY_RIGHT_SUPER: return ImGuiKey_RightSuper;
+ case GLFW_KEY_MENU: return ImGuiKey_Menu;
+ case GLFW_KEY_0: return ImGuiKey_0;
+ case GLFW_KEY_1: return ImGuiKey_1;
+ case GLFW_KEY_2: return ImGuiKey_2;
+ case GLFW_KEY_3: return ImGuiKey_3;
+ case GLFW_KEY_4: return ImGuiKey_4;
+ case GLFW_KEY_5: return ImGuiKey_5;
+ case GLFW_KEY_6: return ImGuiKey_6;
+ case GLFW_KEY_7: return ImGuiKey_7;
+ case GLFW_KEY_8: return ImGuiKey_8;
+ case GLFW_KEY_9: return ImGuiKey_9;
+ case GLFW_KEY_A: return ImGuiKey_A;
+ case GLFW_KEY_B: return ImGuiKey_B;
+ case GLFW_KEY_C: return ImGuiKey_C;
+ case GLFW_KEY_D: return ImGuiKey_D;
+ case GLFW_KEY_E: return ImGuiKey_E;
+ case GLFW_KEY_F: return ImGuiKey_F;
+ case GLFW_KEY_G: return ImGuiKey_G;
+ case GLFW_KEY_H: return ImGuiKey_H;
+ case GLFW_KEY_I: return ImGuiKey_I;
+ case GLFW_KEY_J: return ImGuiKey_J;
+ case GLFW_KEY_K: return ImGuiKey_K;
+ case GLFW_KEY_L: return ImGuiKey_L;
+ case GLFW_KEY_M: return ImGuiKey_M;
+ case GLFW_KEY_N: return ImGuiKey_N;
+ case GLFW_KEY_O: return ImGuiKey_O;
+ case GLFW_KEY_P: return ImGuiKey_P;
+ case GLFW_KEY_Q: return ImGuiKey_Q;
+ case GLFW_KEY_R: return ImGuiKey_R;
+ case GLFW_KEY_S: return ImGuiKey_S;
+ case GLFW_KEY_T: return ImGuiKey_T;
+ case GLFW_KEY_U: return ImGuiKey_U;
+ case GLFW_KEY_V: return ImGuiKey_V;
+ case GLFW_KEY_W: return ImGuiKey_W;
+ case GLFW_KEY_X: return ImGuiKey_X;
+ case GLFW_KEY_Y: return ImGuiKey_Y;
+ case GLFW_KEY_Z: return ImGuiKey_Z;
+ case GLFW_KEY_F1: return ImGuiKey_F1;
+ case GLFW_KEY_F2: return ImGuiKey_F2;
+ case GLFW_KEY_F3: return ImGuiKey_F3;
+ case GLFW_KEY_F4: return ImGuiKey_F4;
+ case GLFW_KEY_F5: return ImGuiKey_F5;
+ case GLFW_KEY_F6: return ImGuiKey_F6;
+ case GLFW_KEY_F7: return ImGuiKey_F7;
+ case GLFW_KEY_F8: return ImGuiKey_F8;
+ case GLFW_KEY_F9: return ImGuiKey_F9;
+ case GLFW_KEY_F10: return ImGuiKey_F10;
+ case GLFW_KEY_F11: return ImGuiKey_F11;
+ case GLFW_KEY_F12: return ImGuiKey_F12;
+ default: return ImGuiKey_None;
+ }
+}
- if (action == GLFW_PRESS && button >= 0 && button < IM_ARRAYSIZE(g_MouseJustPressed))
- g_MouseJustPressed[button] = true;
+static void ImGui_ImplGlfw_UpdateKeyModifiers(int mods)
+{
+ ImGuiIO& io = ImGui::GetIO();
+ io.AddKeyEvent(ImGuiKey_ModCtrl, (mods & GLFW_MOD_CONTROL) != 0);
+ io.AddKeyEvent(ImGuiKey_ModShift, (mods & GLFW_MOD_SHIFT) != 0);
+ io.AddKeyEvent(ImGuiKey_ModAlt, (mods & GLFW_MOD_ALT) != 0);
+ io.AddKeyEvent(ImGuiKey_ModSuper, (mods & GLFW_MOD_SUPER) != 0);
}
-void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset)
+void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
{
- if (g_PrevUserCallbackScroll != NULL)
- g_PrevUserCallbackScroll(window, xoffset, yoffset);
+ ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
+ if (bd->PrevUserCallbackMousebutton != NULL && window == bd->Window)
+ bd->PrevUserCallbackMousebutton(window, button, action, mods);
+
+ ImGui_ImplGlfw_UpdateKeyModifiers(mods);
ImGuiIO& io = ImGui::GetIO();
- io.MouseWheelH += (float)xoffset;
- io.MouseWheel += (float)yoffset;
+ if (button >= 0 && button < ImGuiMouseButton_COUNT)
+ io.AddMouseButtonEvent(button, action == GLFW_PRESS);
}
-void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
+void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset)
{
- if (g_PrevUserCallbackKey != NULL)
- g_PrevUserCallbackKey(window, key, scancode, action, mods);
+ ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
+ if (bd->PrevUserCallbackScroll != NULL && window == bd->Window)
+ bd->PrevUserCallbackScroll(window, xoffset, yoffset);
ImGuiIO& io = ImGui::GetIO();
- if (action == GLFW_PRESS)
- io.KeysDown[key] = true;
- if (action == GLFW_RELEASE)
- io.KeysDown[key] = false;
+ io.AddMouseWheelEvent((float)xoffset, (float)yoffset);
+}
- // 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;
+static int ImGui_ImplGlfw_TranslateUntranslatedKey(int key, int scancode)
+{
+#if GLFW_HAS_GET_KEY_NAME && !defined(__EMSCRIPTEN__)
+ // GLFW 3.1+ attempts to "untranslate" keys, which goes the opposite of what every other framework does, making using lettered shortcuts difficult.
+ // (It had reasons to do so: namely GLFW is/was more likely to be used for WASD-type game controls rather than lettered shortcuts, but IHMO the 3.1 change could have been done differently)
+ // See https://github.com/glfw/glfw/issues/1502 for details.
+ // Adding a workaround to undo this (so our keys are translated->untranslated->translated, likely a lossy process).
+ // This won't cover edge cases but this is at least going to cover common cases.
+ if (key >= GLFW_KEY_KP_0 && key <= GLFW_KEY_KP_EQUAL)
+ return key;
+ const char* key_name = glfwGetKeyName(key, scancode);
+ if (key_name && key_name[0] != 0 && key_name[1] == 0)
+ {
+ const char char_names[] = "`-=[]\\,;\'./";
+ const int char_keys[] = { GLFW_KEY_GRAVE_ACCENT, GLFW_KEY_MINUS, GLFW_KEY_EQUAL, GLFW_KEY_LEFT_BRACKET, GLFW_KEY_RIGHT_BRACKET, GLFW_KEY_BACKSLASH, GLFW_KEY_COMMA, GLFW_KEY_SEMICOLON, GLFW_KEY_APOSTROPHE, GLFW_KEY_PERIOD, GLFW_KEY_SLASH, 0 };
+ IM_ASSERT(IM_ARRAYSIZE(char_names) == IM_ARRAYSIZE(char_keys));
+ if (key_name[0] >= '0' && key_name[0] <= '9') { key = GLFW_KEY_0 + (key_name[0] - '0'); }
+ else if (key_name[0] >= 'A' && key_name[0] <= 'Z') { key = GLFW_KEY_A + (key_name[0] - 'A'); }
+ else if (const char* p = strchr(char_names, key_name[0])) { key = char_keys[p - char_names]; }
+ }
+ // if (action == GLFW_PRESS) printf("key %d scancode %d name '%s'\n", key, scancode, key_name);
#else
- io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER];
+ IM_UNUSED(scancode);
#endif
+ return key;
+}
+
+void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int keycode, int scancode, int action, int mods)
+{
+ ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
+ if (bd->PrevUserCallbackKey != NULL && window == bd->Window)
+ bd->PrevUserCallbackKey(window, keycode, scancode, action, mods);
+
+ if (action != GLFW_PRESS && action != GLFW_RELEASE)
+ return;
+
+ ImGui_ImplGlfw_UpdateKeyModifiers(mods);
+
+ keycode = ImGui_ImplGlfw_TranslateUntranslatedKey(keycode, scancode);
+
+ ImGuiIO& io = ImGui::GetIO();
+ ImGuiKey imgui_key = ImGui_ImplGlfw_KeyToImGuiKey(keycode);
+ io.AddKeyEvent(imgui_key, (action == GLFW_PRESS));
+ io.SetKeyEventNativeData(imgui_key, keycode, scancode); // To support legacy indexing (<1.87 user code)
+}
+
+void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused)
+{
+ ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
+ if (bd->PrevUserCallbackWindowFocus != NULL && window == bd->Window)
+ bd->PrevUserCallbackWindowFocus(window, focused);
+
+ ImGuiIO& io = ImGui::GetIO();
+ io.AddFocusEvent(focused != 0);
+}
+
+void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double x, double y)
+{
+ ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
+ if (bd->PrevUserCallbackCursorPos != NULL && window == bd->Window)
+ bd->PrevUserCallbackCursorPos(window, x, y);
+
+ ImGuiIO& io = ImGui::GetIO();
+ io.AddMousePosEvent((float)x, (float)y);
+ bd->LastValidMousePos = ImVec2((float)x, (float)y);
+}
+
+// Workaround: X11 seems to send spurious Leave/Enter events which would make us lose our position,
+// so we back it up and restore on Leave/Enter (see https://github.com/ocornut/imgui/issues/4984)
+void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered)
+{
+ ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
+ if (bd->PrevUserCallbackCursorEnter != NULL && window == bd->Window)
+ bd->PrevUserCallbackCursorEnter(window, entered);
+
+ ImGuiIO& io = ImGui::GetIO();
+ if (entered)
+ {
+ bd->MouseWindow = window;
+ io.AddMousePosEvent(bd->LastValidMousePos.x, bd->LastValidMousePos.y);
+ }
+ else if (!entered && bd->MouseWindow == window)
+ {
+ bd->LastValidMousePos = io.MousePos;
+ bd->MouseWindow = NULL;
+ io.AddMousePosEvent(-FLT_MAX, -FLT_MAX);
+ }
}
void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c)
{
- if (g_PrevUserCallbackChar != NULL)
- g_PrevUserCallbackChar(window, c);
+ ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
+ if (bd->PrevUserCallbackChar != NULL && window == bd->Window)
+ bd->PrevUserCallbackChar(window, c);
ImGuiIO& io = ImGui::GetIO();
io.AddInputCharacter(c);
}
+void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor*, int)
+{
+ // Unused in 'master' branch but 'docking' branch will use this, so we declare it ahead of it so if you have to install callbacks you can install this one too.
+}
+
+void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window)
+{
+ ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
+ IM_ASSERT(bd->InstalledCallbacks == false && "Callbacks already installed!");
+ IM_ASSERT(bd->Window == window);
+
+ bd->PrevUserCallbackWindowFocus = glfwSetWindowFocusCallback(window, ImGui_ImplGlfw_WindowFocusCallback);
+ bd->PrevUserCallbackCursorEnter = glfwSetCursorEnterCallback(window, ImGui_ImplGlfw_CursorEnterCallback);
+ bd->PrevUserCallbackCursorPos = glfwSetCursorPosCallback(window, ImGui_ImplGlfw_CursorPosCallback);
+ bd->PrevUserCallbackMousebutton = glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback);
+ bd->PrevUserCallbackScroll = glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback);
+ bd->PrevUserCallbackKey = glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback);
+ bd->PrevUserCallbackChar = glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback);
+ bd->PrevUserCallbackMonitor = glfwSetMonitorCallback(ImGui_ImplGlfw_MonitorCallback);
+ bd->InstalledCallbacks = true;
+}
+
+void ImGui_ImplGlfw_RestoreCallbacks(GLFWwindow* window)
+{
+ ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
+ IM_ASSERT(bd->InstalledCallbacks == true && "Callbacks not installed!");
+ IM_ASSERT(bd->Window == window);
+
+ glfwSetWindowFocusCallback(window, bd->PrevUserCallbackWindowFocus);
+ glfwSetCursorEnterCallback(window, bd->PrevUserCallbackCursorEnter);
+ glfwSetCursorPosCallback(window, bd->PrevUserCallbackCursorPos);
+ glfwSetMouseButtonCallback(window, bd->PrevUserCallbackMousebutton);
+ glfwSetScrollCallback(window, bd->PrevUserCallbackScroll);
+ glfwSetKeyCallback(window, bd->PrevUserCallbackKey);
+ glfwSetCharCallback(window, bd->PrevUserCallbackChar);
+ glfwSetMonitorCallback(bd->PrevUserCallbackMonitor);
+ bd->InstalledCallbacks = false;
+ bd->PrevUserCallbackWindowFocus = NULL;
+ bd->PrevUserCallbackCursorEnter = NULL;
+ bd->PrevUserCallbackCursorPos = NULL;
+ bd->PrevUserCallbackMousebutton = NULL;
+ bd->PrevUserCallbackScroll = NULL;
+ bd->PrevUserCallbackKey = NULL;
+ bd->PrevUserCallbackChar = NULL;
+ bd->PrevUserCallbackMonitor = NULL;
+}
+
static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api)
{
- g_Window = window;
- g_Time = 0.0;
+ ImGuiIO& io = ImGui::GetIO();
+ IM_ASSERT(io.BackendPlatformUserData == NULL && "Already initialized a platform backend!");
// Setup backend capabilities flags
- ImGuiIO& io = ImGui::GetIO();
+ ImGui_ImplGlfw_Data* bd = IM_NEW(ImGui_ImplGlfw_Data)();
+ io.BackendPlatformUserData = (void*)bd;
+ io.BackendPlatformName = "imgui_impl_glfw";
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;
+ bd->Window = window;
+ bd->Time = 0.0;
io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText;
io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText;
- io.ClipboardUserData = g_Window;
+ io.ClipboardUserData = bd->Window;
+
+ // Set platform dependent data in viewport
#if defined(_WIN32)
- io.ImeWindowHandle = (void*)glfwGetWin32Window(g_Window);
+ ImGui::GetMainViewport()->PlatformHandleRaw = (void*)glfwGetWin32Window(bd->Window);
#endif
// Create mouse cursors
@@ -185,39 +451,29 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw
// 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);
+ bd->MouseCursors[ImGuiMouseCursor_Arrow] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
+ bd->MouseCursors[ImGuiMouseCursor_TextInput] = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR);
+ bd->MouseCursors[ImGuiMouseCursor_ResizeNS] = glfwCreateStandardCursor(GLFW_VRESIZE_CURSOR);
+ bd->MouseCursors[ImGuiMouseCursor_ResizeEW] = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR);
+ bd->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);
+ bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_RESIZE_ALL_CURSOR);
+ bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_RESIZE_NESW_CURSOR);
+ bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_RESIZE_NWSE_CURSOR);
+ bd->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);
+ bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
+ bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
+ bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
+ bd->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);
- }
+ ImGui_ImplGlfw_InstallCallbacks(window);
- g_ClientApi = client_api;
+ bd->ClientApi = client_api;
return true;
}
@@ -238,53 +494,44 @@ bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool install_callbacks)
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;
- }
+ ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
+ IM_ASSERT(bd != NULL && "No platform backend to shutdown, or already shutdown?");
+ ImGuiIO& io = ImGui::GetIO();
+
+ if (bd->InstalledCallbacks)
+ ImGui_ImplGlfw_RestoreCallbacks(bd->Window);
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;
+ glfwDestroyCursor(bd->MouseCursors[cursor_n]);
+
+ io.BackendPlatformName = NULL;
+ io.BackendPlatformUserData = NULL;
+ IM_DELETE(bd);
}
-static void ImGui_ImplGlfw_UpdateMousePosAndButtons()
+static void ImGui_ImplGlfw_UpdateMouseData()
{
- // Update buttons
+ ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
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
+ const bool is_app_focused = true;
#else
- const bool focused = glfwGetWindowAttrib(g_Window, GLFW_FOCUSED) != 0;
+ const bool is_app_focused = glfwGetWindowAttrib(bd->Window, GLFW_FOCUSED) != 0;
#endif
- if (focused)
+ if (is_app_focused)
{
+ // (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
if (io.WantSetMousePos)
- {
- glfwSetCursorPos(g_Window, (double)mouse_pos_backup.x, (double)mouse_pos_backup.y);
- }
- else
+ glfwSetCursorPos(bd->Window, (double)io.MousePos.x, (double)io.MousePos.y);
+
+ // (Optional) Fallback to provide mouse position when focused (ImGui_ImplGlfw_CursorPosCallback already provides this when hovered or captured)
+ if (is_app_focused && bd->MouseWindow == NULL)
{
double mouse_x, mouse_y;
- glfwGetCursorPos(g_Window, &mouse_x, &mouse_y);
- io.MousePos = ImVec2((float)mouse_x, (float)mouse_y);
+ glfwGetCursorPos(bd->Window, &mouse_x, &mouse_y);
+ io.AddMousePosEvent((float)mouse_x, (float)mouse_y);
+ bd->LastValidMousePos = ImVec2((float)mouse_x, (float)mouse_y);
}
}
}
@@ -292,83 +539,105 @@ static void ImGui_ImplGlfw_UpdateMousePosAndButtons()
static void ImGui_ImplGlfw_UpdateMouseCursor()
{
ImGuiIO& io = ImGui::GetIO();
- if ((io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) || glfwGetInputMode(g_Window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED)
+ ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
+ if ((io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) || glfwGetInputMode(bd->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);
+ glfwSetInputMode(bd->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);
+ glfwSetCursor(bd->Window, bd->MouseCursors[imgui_cursor] ? bd->MouseCursors[imgui_cursor] : bd->MouseCursors[ImGuiMouseCursor_Arrow]);
+ glfwSetInputMode(bd->Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
}
}
+// Update gamepad inputs
+static inline float Saturate(float v) { return v < 0.0f ? 0.0f : v > 1.0f ? 1.0f : v; }
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; }
+ io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
+#if GLFW_HAS_GAMEPAD_API
+ GLFWgamepadstate gamepad;
+ if (!glfwGetGamepadState(GLFW_JOYSTICK_1, &gamepad))
+ return;
+ #define MAP_BUTTON(KEY_NO, BUTTON_NO, _UNUSED) do { io.AddKeyEvent(KEY_NO, gamepad.buttons[BUTTON_NO] != 0); } while (0)
+ #define MAP_ANALOG(KEY_NO, AXIS_NO, _UNUSED, V0, V1) do { float v = gamepad.axes[AXIS_NO]; v = (v - V0) / (V1 - V0); io.AddKeyAnalogEvent(KEY_NO, v > 0.10f, Saturate(v)); } while (0)
+#else
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);
+ if (axes_count == 0 || buttons_count == 0)
+ return;
+ #define MAP_BUTTON(KEY_NO, _UNUSED, BUTTON_NO) do { io.AddKeyEvent(KEY_NO, (buttons_count > BUTTON_NO && buttons[BUTTON_NO] == GLFW_PRESS)); } while (0)
+ #define MAP_ANALOG(KEY_NO, _UNUSED, AXIS_NO, V0, V1) do { float v = (axes_count > AXIS_NO) ? axes[AXIS_NO] : V0; v = (v - V0) / (V1 - V0); io.AddKeyAnalogEvent(KEY_NO, v > 0.10f, Saturate(v)); } while (0)
+#endif
+ io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
+ MAP_BUTTON(ImGuiKey_GamepadStart, GLFW_GAMEPAD_BUTTON_START, 7);
+ MAP_BUTTON(ImGuiKey_GamepadBack, GLFW_GAMEPAD_BUTTON_BACK, 6);
+ MAP_BUTTON(ImGuiKey_GamepadFaceDown, GLFW_GAMEPAD_BUTTON_A, 0); // Xbox A, PS Cross
+ MAP_BUTTON(ImGuiKey_GamepadFaceRight, GLFW_GAMEPAD_BUTTON_B, 1); // Xbox B, PS Circle
+ MAP_BUTTON(ImGuiKey_GamepadFaceLeft, GLFW_GAMEPAD_BUTTON_X, 2); // Xbox X, PS Square
+ MAP_BUTTON(ImGuiKey_GamepadFaceUp, GLFW_GAMEPAD_BUTTON_Y, 3); // Xbox Y, PS Triangle
+ MAP_BUTTON(ImGuiKey_GamepadDpadLeft, GLFW_GAMEPAD_BUTTON_DPAD_LEFT, 13);
+ MAP_BUTTON(ImGuiKey_GamepadDpadRight, GLFW_GAMEPAD_BUTTON_DPAD_RIGHT, 11);
+ MAP_BUTTON(ImGuiKey_GamepadDpadUp, GLFW_GAMEPAD_BUTTON_DPAD_UP, 10);
+ MAP_BUTTON(ImGuiKey_GamepadDpadDown, GLFW_GAMEPAD_BUTTON_DPAD_DOWN, 12);
+ MAP_BUTTON(ImGuiKey_GamepadL1, GLFW_GAMEPAD_BUTTON_LEFT_BUMPER, 4);
+ MAP_BUTTON(ImGuiKey_GamepadR1, GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER, 5);
+ MAP_ANALOG(ImGuiKey_GamepadL2, GLFW_GAMEPAD_AXIS_LEFT_TRIGGER, 4, -0.75f, +1.0f);
+ MAP_ANALOG(ImGuiKey_GamepadR2, GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER, 5, -0.75f, +1.0f);
+ MAP_BUTTON(ImGuiKey_GamepadL3, GLFW_GAMEPAD_BUTTON_LEFT_THUMB, 8);
+ MAP_BUTTON(ImGuiKey_GamepadR3, GLFW_GAMEPAD_BUTTON_RIGHT_THUMB, 9);
+ MAP_ANALOG(ImGuiKey_GamepadLStickLeft, GLFW_GAMEPAD_AXIS_LEFT_X, 0, -0.25f, -1.0f);
+ MAP_ANALOG(ImGuiKey_GamepadLStickRight, GLFW_GAMEPAD_AXIS_LEFT_X, 0, +0.25f, +1.0f);
+ MAP_ANALOG(ImGuiKey_GamepadLStickUp, GLFW_GAMEPAD_AXIS_LEFT_Y, 1, -0.25f, -1.0f);
+ MAP_ANALOG(ImGuiKey_GamepadLStickDown, GLFW_GAMEPAD_AXIS_LEFT_Y, 1, +0.25f, +1.0f);
+ MAP_ANALOG(ImGuiKey_GamepadRStickLeft, GLFW_GAMEPAD_AXIS_RIGHT_X, 2, -0.25f, -1.0f);
+ MAP_ANALOG(ImGuiKey_GamepadRStickRight, GLFW_GAMEPAD_AXIS_RIGHT_X, 2, +0.25f, +1.0f);
+ MAP_ANALOG(ImGuiKey_GamepadRStickUp, GLFW_GAMEPAD_AXIS_RIGHT_Y, 3, -0.25f, -1.0f);
+ MAP_ANALOG(ImGuiKey_GamepadRStickDown, GLFW_GAMEPAD_AXIS_RIGHT_Y, 3, +0.25f, +1.0f);
#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().");
+ ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
+ IM_ASSERT(bd != NULL && "Did you call ImGui_ImplGlfw_InitForXXX()?");
// 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);
+ glfwGetWindowSize(bd->Window, &w, &h);
+ glfwGetFramebufferSize(bd->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);
+ io.DisplayFramebufferScale = ImVec2((float)display_w / (float)w, (float)display_h / (float)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;
+ io.DeltaTime = bd->Time > 0.0 ? (float)(current_time - bd->Time) : (float)(1.0f / 60.0f);
+ bd->Time = current_time;
- ImGui_ImplGlfw_UpdateMousePosAndButtons();
+ ImGui_ImplGlfw_UpdateMouseData();
ImGui_ImplGlfw_UpdateMouseCursor();
// Update game controllers (if enabled and available)
ImGui_ImplGlfw_UpdateGamepads();
}
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
diff --git a/3rdparty/imgui/backend/imgui_impl_glfw.h b/3rdparty/imgui/backend/imgui_impl_glfw.h
index 018f1a1..58712de 100644
--- a/3rdparty/imgui/backend/imgui_impl_glfw.h
+++ b/3rdparty/imgui/backend/imgui_impl_glfw.h
@@ -4,11 +4,12 @@
// Implemented features:
// [X] Platform: Clipboard support.
+// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
// [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).
+// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+).
-// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// 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
@@ -20,6 +21,7 @@
#include "imgui.h" // IMGUI_IMPL_API
struct GLFWwindow;
+struct GLFWmonitor;
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks);
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks);
@@ -27,10 +29,18 @@ IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool ins
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.
+// GLFW callbacks (installer)
+// - When calling Init with 'install_callbacks=true': ImGui_ImplGlfw_InstallCallbacks() is called. GLFW callbacks will be installed for you. They will chain-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 individual function yourself from your own GLFW callbacks.
+IMGUI_IMPL_API void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window);
+IMGUI_IMPL_API void ImGui_ImplGlfw_RestoreCallbacks(GLFWwindow* window);
+
+// GLFW callbacks (individual callbacks to call if you didn't install callbacks)
+IMGUI_IMPL_API void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused); // Since 1.84
+IMGUI_IMPL_API void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered); // Since 1.84
+IMGUI_IMPL_API void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double x, double y); // Since 1.87
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);
+IMGUI_IMPL_API void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor* monitor, int event);
diff --git a/3rdparty/imgui/backend/imgui_impl_metal.h b/3rdparty/imgui/backend/imgui_impl_metal.h
index 1db7d87..469516b 100644
--- a/3rdparty/imgui/backend/imgui_impl_metal.h
+++ b/3rdparty/imgui/backend/imgui_impl_metal.h
@@ -5,12 +5,19 @@
// [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.
+// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// 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
+//-----------------------------------------------------------------------------
+// ObjC API
+//-----------------------------------------------------------------------------
+
+#ifdef __OBJC__
+
@class MTLRenderPassDescriptor;
@protocol MTLDevice, MTLCommandBuffer, MTLRenderCommandEncoder;
@@ -26,3 +33,35 @@ 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();
+
+#endif
+
+//-----------------------------------------------------------------------------
+// C++ API
+//-----------------------------------------------------------------------------
+
+// Enable Metal C++ binding support with '#define IMGUI_IMPL_METAL_CPP' in your imconfig.h file
+// More info about using Metal from C++: https://developer.apple.com/metal/cpp/
+
+#ifdef IMGUI_IMPL_METAL_CPP
+
+#include <Metal/Metal.hpp>
+
+#ifndef __OBJC__
+
+IMGUI_IMPL_API bool ImGui_ImplMetal_Init(MTL::Device* device);
+IMGUI_IMPL_API void ImGui_ImplMetal_Shutdown();
+IMGUI_IMPL_API void ImGui_ImplMetal_NewFrame(MTL::RenderPassDescriptor* renderPassDescriptor);
+IMGUI_IMPL_API void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data,
+ MTL::CommandBuffer* commandBuffer,
+ MTL::RenderCommandEncoder* commandEncoder);
+
+// Called by Init/NewFrame/Shutdown
+IMGUI_IMPL_API bool ImGui_ImplMetal_CreateFontsTexture(MTL::Device* device);
+IMGUI_IMPL_API void ImGui_ImplMetal_DestroyFontsTexture();
+IMGUI_IMPL_API bool ImGui_ImplMetal_CreateDeviceObjects(MTL::Device* device);
+IMGUI_IMPL_API void ImGui_ImplMetal_DestroyDeviceObjects();
+
+#endif
+
+#endif
diff --git a/3rdparty/imgui/backend/imgui_impl_metal.mm b/3rdparty/imgui/backend/imgui_impl_metal.mm
index cb57c12..358103f 100644
--- a/3rdparty/imgui/backend/imgui_impl_metal.mm
+++ b/3rdparty/imgui/backend/imgui_impl_metal.mm
@@ -5,12 +5,17 @@
// [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.
+// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// 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)
+// 2022-01-03: Metal: Ignore ImDrawCmd where ElemCount == 0 (very rare but can technically be manufactured by user code).
+// 2021-12-30: Metal: Added Metal C++ support. Enable with '#define IMGUI_IMPL_METAL_CPP' in your imconfig.h file.
+// 2021-08-24: Metal: Fixed a crash when clipping rect larger than framebuffer is submitted. (#4464)
+// 2021-05-19: Metal: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
// 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.
@@ -74,7 +79,43 @@
static MetalContext *g_sharedMetalContext = nil;
-#pragma mark - ImGui API implementation
+#ifdef IMGUI_IMPL_METAL_CPP
+
+#pragma mark - Dear ImGui Metal C++ Backend API
+
+bool ImGui_ImplMetal_Init(MTL::Device* device)
+{
+ return ImGui_ImplMetal_Init((id<MTLDevice>)(device));
+}
+
+void ImGui_ImplMetal_NewFrame(MTL::RenderPassDescriptor* renderPassDescriptor)
+{
+ ImGui_ImplMetal_NewFrame((MTLRenderPassDescriptor*)(renderPassDescriptor));
+}
+
+void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data,
+ MTL::CommandBuffer* commandBuffer,
+ MTL::RenderCommandEncoder* commandEncoder)
+{
+ ImGui_ImplMetal_RenderDrawData(draw_data,
+ (id<MTLCommandBuffer>)(commandBuffer),
+ (id<MTLRenderCommandEncoder>)(commandEncoder));
+
+}
+
+bool ImGui_ImplMetal_CreateFontsTexture(MTL::Device* device)
+{
+ return ImGui_ImplMetal_CreateFontsTexture((id<MTLDevice>)(device));
+}
+
+bool ImGui_ImplMetal_CreateDeviceObjects(MTL::Device* device)
+{
+ return ImGui_ImplMetal_CreateDeviceObjects((id<MTLDevice>)(device));
+}
+
+#endif // #ifdef IMGUI_IMPL_METAL_CPP
+
+#pragma mark - Dear ImGui Metal Backend API
bool ImGui_ImplMetal_Init(id<MTLDevice> device)
{
@@ -502,36 +543,39 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
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;
+ ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
+ ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (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];
+ // Clamp to viewport as setScissorRect() won't accept values that are off bounds
+ if (clip_min.x < 0.0f) { clip_min.x = 0.0f; }
+ if (clip_min.y < 0.0f) { clip_min.y = 0.0f; }
+ if (clip_max.x > fb_width) { clip_max.x = (float)fb_width; }
+ if (clip_max.y > fb_height) { clip_max.y = (float)fb_height; }
+ if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
+ continue;
+ if (pcmd->ElemCount == 0) // drawIndexedPrimitives() validation doesn't accept this
+ continue;
+ // Apply scissor/clipping rectangle
+ MTLScissorRect scissorRect =
+ {
+ .x = NSUInteger(clip_min.x),
+ .y = NSUInteger(clip_min.y),
+ .width = NSUInteger(clip_max.x - clip_min.x),
+ .height = NSUInteger(clip_max.y - clip_min.y)
+ };
+ [commandEncoder setScissorRect:scissorRect];
- // Bind texture, Draw
- if (pcmd->TextureId != NULL)
- [commandEncoder setFragmentTexture:(__bridge id<MTLTexture>)(pcmd->TextureId) atIndex:0];
+ // Bind texture, Draw
+ if (ImTextureID tex_id = pcmd->GetTexID())
+ [commandEncoder setFragmentTexture:(__bridge id<MTLTexture>)(tex_id) 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)];
- }
+ [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)];
}
}
diff --git a/3rdparty/imgui/backend/imgui_impl_opengl2.cpp b/3rdparty/imgui/backend/imgui_impl_opengl2.cpp
index 5771049..17a6fae 100644
--- a/3rdparty/imgui/backend/imgui_impl_opengl2.cpp
+++ b/3rdparty/imgui/backend/imgui_impl_opengl2.cpp
@@ -4,7 +4,8 @@
// 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.
+// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// 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
@@ -18,6 +19,9 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
+// 2021-12-08: OpenGL: Fixed mishandling of the the ImDrawCmd::IdxOffset field! This is an old bug but it never had an effect until some internal rendering changes in 1.86.
+// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
+// 2021-05-19: OpenGL: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
// 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.
@@ -53,26 +57,52 @@
#include <GL/gl.h>
#endif
-// OpenGL Data
-static GLuint g_FontTexture = 0;
+struct ImGui_ImplOpenGL2_Data
+{
+ GLuint FontTexture;
+
+ ImGui_ImplOpenGL2_Data() { memset(this, 0, sizeof(*this)); }
+};
+
+// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
+// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
+static ImGui_ImplOpenGL2_Data* ImGui_ImplOpenGL2_GetBackendData()
+{
+ return ImGui::GetCurrentContext() ? (ImGui_ImplOpenGL2_Data*)ImGui::GetIO().BackendRendererUserData : NULL;
+}
// Functions
bool ImGui_ImplOpenGL2_Init()
{
- // Setup backend capabilities flags
ImGuiIO& io = ImGui::GetIO();
+ IM_ASSERT(io.BackendRendererUserData == NULL && "Already initialized a renderer backend!");
+
+ // Setup backend capabilities flags
+ ImGui_ImplOpenGL2_Data* bd = IM_NEW(ImGui_ImplOpenGL2_Data)();
+ io.BackendRendererUserData = (void*)bd;
io.BackendRendererName = "imgui_impl_opengl2";
+
return true;
}
void ImGui_ImplOpenGL2_Shutdown()
{
+ ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData();
+ IM_ASSERT(bd != NULL && "No renderer backend to shutdown, or already shutdown?");
+ ImGuiIO& io = ImGui::GetIO();
+
ImGui_ImplOpenGL2_DestroyDeviceObjects();
+ io.BackendRendererName = NULL;
+ io.BackendRendererUserData = NULL;
+ IM_DELETE(bd);
}
void ImGui_ImplOpenGL2_NewFrame()
{
- if (!g_FontTexture)
+ ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData();
+ IM_ASSERT(bd != NULL && "Did you call ImGui_ImplOpenGL2_Init()?");
+
+ if (!bd->FontTexture)
ImGui_ImplOpenGL2_CreateDeviceObjects();
}
@@ -172,23 +202,18 @@ void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data)
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;
+ ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
+ ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
+ if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
+ continue;
- 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));
+ // Apply scissor/clipping rectangle (Y is inverted in OpenGL)
+ glScissor((int)clip_min.x, (int)(fb_height - clip_max.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.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);
- }
+ // Bind texture, Draw
+ glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID());
+ glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer + pcmd->IdxOffset);
}
- idx_buffer += pcmd->ElemCount;
}
}
@@ -213,6 +238,7 @@ bool ImGui_ImplOpenGL2_CreateFontsTexture()
{
// Build texture atlas
ImGuiIO& io = ImGui::GetIO();
+ ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData();
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.
@@ -220,15 +246,15 @@ bool ImGui_ImplOpenGL2_CreateFontsTexture()
// 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);
+ glGenTextures(1, &bd->FontTexture);
+ glBindTexture(GL_TEXTURE_2D, bd->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);
+ io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontTexture);
// Restore state
glBindTexture(GL_TEXTURE_2D, last_texture);
@@ -238,12 +264,13 @@ bool ImGui_ImplOpenGL2_CreateFontsTexture()
void ImGui_ImplOpenGL2_DestroyFontsTexture()
{
- if (g_FontTexture)
+ ImGuiIO& io = ImGui::GetIO();
+ ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData();
+ if (bd->FontTexture)
{
- ImGuiIO& io = ImGui::GetIO();
- glDeleteTextures(1, &g_FontTexture);
+ glDeleteTextures(1, &bd->FontTexture);
io.Fonts->SetTexID(0);
- g_FontTexture = 0;
+ bd->FontTexture = 0;
}
}
diff --git a/3rdparty/imgui/backend/imgui_impl_opengl2.h b/3rdparty/imgui/backend/imgui_impl_opengl2.h
index c0e2976..d00d27f 100644
--- a/3rdparty/imgui/backend/imgui_impl_opengl2.h
+++ b/3rdparty/imgui/backend/imgui_impl_opengl2.h
@@ -4,7 +4,8 @@
// 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.
+// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// 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
diff --git a/3rdparty/imgui/backend/imgui_impl_opengl3.cpp b/3rdparty/imgui/backend/imgui_impl_opengl3.cpp
index b582851..0d3489c 100644
--- a/3rdparty/imgui/backend/imgui_impl_opengl3.cpp
+++ b/3rdparty/imgui/backend/imgui_impl_opengl3.cpp
@@ -7,12 +7,22 @@
// [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.
+// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// 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-12-15: OpenGL: Using buffer orphaning + glBufferSubData(), seems to fix leaks with multi-viewports with some Intel HD drivers.
+// 2021-08-23: OpenGL: Fixed ES 3.0 shader ("#version 300 es") use normal precision floats to avoid wobbly rendering at HD resolutions.
+// 2021-08-19: OpenGL: Embed and use our own minimal GL loader (imgui_impl_opengl3_loader.h), removing requirement and support for third-party loader.
+// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
+// 2021-06-25: OpenGL: Use OES_vertex_array extension on Emscripten + backup/restore current state.
+// 2021-06-21: OpenGL: Destroy individual vertex/fragment shader objects right after they are linked into the main shader.
+// 2021-05-24: OpenGL: Access GL_CLIP_ORIGIN when "GL_ARB_clip_control" extension is detected, inside of just OpenGL 4.5 version.
+// 2021-05-19: OpenGL: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
+// 2021-04-06: OpenGL: Don't try to read GL_CLIP_ORIGIN unless we're OpenGL 4.5 or greater.
// 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.
@@ -86,45 +96,64 @@
#include <stdint.h> // intptr_t
#endif
+// Clang warnings with -Weverything
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast
+#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
+#if __has_warning("-Wzero-as-null-pointer-constant")
+#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
+#endif
+#endif
+
// GL includes
#if defined(IMGUI_IMPL_OPENGL_ES2)
-#include <GLES2/gl2.h>
+#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV))
+#include <OpenGLES/ES2/gl.h> // Use GL ES 2
+#else
+#include <GLES2/gl2.h> // Use GL ES 2
+#endif
+#if defined(__EMSCRIPTEN__)
+#ifndef GL_GLEXT_PROTOTYPES
+#define GL_GLEXT_PROTOTYPES
+#endif
+#include <GLES2/gl2ext.h>
+#endif
#elif defined(IMGUI_IMPL_OPENGL_ES3)
+#if defined(__APPLE__)
+#include <TargetConditionals.h>
+#endif
#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.
+#elif !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM)
+// 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 using our own minimal custom loader based on gl3w.
+// In the rest of your app/engine, you can use another loader of your choice (gl3w, glew, glad, glbinding, glext, glLoadGen, etc.).
+// If you happen to be developing a new feature for this backend (imgui_impl_opengl3.cpp):
+// - You may need to regenerate imgui_impl_opengl3_loader.h to add new symbols. See https://github.com/dearimgui/gl3w_stripped
+// - You can temporarily use an unstripped version. See https://github.com/dearimgui/gl3w_stripped/releases
+// Changes to this backend using new APIs should be accompanied by a regenerated stripped loader version.
+#define IMGL3W_IMPL
+#include "imgui_impl_opengl3_loader.h"
#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
+
+// Vertex arrays are not supported on ES2/WebGL1 unless Emscripten which uses an extension
+#ifndef IMGUI_IMPL_OPENGL_ES2
+#define IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
+#elif defined(__EMSCRIPTEN__)
+#define IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
+#define glBindVertexArray glBindVertexArrayOES
+#define glGenVertexArrays glGenVertexArraysOES
+#define glDeleteVertexArrays glDeleteVertexArraysOES
+#define GL_VERTEX_ARRAY_BINDING GL_VERTEX_ARRAY_BINDING_OES
#endif
+
+// Desktop GL 2.0+ has glPolygonMode() which GL ES and WebGL don't have.
+#ifdef GL_POLYGON_MODE
+#define IMGUI_IMPL_HAS_POLYGON_MODE
#endif
// Desktop GL 3.2+ has glDrawElementsBaseVertex() which GL ES and WebGL don't have.
@@ -142,18 +171,58 @@ using namespace gl;
#define IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
#endif
+// Desktop GL use extension detection
+#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3)
+#define IMGUI_IMPL_OPENGL_MAY_HAVE_EXTENSIONS
+#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;
+struct ImGui_ImplOpenGL3_Data
+{
+ GLuint GlVersion; // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries (e.g. 320 for GL 3.2)
+ char GlslVersionString[32]; // Specified by user or detected based on compile time GL settings.
+ GLuint FontTexture;
+ GLuint ShaderHandle;
+ GLint AttribLocationTex; // Uniforms location
+ GLint AttribLocationProjMtx;
+ GLuint AttribLocationVtxPos; // Vertex attributes location
+ GLuint AttribLocationVtxUV;
+ GLuint AttribLocationVtxColor;
+ unsigned int VboHandle, ElementsHandle;
+ GLsizeiptr VertexBufferSize;
+ GLsizeiptr IndexBufferSize;
+ bool HasClipOrigin;
+
+ ImGui_ImplOpenGL3_Data() { memset(this, 0, sizeof(*this)); }
+};
+
+// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
+// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
+static ImGui_ImplOpenGL3_Data* ImGui_ImplOpenGL3_GetBackendData()
+{
+ return ImGui::GetCurrentContext() ? (ImGui_ImplOpenGL3_Data*)ImGui::GetIO().BackendRendererUserData : NULL;
+}
// Functions
bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
{
+ ImGuiIO& io = ImGui::GetIO();
+ IM_ASSERT(io.BackendRendererUserData == NULL && "Already initialized a renderer backend!");
+
+ // Initialize our loader
+#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM)
+ if (imgl3wInit() != 0)
+ {
+ fprintf(stderr, "Failed to initialize OpenGL loader!\n");
+ return false;
+ }
+#endif
+
+ // Setup backend capabilities flags
+ ImGui_ImplOpenGL3_Data* bd = IM_NEW(ImGui_ImplOpenGL3_Data)();
+ io.BackendRendererUserData = (void*)bd;
+ io.BackendRendererName = "imgui_impl_opengl3";
+
// Query for GL version (e.g. 320 for GL 3.2)
#if !defined(IMGUI_IMPL_OPENGL_ES2)
GLint major = 0;
@@ -166,85 +235,80 @@ bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
const char* gl_version = (const char*)glGetString(GL_VERSION);
sscanf(gl_version, "%d.%d", &major, &minor);
}
- g_GlVersion = (GLuint)(major * 100 + minor * 10);
+ bd->GlVersion = (GLuint)(major * 100 + minor * 10);
#else
- g_GlVersion = 200; // GLES 2
+ bd->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)
+ if (bd->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)
+ {
+#if defined(IMGUI_IMPL_OPENGL_ES2)
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
+ }
+ IM_ASSERT((int)strlen(glsl_version) + 2 < IM_ARRAYSIZE(bd->GlslVersionString));
+ strcpy(bd->GlslVersionString, glsl_version);
+ strcat(bd->GlslVersionString, "\n");
// 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.
+ // IF YOU GET A CRASH HERE: it probably means the OpenGL function loader didn't do its job. Let us know!
GLint current_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &current_texture);
+ // Detect extensions we support
+ bd->HasClipOrigin = (bd->GlVersion >= 450);
+#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_EXTENSIONS
+ GLint num_extensions = 0;
+ glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions);
+ for (GLint i = 0; i < num_extensions; i++)
+ {
+ const char* extension = (const char*)glGetStringi(GL_EXTENSIONS, i);
+ if (extension != NULL && strcmp(extension, "GL_ARB_clip_control") == 0)
+ bd->HasClipOrigin = true;
+ }
+#endif
+
return true;
}
void ImGui_ImplOpenGL3_Shutdown()
{
+ ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
+ IM_ASSERT(bd != NULL && "No renderer backend to shutdown, or already shutdown?");
+ ImGuiIO& io = ImGui::GetIO();
+
ImGui_ImplOpenGL3_DestroyDeviceObjects();
+ io.BackendRendererName = NULL;
+ io.BackendRendererUserData = NULL;
+ IM_DELETE(bd);
}
void ImGui_ImplOpenGL3_NewFrame()
{
- if (!g_ShaderHandle)
+ ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
+ IM_ASSERT(bd != NULL && "Did you call ImGui_ImplOpenGL3_Init()?");
+
+ if (!bd->ShaderHandle)
ImGui_ImplOpenGL3_CreateDeviceObjects();
}
static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object)
{
+ ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
+
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
@@ -254,19 +318,22 @@ static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_wid
glDisable(GL_STENCIL_TEST);
glEnable(GL_SCISSOR_TEST);
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
- if (g_GlVersion >= 310)
+ if (bd->GlVersion >= 310)
glDisable(GL_PRIMITIVE_RESTART);
#endif
-#ifdef GL_POLYGON_MODE
+#ifdef IMGUI_IMPL_HAS_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__)
+#if defined(GL_CLIP_ORIGIN)
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;
+ if (bd->HasClipOrigin)
+ {
+ 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
@@ -276,7 +343,7 @@ static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_wid
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 defined(GL_CLIP_ORIGIN)
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] =
@@ -286,29 +353,29 @@ static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_wid
{ 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]);
+ glUseProgram(bd->ShaderHandle);
+ glUniform1i(bd->AttribLocationTex, 0);
+ glUniformMatrix4fv(bd->AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
- if (g_GlVersion >= 330)
+ if (bd->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
+#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
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));
+ glBindBuffer(GL_ARRAY_BUFFER, bd->VboHandle);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bd->ElementsHandle);
+ glEnableVertexAttribArray(bd->AttribLocationVtxPos);
+ glEnableVertexAttribArray(bd->AttribLocationVtxUV);
+ glEnableVertexAttribArray(bd->AttribLocationVtxColor);
+ glVertexAttribPointer(bd->AttribLocationVtxPos, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, pos));
+ glVertexAttribPointer(bd->AttribLocationVtxUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, uv));
+ glVertexAttribPointer(bd->AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, col));
}
// OpenGL3 Render function.
@@ -322,19 +389,21 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
if (fb_width <= 0 || fb_height <= 0)
return;
+ ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
+
// 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; }
+ GLuint last_sampler; if (bd->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
+#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
GLuint last_vertex_array_object; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, (GLint*)&last_vertex_array_object);
#endif
-#ifdef GL_POLYGON_MODE
+#ifdef IMGUI_IMPL_HAS_POLYGON_MODE
GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode);
#endif
GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport);
@@ -351,14 +420,14 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
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;
+ GLboolean last_enable_primitive_restart = (bd->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
+#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
glGenVertexArrays(1, &vertex_array_object);
#endif
ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
@@ -373,8 +442,20 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
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);
+ GLsizeiptr vtx_buffer_size = (GLsizeiptr)cmd_list->VtxBuffer.Size * (int)sizeof(ImDrawVert);
+ GLsizeiptr idx_buffer_size = (GLsizeiptr)cmd_list->IdxBuffer.Size * (int)sizeof(ImDrawIdx);
+ if (bd->VertexBufferSize < vtx_buffer_size)
+ {
+ bd->VertexBufferSize = vtx_buffer_size;
+ glBufferData(GL_ARRAY_BUFFER, bd->VertexBufferSize, NULL, GL_STREAM_DRAW);
+ }
+ if (bd->IndexBufferSize < idx_buffer_size)
+ {
+ bd->IndexBufferSize = idx_buffer_size;
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, bd->IndexBufferSize, NULL, GL_STREAM_DRAW);
+ }
+ glBufferSubData(GL_ARRAY_BUFFER, 0, vtx_buffer_size, (const GLvoid*)cmd_list->VtxBuffer.Data);
+ glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, idx_buffer_size, (const GLvoid*)cmd_list->IdxBuffer.Data);
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
{
@@ -391,32 +472,28 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
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;
+ ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
+ ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
+ if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
+ continue;
- 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));
+ // Apply scissor/clipping rectangle (Y is inverted in OpenGL)
+ glScissor((int)clip_min.x, (int)((float)fb_height - clip_max.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y));
- // Bind texture, Draw
- glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);
+ // Bind texture, Draw
+ glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID());
#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
+ if (bd->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)));
- }
+ 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
+#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
glDeleteVertexArrays(1, &vertex_array_object);
#endif
@@ -424,11 +501,11 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
glUseProgram(last_program);
glBindTexture(GL_TEXTURE_2D, last_texture);
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
- if (g_GlVersion >= 330)
+ if (bd->GlVersion >= 330)
glBindSampler(0, last_sampler);
#endif
glActiveTexture(last_active_texture);
-#ifndef IMGUI_IMPL_OPENGL_ES2
+#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
glBindVertexArray(last_vertex_array_object);
#endif
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
@@ -440,20 +517,23 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
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); }
+ if (bd->GlVersion >= 310) { if (last_enable_primitive_restart) glEnable(GL_PRIMITIVE_RESTART); else glDisable(GL_PRIMITIVE_RESTART); }
#endif
-#ifdef GL_POLYGON_MODE
+#ifdef IMGUI_IMPL_HAS_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]);
+ (void)bd; // Not all compilation paths use this
}
bool ImGui_ImplOpenGL3_CreateFontsTexture()
{
- // Build texture atlas
ImGuiIO& io = ImGui::GetIO();
+ ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
+
+ // Build texture atlas
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.
@@ -461,17 +541,17 @@ bool ImGui_ImplOpenGL3_CreateFontsTexture()
// 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);
+ glGenTextures(1, &bd->FontTexture);
+ glBindTexture(GL_TEXTURE_2D, bd->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
+#ifdef GL_UNPACK_ROW_LENGTH // Not on WebGL/ES
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);
+ io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontTexture);
// Restore state
glBindTexture(GL_TEXTURE_2D, last_texture);
@@ -481,23 +561,25 @@ bool ImGui_ImplOpenGL3_CreateFontsTexture()
void ImGui_ImplOpenGL3_DestroyFontsTexture()
{
- if (g_FontTexture)
+ ImGuiIO& io = ImGui::GetIO();
+ ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
+ if (bd->FontTexture)
{
- ImGuiIO& io = ImGui::GetIO();
- glDeleteTextures(1, &g_FontTexture);
+ glDeleteTextures(1, &bd->FontTexture);
io.Fonts->SetTexID(0);
- g_FontTexture = 0;
+ bd->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)
{
+ ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
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);
+ fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to compile %s! With GLSL: %s\n", desc, bd->GlslVersionString);
if (log_length > 1)
{
ImVector<char> buf;
@@ -511,11 +593,12 @@ static bool CheckShader(GLuint handle, const char* desc)
// 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)
{
+ ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
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);
+ fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to link %s! With GLSL %s\n", desc, bd->GlslVersionString);
if (log_length > 1)
{
ImVector<char> buf;
@@ -528,18 +611,20 @@ static bool CheckProgram(GLuint handle, const char* desc)
bool ImGui_ImplOpenGL3_CreateDeviceObjects()
{
+ ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
+
// 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
+#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
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);
+ sscanf(bd->GlslVersionString, "#version %d", &glsl_version);
const GLchar* vertex_shader_glsl_120 =
"uniform mat4 ProjMtx;\n"
@@ -570,7 +655,7 @@ bool ImGui_ImplOpenGL3_CreateDeviceObjects()
"}\n";
const GLchar* vertex_shader_glsl_300_es =
- "precision mediump float;\n"
+ "precision highp float;\n"
"layout (location = 0) in vec2 Position;\n"
"layout (location = 1) in vec2 UV;\n"
"layout (location = 2) in vec4 Color;\n"
@@ -666,40 +751,46 @@ bool ImGui_ImplOpenGL3_CreateDeviceObjects()
}
// 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* vertex_shader_with_version[2] = { bd->GlslVersionString, vertex_shader };
+ GLuint vert_handle = glCreateShader(GL_VERTEX_SHADER);
+ glShaderSource(vert_handle, 2, vertex_shader_with_version, NULL);
+ glCompileShader(vert_handle);
+ CheckShader(vert_handle, "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");
+ const GLchar* fragment_shader_with_version[2] = { bd->GlslVersionString, fragment_shader };
+ GLuint frag_handle = glCreateShader(GL_FRAGMENT_SHADER);
+ glShaderSource(frag_handle, 2, fragment_shader_with_version, NULL);
+ glCompileShader(frag_handle);
+ CheckShader(frag_handle, "fragment shader");
- g_ShaderHandle = glCreateProgram();
- glAttachShader(g_ShaderHandle, g_VertHandle);
- glAttachShader(g_ShaderHandle, g_FragHandle);
- glLinkProgram(g_ShaderHandle);
- CheckProgram(g_ShaderHandle, "shader program");
+ // Link
+ bd->ShaderHandle = glCreateProgram();
+ glAttachShader(bd->ShaderHandle, vert_handle);
+ glAttachShader(bd->ShaderHandle, frag_handle);
+ glLinkProgram(bd->ShaderHandle);
+ CheckProgram(bd->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");
+ glDetachShader(bd->ShaderHandle, vert_handle);
+ glDetachShader(bd->ShaderHandle, frag_handle);
+ glDeleteShader(vert_handle);
+ glDeleteShader(frag_handle);
+
+ bd->AttribLocationTex = glGetUniformLocation(bd->ShaderHandle, "Texture");
+ bd->AttribLocationProjMtx = glGetUniformLocation(bd->ShaderHandle, "ProjMtx");
+ bd->AttribLocationVtxPos = (GLuint)glGetAttribLocation(bd->ShaderHandle, "Position");
+ bd->AttribLocationVtxUV = (GLuint)glGetAttribLocation(bd->ShaderHandle, "UV");
+ bd->AttribLocationVtxColor = (GLuint)glGetAttribLocation(bd->ShaderHandle, "Color");
// Create buffers
- glGenBuffers(1, &g_VboHandle);
- glGenBuffers(1, &g_ElementsHandle);
+ glGenBuffers(1, &bd->VboHandle);
+ glGenBuffers(1, &bd->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
+#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
glBindVertexArray(last_vertex_array);
#endif
@@ -708,13 +799,13 @@ bool ImGui_ImplOpenGL3_CreateDeviceObjects()
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_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
+ if (bd->VboHandle) { glDeleteBuffers(1, &bd->VboHandle); bd->VboHandle = 0; }
+ if (bd->ElementsHandle) { glDeleteBuffers(1, &bd->ElementsHandle); bd->ElementsHandle = 0; }
+ if (bd->ShaderHandle) { glDeleteProgram(bd->ShaderHandle); bd->ShaderHandle = 0; }
ImGui_ImplOpenGL3_DestroyFontsTexture();
}
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
diff --git a/3rdparty/imgui/backend/imgui_impl_opengl3.h b/3rdparty/imgui/backend/imgui_impl_opengl3.h
index 8c0126d..98c9aca 100644
--- a/3rdparty/imgui/backend/imgui_impl_opengl3.h
+++ b/3rdparty/imgui/backend/imgui_impl_opengl3.h
@@ -7,15 +7,11 @@
// [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.
+// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// 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"
@@ -40,48 +36,20 @@ IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects();
//#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.
+// You can explicitly select GLES2 or GLES3 API 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)
+ && !defined(IMGUI_IMPL_OPENGL_ES3)
// Try to detect GLES on matching platforms
#if defined(__APPLE__)
-#include "TargetConditionals.h"
+#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
+// Otherwise imgui_impl_opengl3_loader.h will be used.
#endif
#endif
diff --git a/3rdparty/imgui/backend/imgui_impl_opengl3_loader.h b/3rdparty/imgui/backend/imgui_impl_opengl3_loader.h
new file mode 100644
index 0000000..e24760d
--- /dev/null
+++ b/3rdparty/imgui/backend/imgui_impl_opengl3_loader.h
@@ -0,0 +1,757 @@
+//-----------------------------------------------------------------------------
+// About imgui_impl_opengl3_loader.h:
+//
+// We embed our own OpenGL loader to not require user to provide their own or to have to use ours,
+// which proved to be endless problems for users.
+// Our loader is custom-generated, based on gl3w but automatically filtered to only include
+// enums/functions that we use in our imgui_impl_opengl3.cpp source file in order to be small.
+//
+// YOU SHOULD NOT NEED TO INCLUDE/USE THIS DIRECTLY. THIS IS USED BY imgui_impl_opengl3.cpp ONLY.
+// THE REST OF YOUR APP SHOULD USE A DIFFERENT GL LOADER: ANY GL LOADER OF YOUR CHOICE.
+//
+// Regenerate with:
+// python gl3w_gen.py --output ../imgui/backends/imgui_impl_opengl3_loader.h --ref ../imgui/backends/imgui_impl_opengl3.cpp ./extra_symbols.txt
+//
+// More info:
+// https://github.com/dearimgui/gl3w_stripped
+// https://github.com/ocornut/imgui/issues/4445
+//-----------------------------------------------------------------------------
+
+/*
+ * This file was generated with gl3w_gen.py, part of imgl3w
+ * (hosted at https://github.com/dearimgui/gl3w_stripped)
+ *
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __gl3w_h_
+#define __gl3w_h_
+
+// Adapted from KHR/khrplatform.h to avoid including entire file.
+#ifndef __khrplatform_h_
+typedef float khronos_float_t;
+typedef signed char khronos_int8_t;
+typedef unsigned char khronos_uint8_t;
+typedef signed short int khronos_int16_t;
+typedef unsigned short int khronos_uint16_t;
+#ifdef _WIN64
+typedef signed long long int khronos_intptr_t;
+typedef signed long long int khronos_ssize_t;
+#else
+typedef signed long int khronos_intptr_t;
+typedef signed long int khronos_ssize_t;
+#endif
+
+#if defined(_MSC_VER) && !defined(__clang__)
+typedef signed __int64 khronos_int64_t;
+typedef unsigned __int64 khronos_uint64_t;
+#elif (defined(__clang__) || defined(__GNUC__)) && (__cplusplus < 201100)
+#include <stdint.h>
+typedef int64_t khronos_int64_t;
+typedef uint64_t khronos_uint64_t;
+#else
+typedef signed long long khronos_int64_t;
+typedef unsigned long long khronos_uint64_t;
+#endif
+#endif // __khrplatform_h_
+
+#ifndef __gl_glcorearb_h_
+#define __gl_glcorearb_h_ 1
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+** Copyright 2013-2020 The Khronos Group Inc.
+** SPDX-License-Identifier: MIT
+**
+** This header is generated from the Khronos OpenGL / OpenGL ES XML
+** API Registry. The current version of the Registry, generator scripts
+** used to make the header, and the header can be found at
+** https://github.com/KhronosGroup/OpenGL-Registry
+*/
+#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN 1
+#endif
+#include <windows.h>
+#endif
+#ifndef APIENTRY
+#define APIENTRY
+#endif
+#ifndef APIENTRYP
+#define APIENTRYP APIENTRY *
+#endif
+#ifndef GLAPI
+#define GLAPI extern
+#endif
+/* glcorearb.h is for use with OpenGL core profile implementations.
+** It should should be placed in the same directory as gl.h and
+** included as <GL/glcorearb.h>.
+**
+** glcorearb.h includes only APIs in the latest OpenGL core profile
+** implementation together with APIs in newer ARB extensions which
+** can be supported by the core profile. It does not, and never will
+** include functionality removed from the core profile, such as
+** fixed-function vertex and fragment processing.
+**
+** Do not #include both <GL/glcorearb.h> and either of <GL/gl.h> or
+** <GL/glext.h> in the same source file.
+*/
+/* Generated C header for:
+ * API: gl
+ * Profile: core
+ * Versions considered: .*
+ * Versions emitted: .*
+ * Default extensions included: glcore
+ * Additional extensions included: _nomatch_^
+ * Extensions removed: _nomatch_^
+ */
+#ifndef GL_VERSION_1_0
+typedef void GLvoid;
+typedef unsigned int GLenum;
+
+typedef khronos_float_t GLfloat;
+typedef int GLint;
+typedef int GLsizei;
+typedef unsigned int GLbitfield;
+typedef double GLdouble;
+typedef unsigned int GLuint;
+typedef unsigned char GLboolean;
+typedef khronos_uint8_t GLubyte;
+#define GL_COLOR_BUFFER_BIT 0x00004000
+#define GL_FALSE 0
+#define GL_TRUE 1
+#define GL_TRIANGLES 0x0004
+#define GL_ONE 1
+#define GL_SRC_ALPHA 0x0302
+#define GL_ONE_MINUS_SRC_ALPHA 0x0303
+#define GL_FRONT_AND_BACK 0x0408
+#define GL_POLYGON_MODE 0x0B40
+#define GL_CULL_FACE 0x0B44
+#define GL_DEPTH_TEST 0x0B71
+#define GL_STENCIL_TEST 0x0B90
+#define GL_VIEWPORT 0x0BA2
+#define GL_BLEND 0x0BE2
+#define GL_SCISSOR_BOX 0x0C10
+#define GL_SCISSOR_TEST 0x0C11
+#define GL_UNPACK_ROW_LENGTH 0x0CF2
+#define GL_PACK_ALIGNMENT 0x0D05
+#define GL_TEXTURE_2D 0x0DE1
+#define GL_UNSIGNED_BYTE 0x1401
+#define GL_UNSIGNED_SHORT 0x1403
+#define GL_UNSIGNED_INT 0x1405
+#define GL_FLOAT 0x1406
+#define GL_RGBA 0x1908
+#define GL_FILL 0x1B02
+#define GL_VERSION 0x1F02
+#define GL_EXTENSIONS 0x1F03
+#define GL_LINEAR 0x2601
+#define GL_TEXTURE_MAG_FILTER 0x2800
+#define GL_TEXTURE_MIN_FILTER 0x2801
+typedef void (APIENTRYP PFNGLPOLYGONMODEPROC) (GLenum face, GLenum mode);
+typedef void (APIENTRYP PFNGLSCISSORPROC) (GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLTEXPARAMETERIPROC) (GLenum target, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLTEXIMAGE2DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);
+typedef void (APIENTRYP PFNGLCLEARPROC) (GLbitfield mask);
+typedef void (APIENTRYP PFNGLCLEARCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+typedef void (APIENTRYP PFNGLDISABLEPROC) (GLenum cap);
+typedef void (APIENTRYP PFNGLENABLEPROC) (GLenum cap);
+typedef void (APIENTRYP PFNGLPIXELSTOREIPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLREADPIXELSPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels);
+typedef GLenum (APIENTRYP PFNGLGETERRORPROC) (void);
+typedef void (APIENTRYP PFNGLGETINTEGERVPROC) (GLenum pname, GLint *data);
+typedef const GLubyte *(APIENTRYP PFNGLGETSTRINGPROC) (GLenum name);
+typedef GLboolean (APIENTRYP PFNGLISENABLEDPROC) (GLenum cap);
+typedef void (APIENTRYP PFNGLVIEWPORTPROC) (GLint x, GLint y, GLsizei width, GLsizei height);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPolygonMode (GLenum face, GLenum mode);
+GLAPI void APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param);
+GLAPI void APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);
+GLAPI void APIENTRY glClear (GLbitfield mask);
+GLAPI void APIENTRY glClearColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+GLAPI void APIENTRY glDisable (GLenum cap);
+GLAPI void APIENTRY glEnable (GLenum cap);
+GLAPI void APIENTRY glPixelStorei (GLenum pname, GLint param);
+GLAPI void APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels);
+GLAPI GLenum APIENTRY glGetError (void);
+GLAPI void APIENTRY glGetIntegerv (GLenum pname, GLint *data);
+GLAPI const GLubyte *APIENTRY glGetString (GLenum name);
+GLAPI GLboolean APIENTRY glIsEnabled (GLenum cap);
+GLAPI void APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height);
+#endif
+#endif /* GL_VERSION_1_0 */
+#ifndef GL_VERSION_1_1
+typedef khronos_float_t GLclampf;
+typedef double GLclampd;
+#define GL_TEXTURE_BINDING_2D 0x8069
+typedef void (APIENTRYP PFNGLDRAWELEMENTSPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices);
+typedef void (APIENTRYP PFNGLBINDTEXTUREPROC) (GLenum target, GLuint texture);
+typedef void (APIENTRYP PFNGLDELETETEXTURESPROC) (GLsizei n, const GLuint *textures);
+typedef void (APIENTRYP PFNGLGENTEXTURESPROC) (GLsizei n, GLuint *textures);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const void *indices);
+GLAPI void APIENTRY glBindTexture (GLenum target, GLuint texture);
+GLAPI void APIENTRY glDeleteTextures (GLsizei n, const GLuint *textures);
+GLAPI void APIENTRY glGenTextures (GLsizei n, GLuint *textures);
+#endif
+#endif /* GL_VERSION_1_1 */
+#ifndef GL_VERSION_1_3
+#define GL_TEXTURE0 0x84C0
+#define GL_ACTIVE_TEXTURE 0x84E0
+typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glActiveTexture (GLenum texture);
+#endif
+#endif /* GL_VERSION_1_3 */
+#ifndef GL_VERSION_1_4
+#define GL_BLEND_DST_RGB 0x80C8
+#define GL_BLEND_SRC_RGB 0x80C9
+#define GL_BLEND_DST_ALPHA 0x80CA
+#define GL_BLEND_SRC_ALPHA 0x80CB
+#define GL_FUNC_ADD 0x8006
+typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
+typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendFuncSeparate (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
+GLAPI void APIENTRY glBlendEquation (GLenum mode);
+#endif
+#endif /* GL_VERSION_1_4 */
+#ifndef GL_VERSION_1_5
+typedef khronos_ssize_t GLsizeiptr;
+typedef khronos_intptr_t GLintptr;
+#define GL_ARRAY_BUFFER 0x8892
+#define GL_ELEMENT_ARRAY_BUFFER 0x8893
+#define GL_ARRAY_BUFFER_BINDING 0x8894
+#define GL_STREAM_DRAW 0x88E0
+typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer);
+typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers);
+typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers);
+typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const void *data, GLenum usage);
+typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const void *data);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBindBuffer (GLenum target, GLuint buffer);
+GLAPI void APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers);
+GLAPI void APIENTRY glGenBuffers (GLsizei n, GLuint *buffers);
+GLAPI void APIENTRY glBufferData (GLenum target, GLsizeiptr size, const void *data, GLenum usage);
+GLAPI void APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const void *data);
+#endif
+#endif /* GL_VERSION_1_5 */
+#ifndef GL_VERSION_2_0
+typedef char GLchar;
+typedef khronos_int16_t GLshort;
+typedef khronos_int8_t GLbyte;
+typedef khronos_uint16_t GLushort;
+#define GL_BLEND_EQUATION_RGB 0x8009
+#define GL_BLEND_EQUATION_ALPHA 0x883D
+#define GL_FRAGMENT_SHADER 0x8B30
+#define GL_VERTEX_SHADER 0x8B31
+#define GL_COMPILE_STATUS 0x8B81
+#define GL_LINK_STATUS 0x8B82
+#define GL_INFO_LOG_LENGTH 0x8B84
+#define GL_CURRENT_PROGRAM 0x8B8D
+#define GL_UPPER_LEFT 0x8CA2
+typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha);
+typedef void (APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader);
+typedef void (APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader);
+typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC) (void);
+typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type);
+typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program);
+typedef void (APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader);
+typedef void (APIENTRYP PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader);
+typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index);
+typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name);
+typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+typedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name);
+typedef void (APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program);
+typedef void (APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length);
+typedef void (APIENTRYP PFNGLUSEPROGRAMPROC) (GLuint program);
+typedef void (APIENTRYP PFNGLUNIFORM1IPROC) (GLint location, GLint v0);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha);
+GLAPI void APIENTRY glAttachShader (GLuint program, GLuint shader);
+GLAPI void APIENTRY glCompileShader (GLuint shader);
+GLAPI GLuint APIENTRY glCreateProgram (void);
+GLAPI GLuint APIENTRY glCreateShader (GLenum type);
+GLAPI void APIENTRY glDeleteProgram (GLuint program);
+GLAPI void APIENTRY glDeleteShader (GLuint shader);
+GLAPI void APIENTRY glDetachShader (GLuint program, GLuint shader);
+GLAPI void APIENTRY glEnableVertexAttribArray (GLuint index);
+GLAPI GLint APIENTRY glGetAttribLocation (GLuint program, const GLchar *name);
+GLAPI void APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+GLAPI void APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+GLAPI GLint APIENTRY glGetUniformLocation (GLuint program, const GLchar *name);
+GLAPI void APIENTRY glLinkProgram (GLuint program);
+GLAPI void APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length);
+GLAPI void APIENTRY glUseProgram (GLuint program);
+GLAPI void APIENTRY glUniform1i (GLint location, GLint v0);
+GLAPI void APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
+#endif
+#endif /* GL_VERSION_2_0 */
+#ifndef GL_VERSION_3_0
+typedef khronos_uint16_t GLhalf;
+#define GL_MAJOR_VERSION 0x821B
+#define GL_MINOR_VERSION 0x821C
+#define GL_NUM_EXTENSIONS 0x821D
+#define GL_FRAMEBUFFER_SRGB 0x8DB9
+#define GL_VERTEX_ARRAY_BINDING 0x85B5
+typedef void (APIENTRYP PFNGLGETBOOLEANI_VPROC) (GLenum target, GLuint index, GLboolean *data);
+typedef void (APIENTRYP PFNGLGETINTEGERI_VPROC) (GLenum target, GLuint index, GLint *data);
+typedef const GLubyte *(APIENTRYP PFNGLGETSTRINGIPROC) (GLenum name, GLuint index);
+typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC) (GLuint array);
+typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint *arrays);
+typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI const GLubyte *APIENTRY glGetStringi (GLenum name, GLuint index);
+GLAPI void APIENTRY glBindVertexArray (GLuint array);
+GLAPI void APIENTRY glDeleteVertexArrays (GLsizei n, const GLuint *arrays);
+GLAPI void APIENTRY glGenVertexArrays (GLsizei n, GLuint *arrays);
+#endif
+#endif /* GL_VERSION_3_0 */
+#ifndef GL_VERSION_3_1
+#define GL_VERSION_3_1 1
+#define GL_PRIMITIVE_RESTART 0x8F9D
+#endif /* GL_VERSION_3_1 */
+#ifndef GL_VERSION_3_2
+#define GL_VERSION_3_2 1
+typedef struct __GLsync *GLsync;
+typedef khronos_uint64_t GLuint64;
+typedef khronos_int64_t GLint64;
+typedef void (APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
+typedef void (APIENTRYP PFNGLGETINTEGER64I_VPROC) (GLenum target, GLuint index, GLint64 *data);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawElementsBaseVertex (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
+#endif
+#endif /* GL_VERSION_3_2 */
+#ifndef GL_VERSION_3_3
+#define GL_VERSION_3_3 1
+#define GL_SAMPLER_BINDING 0x8919
+typedef void (APIENTRYP PFNGLBINDSAMPLERPROC) (GLuint unit, GLuint sampler);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBindSampler (GLuint unit, GLuint sampler);
+#endif
+#endif /* GL_VERSION_3_3 */
+#ifndef GL_VERSION_4_1
+typedef void (APIENTRYP PFNGLGETFLOATI_VPROC) (GLenum target, GLuint index, GLfloat *data);
+typedef void (APIENTRYP PFNGLGETDOUBLEI_VPROC) (GLenum target, GLuint index, GLdouble *data);
+#endif /* GL_VERSION_4_1 */
+#ifndef GL_VERSION_4_3
+typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
+#endif /* GL_VERSION_4_3 */
+#ifndef GL_VERSION_4_5
+#define GL_CLIP_ORIGIN 0x935C
+typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKI_VPROC) (GLuint xfb, GLenum pname, GLuint index, GLint *param);
+typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKI64_VPROC) (GLuint xfb, GLenum pname, GLuint index, GLint64 *param);
+#endif /* GL_VERSION_4_5 */
+#ifndef GL_ARB_bindless_texture
+typedef khronos_uint64_t GLuint64EXT;
+#endif /* GL_ARB_bindless_texture */
+#ifndef GL_ARB_cl_event
+struct _cl_context;
+struct _cl_event;
+#endif /* GL_ARB_cl_event */
+#ifndef GL_ARB_clip_control
+#define GL_ARB_clip_control 1
+#endif /* GL_ARB_clip_control */
+#ifndef GL_ARB_debug_output
+typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
+#endif /* GL_ARB_debug_output */
+#ifndef GL_EXT_EGL_image_storage
+typedef void *GLeglImageOES;
+#endif /* GL_EXT_EGL_image_storage */
+#ifndef GL_EXT_direct_state_access
+typedef void (APIENTRYP PFNGLGETFLOATI_VEXTPROC) (GLenum pname, GLuint index, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETDOUBLEI_VEXTPROC) (GLenum pname, GLuint index, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETPOINTERI_VEXTPROC) (GLenum pname, GLuint index, void **params);
+typedef void (APIENTRYP PFNGLGETVERTEXARRAYINTEGERI_VEXTPROC) (GLuint vaobj, GLuint index, GLenum pname, GLint *param);
+typedef void (APIENTRYP PFNGLGETVERTEXARRAYPOINTERI_VEXTPROC) (GLuint vaobj, GLuint index, GLenum pname, void **param);
+#endif /* GL_EXT_direct_state_access */
+#ifndef GL_NV_draw_vulkan_image
+typedef void (APIENTRY *GLVULKANPROCNV)(void);
+#endif /* GL_NV_draw_vulkan_image */
+#ifndef GL_NV_gpu_shader5
+typedef khronos_int64_t GLint64EXT;
+#endif /* GL_NV_gpu_shader5 */
+#ifndef GL_NV_vertex_buffer_unified_memory
+typedef void (APIENTRYP PFNGLGETINTEGERUI64I_VNVPROC) (GLenum value, GLuint index, GLuint64EXT *result);
+#endif /* GL_NV_vertex_buffer_unified_memory */
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+#ifndef GL3W_API
+#define GL3W_API
+#endif
+
+#ifndef __gl_h_
+#define __gl_h_
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GL3W_OK 0
+#define GL3W_ERROR_INIT -1
+#define GL3W_ERROR_LIBRARY_OPEN -2
+#define GL3W_ERROR_OPENGL_VERSION -3
+
+typedef void (*GL3WglProc)(void);
+typedef GL3WglProc (*GL3WGetProcAddressProc)(const char *proc);
+
+/* gl3w api */
+GL3W_API int imgl3wInit(void);
+GL3W_API int imgl3wInit2(GL3WGetProcAddressProc proc);
+GL3W_API int imgl3wIsSupported(int major, int minor);
+GL3W_API GL3WglProc imgl3wGetProcAddress(const char *proc);
+
+/* gl3w internal state */
+union GL3WProcs {
+ GL3WglProc ptr[54];
+ struct {
+ PFNGLACTIVETEXTUREPROC ActiveTexture;
+ PFNGLATTACHSHADERPROC AttachShader;
+ PFNGLBINDBUFFERPROC BindBuffer;
+ PFNGLBINDSAMPLERPROC BindSampler;
+ PFNGLBINDTEXTUREPROC BindTexture;
+ PFNGLBINDVERTEXARRAYPROC BindVertexArray;
+ PFNGLBLENDEQUATIONPROC BlendEquation;
+ PFNGLBLENDEQUATIONSEPARATEPROC BlendEquationSeparate;
+ PFNGLBLENDFUNCSEPARATEPROC BlendFuncSeparate;
+ PFNGLBUFFERDATAPROC BufferData;
+ PFNGLBUFFERSUBDATAPROC BufferSubData;
+ PFNGLCLEARPROC Clear;
+ PFNGLCLEARCOLORPROC ClearColor;
+ PFNGLCOMPILESHADERPROC CompileShader;
+ PFNGLCREATEPROGRAMPROC CreateProgram;
+ PFNGLCREATESHADERPROC CreateShader;
+ PFNGLDELETEBUFFERSPROC DeleteBuffers;
+ PFNGLDELETEPROGRAMPROC DeleteProgram;
+ PFNGLDELETESHADERPROC DeleteShader;
+ PFNGLDELETETEXTURESPROC DeleteTextures;
+ PFNGLDELETEVERTEXARRAYSPROC DeleteVertexArrays;
+ PFNGLDETACHSHADERPROC DetachShader;
+ PFNGLDISABLEPROC Disable;
+ PFNGLDRAWELEMENTSPROC DrawElements;
+ PFNGLDRAWELEMENTSBASEVERTEXPROC DrawElementsBaseVertex;
+ PFNGLENABLEPROC Enable;
+ PFNGLENABLEVERTEXATTRIBARRAYPROC EnableVertexAttribArray;
+ PFNGLGENBUFFERSPROC GenBuffers;
+ PFNGLGENTEXTURESPROC GenTextures;
+ PFNGLGENVERTEXARRAYSPROC GenVertexArrays;
+ PFNGLGETATTRIBLOCATIONPROC GetAttribLocation;
+ PFNGLGETERRORPROC GetError;
+ PFNGLGETINTEGERVPROC GetIntegerv;
+ PFNGLGETPROGRAMINFOLOGPROC GetProgramInfoLog;
+ PFNGLGETPROGRAMIVPROC GetProgramiv;
+ PFNGLGETSHADERINFOLOGPROC GetShaderInfoLog;
+ PFNGLGETSHADERIVPROC GetShaderiv;
+ PFNGLGETSTRINGPROC GetString;
+ PFNGLGETSTRINGIPROC GetStringi;
+ PFNGLGETUNIFORMLOCATIONPROC GetUniformLocation;
+ PFNGLISENABLEDPROC IsEnabled;
+ PFNGLLINKPROGRAMPROC LinkProgram;
+ PFNGLPIXELSTOREIPROC PixelStorei;
+ PFNGLPOLYGONMODEPROC PolygonMode;
+ PFNGLREADPIXELSPROC ReadPixels;
+ PFNGLSCISSORPROC Scissor;
+ PFNGLSHADERSOURCEPROC ShaderSource;
+ PFNGLTEXIMAGE2DPROC TexImage2D;
+ PFNGLTEXPARAMETERIPROC TexParameteri;
+ PFNGLUNIFORM1IPROC Uniform1i;
+ PFNGLUNIFORMMATRIX4FVPROC UniformMatrix4fv;
+ PFNGLUSEPROGRAMPROC UseProgram;
+ PFNGLVERTEXATTRIBPOINTERPROC VertexAttribPointer;
+ PFNGLVIEWPORTPROC Viewport;
+ } gl;
+};
+
+GL3W_API extern union GL3WProcs imgl3wProcs;
+
+/* OpenGL functions */
+#define glActiveTexture imgl3wProcs.gl.ActiveTexture
+#define glAttachShader imgl3wProcs.gl.AttachShader
+#define glBindBuffer imgl3wProcs.gl.BindBuffer
+#define glBindSampler imgl3wProcs.gl.BindSampler
+#define glBindTexture imgl3wProcs.gl.BindTexture
+#define glBindVertexArray imgl3wProcs.gl.BindVertexArray
+#define glBlendEquation imgl3wProcs.gl.BlendEquation
+#define glBlendEquationSeparate imgl3wProcs.gl.BlendEquationSeparate
+#define glBlendFuncSeparate imgl3wProcs.gl.BlendFuncSeparate
+#define glBufferData imgl3wProcs.gl.BufferData
+#define glBufferSubData imgl3wProcs.gl.BufferSubData
+#define glClear imgl3wProcs.gl.Clear
+#define glClearColor imgl3wProcs.gl.ClearColor
+#define glCompileShader imgl3wProcs.gl.CompileShader
+#define glCreateProgram imgl3wProcs.gl.CreateProgram
+#define glCreateShader imgl3wProcs.gl.CreateShader
+#define glDeleteBuffers imgl3wProcs.gl.DeleteBuffers
+#define glDeleteProgram imgl3wProcs.gl.DeleteProgram
+#define glDeleteShader imgl3wProcs.gl.DeleteShader
+#define glDeleteTextures imgl3wProcs.gl.DeleteTextures
+#define glDeleteVertexArrays imgl3wProcs.gl.DeleteVertexArrays
+#define glDetachShader imgl3wProcs.gl.DetachShader
+#define glDisable imgl3wProcs.gl.Disable
+#define glDrawElements imgl3wProcs.gl.DrawElements
+#define glDrawElementsBaseVertex imgl3wProcs.gl.DrawElementsBaseVertex
+#define glEnable imgl3wProcs.gl.Enable
+#define glEnableVertexAttribArray imgl3wProcs.gl.EnableVertexAttribArray
+#define glGenBuffers imgl3wProcs.gl.GenBuffers
+#define glGenTextures imgl3wProcs.gl.GenTextures
+#define glGenVertexArrays imgl3wProcs.gl.GenVertexArrays
+#define glGetAttribLocation imgl3wProcs.gl.GetAttribLocation
+#define glGetError imgl3wProcs.gl.GetError
+#define glGetIntegerv imgl3wProcs.gl.GetIntegerv
+#define glGetProgramInfoLog imgl3wProcs.gl.GetProgramInfoLog
+#define glGetProgramiv imgl3wProcs.gl.GetProgramiv
+#define glGetShaderInfoLog imgl3wProcs.gl.GetShaderInfoLog
+#define glGetShaderiv imgl3wProcs.gl.GetShaderiv
+#define glGetString imgl3wProcs.gl.GetString
+#define glGetStringi imgl3wProcs.gl.GetStringi
+#define glGetUniformLocation imgl3wProcs.gl.GetUniformLocation
+#define glIsEnabled imgl3wProcs.gl.IsEnabled
+#define glLinkProgram imgl3wProcs.gl.LinkProgram
+#define glPixelStorei imgl3wProcs.gl.PixelStorei
+#define glPolygonMode imgl3wProcs.gl.PolygonMode
+#define glReadPixels imgl3wProcs.gl.ReadPixels
+#define glScissor imgl3wProcs.gl.Scissor
+#define glShaderSource imgl3wProcs.gl.ShaderSource
+#define glTexImage2D imgl3wProcs.gl.TexImage2D
+#define glTexParameteri imgl3wProcs.gl.TexParameteri
+#define glUniform1i imgl3wProcs.gl.Uniform1i
+#define glUniformMatrix4fv imgl3wProcs.gl.UniformMatrix4fv
+#define glUseProgram imgl3wProcs.gl.UseProgram
+#define glVertexAttribPointer imgl3wProcs.gl.VertexAttribPointer
+#define glViewport imgl3wProcs.gl.Viewport
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#ifdef IMGL3W_IMPL
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+#if defined(_WIN32)
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN 1
+#endif
+#include <windows.h>
+
+static HMODULE libgl;
+typedef PROC(__stdcall* GL3WglGetProcAddr)(LPCSTR);
+static GL3WglGetProcAddr wgl_get_proc_address;
+
+static int open_libgl(void)
+{
+ libgl = LoadLibraryA("opengl32.dll");
+ if (!libgl)
+ return GL3W_ERROR_LIBRARY_OPEN;
+ wgl_get_proc_address = (GL3WglGetProcAddr)GetProcAddress(libgl, "wglGetProcAddress");
+ return GL3W_OK;
+}
+
+static void close_libgl(void) { FreeLibrary(libgl); }
+static GL3WglProc get_proc(const char *proc)
+{
+ GL3WglProc res;
+ res = (GL3WglProc)wgl_get_proc_address(proc);
+ if (!res)
+ res = (GL3WglProc)GetProcAddress(libgl, proc);
+ return res;
+}
+#elif defined(__APPLE__)
+#include <dlfcn.h>
+
+static void *libgl;
+static int open_libgl(void)
+{
+ libgl = dlopen("/System/Library/Frameworks/OpenGL.framework/OpenGL", RTLD_LAZY | RTLD_LOCAL);
+ if (!libgl)
+ return GL3W_ERROR_LIBRARY_OPEN;
+ return GL3W_OK;
+}
+
+static void close_libgl(void) { dlclose(libgl); }
+
+static GL3WglProc get_proc(const char *proc)
+{
+ GL3WglProc res;
+ *(void **)(&res) = dlsym(libgl, proc);
+ return res;
+}
+#else
+#include <dlfcn.h>
+
+static void *libgl;
+static GL3WglProc (*glx_get_proc_address)(const GLubyte *);
+
+static int open_libgl(void)
+{
+ libgl = dlopen("libGL.so.1", RTLD_LAZY | RTLD_LOCAL);
+ if (!libgl)
+ return GL3W_ERROR_LIBRARY_OPEN;
+ *(void **)(&glx_get_proc_address) = dlsym(libgl, "glXGetProcAddressARB");
+ return GL3W_OK;
+}
+
+static void close_libgl(void) { dlclose(libgl); }
+
+static GL3WglProc get_proc(const char *proc)
+{
+ GL3WglProc res;
+ res = glx_get_proc_address((const GLubyte *)proc);
+ if (!res)
+ *(void **)(&res) = dlsym(libgl, proc);
+ return res;
+}
+#endif
+
+static struct { int major, minor; } version;
+
+static int parse_version(void)
+{
+ if (!glGetIntegerv)
+ return GL3W_ERROR_INIT;
+ glGetIntegerv(GL_MAJOR_VERSION, &version.major);
+ glGetIntegerv(GL_MINOR_VERSION, &version.minor);
+ if (version.major < 3)
+ return GL3W_ERROR_OPENGL_VERSION;
+ return GL3W_OK;
+}
+
+static void load_procs(GL3WGetProcAddressProc proc);
+
+int imgl3wInit(void)
+{
+ int res = open_libgl();
+ if (res)
+ return res;
+ atexit(close_libgl);
+ return imgl3wInit2(get_proc);
+}
+
+int imgl3wInit2(GL3WGetProcAddressProc proc)
+{
+ load_procs(proc);
+ return parse_version();
+}
+
+int imgl3wIsSupported(int major, int minor)
+{
+ if (major < 3)
+ return 0;
+ if (version.major == major)
+ return version.minor >= minor;
+ return version.major >= major;
+}
+
+GL3WglProc imgl3wGetProcAddress(const char *proc) { return get_proc(proc); }
+
+static const char *proc_names[] = {
+ "glActiveTexture",
+ "glAttachShader",
+ "glBindBuffer",
+ "glBindSampler",
+ "glBindTexture",
+ "glBindVertexArray",
+ "glBlendEquation",
+ "glBlendEquationSeparate",
+ "glBlendFuncSeparate",
+ "glBufferData",
+ "glBufferSubData",
+ "glClear",
+ "glClearColor",
+ "glCompileShader",
+ "glCreateProgram",
+ "glCreateShader",
+ "glDeleteBuffers",
+ "glDeleteProgram",
+ "glDeleteShader",
+ "glDeleteTextures",
+ "glDeleteVertexArrays",
+ "glDetachShader",
+ "glDisable",
+ "glDrawElements",
+ "glDrawElementsBaseVertex",
+ "glEnable",
+ "glEnableVertexAttribArray",
+ "glGenBuffers",
+ "glGenTextures",
+ "glGenVertexArrays",
+ "glGetAttribLocation",
+ "glGetError",
+ "glGetIntegerv",
+ "glGetProgramInfoLog",
+ "glGetProgramiv",
+ "glGetShaderInfoLog",
+ "glGetShaderiv",
+ "glGetString",
+ "glGetStringi",
+ "glGetUniformLocation",
+ "glIsEnabled",
+ "glLinkProgram",
+ "glPixelStorei",
+ "glPolygonMode",
+ "glReadPixels",
+ "glScissor",
+ "glShaderSource",
+ "glTexImage2D",
+ "glTexParameteri",
+ "glUniform1i",
+ "glUniformMatrix4fv",
+ "glUseProgram",
+ "glVertexAttribPointer",
+ "glViewport",
+};
+
+GL3W_API union GL3WProcs imgl3wProcs;
+
+static void load_procs(GL3WGetProcAddressProc proc)
+{
+ size_t i;
+ for (i = 0; i < ARRAY_SIZE(proc_names); i++)
+ imgl3wProcs.ptr[i] = proc(proc_names[i]);
+}
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/3rdparty/imgui/backend/imgui_impl_vulkan.cpp b/3rdparty/imgui/backend/imgui_impl_vulkan.cpp
index 167687e..dbd8b18 100644
--- a/3rdparty/imgui/backend/imgui_impl_vulkan.cpp
+++ b/3rdparty/imgui/backend/imgui_impl_vulkan.cpp
@@ -3,10 +3,18 @@
// 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
+// [!] Renderer: User texture binding. Use 'VkDescriptorSet' as ImTextureID. Read the FAQ about ImTextureID! See https://github.com/ocornut/imgui/pull/914 for discussions.
-// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Important: on 32-bit systems, user texture binding is only supported if your imconfig file has '#define ImTextureID ImU64'.
+// This is because we need ImTextureID to carry a 64-bit value and by default ImTextureID is defined as void*.
+// To build this on 32-bit systems and support texture changes:
+// - [Solution 1] IDE/msbuild: in "Properties/C++/Preprocessor Definitions" add 'ImTextureID=ImU64' (this is what we do in our .vcxproj files)
+// - [Solution 2] IDE/msbuild: in "Properties/C++/Preprocessor Definitions" add 'IMGUI_USER_CONFIG="my_imgui_config.h"' and inside 'my_imgui_config.h' add '#define ImTextureID ImU64' and as many other options as you like.
+// - [Solution 3] IDE/msbuild: edit imconfig.h and add '#define ImTextureID ImU64' (prefer solution 2 to create your own config file!)
+// - [Solution 4] command-line: add '/D ImTextureID=ImU64' to your cl.exe command-line (this is what we do in our batch files)
+
+// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// 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
@@ -22,6 +30,8 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
+// 2021-10-15: Vulkan: Call vkCmdSetScissor() at the end of render a full-viewport to reduce likehood of issues with people using VK_DYNAMIC_STATE_SCISSOR in their app without calling vkCmdSetScissor() explicitly every frame.
+// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
// 2021-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().
@@ -54,6 +64,11 @@
#include "imgui_impl_vulkan.h"
#include <stdio.h>
+// Visual Studio warnings
+#ifdef _MSC_VER
+#pragma warning (disable: 4127) // condition expression is constant
+#endif
+
// Reusable buffers used for rendering 1 current in-flight frame, for ImGui_ImplVulkan_RenderDrawData()
// [Please zero-clear before use!]
struct ImGui_ImplVulkanH_FrameRenderBuffers
@@ -76,33 +91,37 @@ struct ImGui_ImplVulkanH_WindowRenderBuffers
};
// 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
+struct ImGui_ImplVulkan_Data
+{
+ ImGui_ImplVulkan_InitInfo VulkanInitInfo;
+ VkRenderPass RenderPass;
+ VkDeviceSize BufferMemoryAlignment;
+ VkPipelineCreateFlags PipelineCreateFlags;
+ VkDescriptorSetLayout DescriptorSetLayout;
+ VkPipelineLayout PipelineLayout;
+ VkPipeline Pipeline;
+ uint32_t Subpass;
+ VkShaderModule ShaderModuleVert;
+ VkShaderModule ShaderModuleFrag;
-// 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;
+ // Font data
+ VkSampler FontSampler;
+ VkDeviceMemory FontMemory;
+ VkImage FontImage;
+ VkImageView FontView;
+ VkDescriptorSet FontDescriptorSet;
+ VkDeviceMemory UploadBufferMemory;
+ VkBuffer UploadBuffer;
-// Render buffers
-static ImGui_ImplVulkanH_WindowRenderBuffers g_MainWindowRenderBuffers;
+ // Render buffers
+ ImGui_ImplVulkanH_WindowRenderBuffers MainWindowRenderBuffers;
+
+ ImGui_ImplVulkan_Data()
+ {
+ memset(this, 0, sizeof(*this));
+ BufferMemoryAlignment = 256;
+ }
+};
// Forward Declarations
bool ImGui_ImplVulkan_CreateDeviceObjects();
@@ -117,6 +136,11 @@ void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkPhysicalDevice physical_devi
// Vulkan prototypes for use with custom loaders
// (see description of IMGUI_IMPL_VULKAN_NO_PROTOTYPES in imgui_impl_vulkan.h
#ifdef VK_NO_PROTOTYPES
+static bool g_FunctionsLoaded = false;
+#else
+static bool g_FunctionsLoaded = true;
+#endif
+#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) \
@@ -296,9 +320,18 @@ static uint32_t __glsl_shader_frag_spv[] =
// FUNCTIONS
//-----------------------------------------------------------------------------
+// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
+// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
+// FIXME: multi-context support is not tested and probably dysfunctional in this backend.
+static ImGui_ImplVulkan_Data* ImGui_ImplVulkan_GetBackendData()
+{
+ return ImGui::GetCurrentContext() ? (ImGui_ImplVulkan_Data*)ImGui::GetIO().BackendRendererUserData : NULL;
+}
+
static uint32_t ImGui_ImplVulkan_MemoryType(VkMemoryPropertyFlags properties, uint32_t type_bits)
{
- ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
+ ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
+ ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
VkPhysicalDeviceMemoryProperties prop;
vkGetPhysicalDeviceMemoryProperties(v->PhysicalDevice, &prop);
for (uint32_t i = 0; i < prop.memoryTypeCount; i++)
@@ -309,21 +342,25 @@ static uint32_t ImGui_ImplVulkan_MemoryType(VkMemoryPropertyFlags properties, ui
static void check_vk_result(VkResult err)
{
- ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
+ ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
+ if (!bd)
+ return;
+ ImGui_ImplVulkan_InitInfo* v = &bd->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;
+ ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
+ ImGui_ImplVulkan_InitInfo* v = &bd->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;
+ VkDeviceSize vertex_buffer_size_aligned = ((new_size - 1) / bd->BufferMemoryAlignment + 1) * bd->BufferMemoryAlignment;
VkBufferCreateInfo buffer_info = {};
buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
buffer_info.size = vertex_buffer_size_aligned;
@@ -334,7 +371,7 @@ static void CreateOrResizeBuffer(VkBuffer& buffer, VkDeviceMemory& buffer_memory
VkMemoryRequirements req;
vkGetBufferMemoryRequirements(v->Device, buffer, &req);
- g_BufferMemoryAlignment = (g_BufferMemoryAlignment > req.alignment) ? g_BufferMemoryAlignment : req.alignment;
+ bd->BufferMemoryAlignment = (bd->BufferMemoryAlignment > req.alignment) ? bd->BufferMemoryAlignment : req.alignment;
VkMemoryAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
alloc_info.allocationSize = req.size;
@@ -349,11 +386,11 @@ static void CreateOrResizeBuffer(VkBuffer& buffer, VkDeviceMemory& buffer_memory
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:
+ ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
+
+ // Bind pipeline:
{
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:
@@ -386,8 +423,8 @@ static void ImGui_ImplVulkan_SetupRenderState(ImDrawData* draw_data, VkPipeline
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);
+ vkCmdPushConstants(command_buffer, bd->PipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, sizeof(float) * 0, sizeof(float) * 2, scale);
+ vkCmdPushConstants(command_buffer, bd->PipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, sizeof(float) * 2, sizeof(float) * 2, translate);
}
}
@@ -400,12 +437,13 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm
if (fb_width <= 0 || fb_height <= 0)
return;
- ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
+ ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
+ ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
if (pipeline == VK_NULL_HANDLE)
- pipeline = g_Pipeline;
+ pipeline = bd->Pipeline;
// Allocate array to store enough vertex/index buffers
- ImGui_ImplVulkanH_WindowRenderBuffers* wrb = &g_MainWindowRenderBuffers;
+ ImGui_ImplVulkanH_WindowRenderBuffers* wrb = &bd->MainWindowRenderBuffers;
if (wrb->FrameRenderBuffers == NULL)
{
wrb->Index = 0;
@@ -484,42 +522,59 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm
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;
+ ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
+ ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (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;
+ // Clamp to viewport as vkCmdSetScissor() won't accept values that are off bounds
+ if (clip_min.x < 0.0f) { clip_min.x = 0.0f; }
+ if (clip_min.y < 0.0f) { clip_min.y = 0.0f; }
+ if (clip_max.x > fb_width) { clip_max.x = (float)fb_width; }
+ if (clip_max.y > fb_height) { clip_max.y = (float)fb_height; }
+ if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
+ continue;
- // 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);
+ // Apply scissor/clipping rectangle
+ VkRect2D scissor;
+ scissor.offset.x = (int32_t)(clip_min.x);
+ scissor.offset.y = (int32_t)(clip_min.y);
+ scissor.extent.width = (uint32_t)(clip_max.x - clip_min.x);
+ scissor.extent.height = (uint32_t)(clip_max.y - clip_min.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);
+ // Bind DescriptorSet with font or user texture
+ VkDescriptorSet desc_set[1] = { (VkDescriptorSet)pcmd->TextureId };
+ if (sizeof(ImTextureID) < sizeof(ImU64))
+ {
+ // We don't support texture switches if ImTextureID hasn't been redefined to be 64-bit. Do a flaky check that other textures haven't been used.
+ IM_ASSERT(pcmd->TextureId == (ImTextureID)bd->FontDescriptorSet);
+ desc_set[0] = bd->FontDescriptorSet;
}
+ vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 0, 1, desc_set, 0, NULL);
+
+ // 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;
}
+
+ // Note: at this point both vkCmdSetViewport() and vkCmdSetScissor() have been called.
+ // Our last values will leak into user/application rendering IF:
+ // - Your app uses a pipeline with VK_DYNAMIC_STATE_VIEWPORT or VK_DYNAMIC_STATE_SCISSOR dynamic state
+ // - And you forgot to call vkCmdSetViewport() and vkCmdSetScissor() yourself to explicitely set that state.
+ // If you use VK_DYNAMIC_STATE_VIEWPORT or VK_DYNAMIC_STATE_SCISSOR you are responsible for setting the values before rendering.
+ // In theory we should aim to backup/restore those values but I am not sure this is possible.
+ // We perform a call to vkCmdSetScissor() to set back a full viewport which is likely to fix things for 99% users but technically this is not perfect. (See github #4644)
+ VkRect2D scissor = { { 0, 0 }, { (uint32_t)fb_width, (uint32_t)fb_height } };
+ vkCmdSetScissor(command_buffer, 0, 1, &scissor);
}
bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer)
{
- ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
ImGuiIO& io = ImGui::GetIO();
+ ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
+ ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
unsigned char* pixels;
int width, height;
@@ -544,17 +599,17 @@ bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer)
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);
+ err = vkCreateImage(v->Device, &info, v->Allocator, &bd->FontImage);
check_vk_result(err);
VkMemoryRequirements req;
- vkGetImageMemoryRequirements(v->Device, g_FontImage, &req);
+ vkGetImageMemoryRequirements(v->Device, bd->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);
+ err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &bd->FontMemory);
check_vk_result(err);
- err = vkBindImageMemory(v->Device, g_FontImage, g_FontMemory, 0);
+ err = vkBindImageMemory(v->Device, bd->FontImage, bd->FontMemory, 0);
check_vk_result(err);
}
@@ -562,30 +617,18 @@ bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer)
{
VkImageViewCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
- info.image = g_FontImage;
+ info.image = bd->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);
+ err = vkCreateImageView(v->Device, &info, v->Allocator, &bd->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 Descriptor Set:
+ bd->FontDescriptorSet = (VkDescriptorSet)ImGui_ImplVulkan_AddTexture(bd->FontSampler, bd->FontView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
// Create the Upload Buffer:
{
@@ -594,34 +637,34 @@ bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer)
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);
+ err = vkCreateBuffer(v->Device, &buffer_info, v->Allocator, &bd->UploadBuffer);
check_vk_result(err);
VkMemoryRequirements req;
- vkGetBufferMemoryRequirements(v->Device, g_UploadBuffer, &req);
- g_BufferMemoryAlignment = (g_BufferMemoryAlignment > req.alignment) ? g_BufferMemoryAlignment : req.alignment;
+ vkGetBufferMemoryRequirements(v->Device, bd->UploadBuffer, &req);
+ bd->BufferMemoryAlignment = (bd->BufferMemoryAlignment > req.alignment) ? bd->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);
+ err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &bd->UploadBufferMemory);
check_vk_result(err);
- err = vkBindBufferMemory(v->Device, g_UploadBuffer, g_UploadBufferMemory, 0);
+ err = vkBindBufferMemory(v->Device, bd->UploadBuffer, bd->UploadBufferMemory, 0);
check_vk_result(err);
}
// Upload to Buffer:
{
char* map = NULL;
- err = vkMapMemory(v->Device, g_UploadBufferMemory, 0, upload_size, 0, (void**)(&map));
+ err = vkMapMemory(v->Device, bd->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].memory = bd->UploadBufferMemory;
range[0].size = upload_size;
err = vkFlushMappedMemoryRanges(v->Device, 1, range);
check_vk_result(err);
- vkUnmapMemory(v->Device, g_UploadBufferMemory);
+ vkUnmapMemory(v->Device, bd->UploadBufferMemory);
}
// Copy to Image:
@@ -633,7 +676,7 @@ bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer)
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].image = bd->FontImage;
copy_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
copy_barrier[0].subresourceRange.levelCount = 1;
copy_barrier[0].subresourceRange.layerCount = 1;
@@ -645,7 +688,7 @@ bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer)
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);
+ vkCmdCopyBufferToImage(command_buffer, bd->UploadBuffer, bd->FontImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
VkImageMemoryBarrier use_barrier[1] = {};
use_barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
@@ -655,7 +698,7 @@ bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer)
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].image = bd->FontImage;
use_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
use_barrier[0].subresourceRange.levelCount = 1;
use_barrier[0].subresourceRange.layerCount = 1;
@@ -663,7 +706,7 @@ bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer)
}
// Store our identifier
- io.Fonts->SetTexID((ImTextureID)(intptr_t)g_FontImage);
+ io.Fonts->SetTexID((ImTextureID)bd->FontDescriptorSet);
return true;
}
@@ -671,29 +714,31 @@ bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer)
static void ImGui_ImplVulkan_CreateShaderModules(VkDevice device, const VkAllocationCallbacks* allocator)
{
// Create the shader modules
- if (g_ShaderModuleVert == NULL)
+ ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
+ if (bd->ShaderModuleVert == VK_NULL_HANDLE)
{
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);
+ VkResult err = vkCreateShaderModule(device, &vert_info, allocator, &bd->ShaderModuleVert);
check_vk_result(err);
}
- if (g_ShaderModuleFrag == NULL)
+ if (bd->ShaderModuleFrag == VK_NULL_HANDLE)
{
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);
+ VkResult err = vkCreateShaderModule(device, &frag_info, allocator, &bd->ShaderModuleFrag);
check_vk_result(err);
}
}
static void ImGui_ImplVulkan_CreateFontSampler(VkDevice device, const VkAllocationCallbacks* allocator)
{
- if (g_FontSampler)
+ ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
+ if (bd->FontSampler)
return;
VkSamplerCreateInfo info = {};
@@ -707,17 +752,18 @@ static void ImGui_ImplVulkan_CreateFontSampler(VkDevice device, const VkAllocati
info.minLod = -1000;
info.maxLod = 1000;
info.maxAnisotropy = 1.0f;
- VkResult err = vkCreateSampler(device, &info, allocator, &g_FontSampler);
+ VkResult err = vkCreateSampler(device, &info, allocator, &bd->FontSampler);
check_vk_result(err);
}
static void ImGui_ImplVulkan_CreateDescriptorSetLayout(VkDevice device, const VkAllocationCallbacks* allocator)
{
- if (g_DescriptorSetLayout)
+ ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
+ if (bd->DescriptorSetLayout)
return;
ImGui_ImplVulkan_CreateFontSampler(device, allocator);
- VkSampler sampler[1] = { g_FontSampler };
+ VkSampler sampler[1] = { bd->FontSampler };
VkDescriptorSetLayoutBinding binding[1] = {};
binding[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
binding[0].descriptorCount = 1;
@@ -727,13 +773,14 @@ static void ImGui_ImplVulkan_CreateDescriptorSetLayout(VkDevice device, const Vk
info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
info.bindingCount = 1;
info.pBindings = binding;
- VkResult err = vkCreateDescriptorSetLayout(device, &info, allocator, &g_DescriptorSetLayout);
+ VkResult err = vkCreateDescriptorSetLayout(device, &info, allocator, &bd->DescriptorSetLayout);
check_vk_result(err);
}
static void ImGui_ImplVulkan_CreatePipelineLayout(VkDevice device, const VkAllocationCallbacks* allocator)
{
- if (g_PipelineLayout)
+ ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
+ if (bd->PipelineLayout)
return;
// Constants: we are using 'vec2 offset' and 'vec2 scale' instead of a full 3d projection matrix
@@ -742,29 +789,30 @@ static void ImGui_ImplVulkan_CreatePipelineLayout(VkDevice device, const VkAlloc
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 };
+ VkDescriptorSetLayout set_layout[1] = { bd->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);
+ VkResult err = vkCreatePipelineLayout(device, &layout_info, allocator, &bd->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_Data* bd = ImGui_ImplVulkan_GetBackendData();
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].module = bd->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].module = bd->ShaderModuleFrag;
stage[1].pName = "main";
VkVertexInputBindingDescription binding_desc[1] = {};
@@ -840,7 +888,7 @@ static void ImGui_ImplVulkan_CreatePipeline(VkDevice device, const VkAllocationC
VkGraphicsPipelineCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
- info.flags = g_PipelineCreateFlags;
+ info.flags = bd->PipelineCreateFlags;
info.stageCount = 2;
info.pStages = stage;
info.pVertexInputState = &vertex_info;
@@ -851,7 +899,7 @@ static void ImGui_ImplVulkan_CreatePipeline(VkDevice device, const VkAllocationC
info.pDepthStencilState = &depth_info;
info.pColorBlendState = &blend_info;
info.pDynamicState = &dynamic_state;
- info.layout = g_PipelineLayout;
+ info.layout = bd->PipelineLayout;
info.renderPass = renderPass;
info.subpass = subpass;
VkResult err = vkCreateGraphicsPipelines(device, pipelineCache, 1, &info, allocator, pipeline);
@@ -860,10 +908,11 @@ static void ImGui_ImplVulkan_CreatePipeline(VkDevice device, const VkAllocationC
bool ImGui_ImplVulkan_CreateDeviceObjects()
{
- ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
+ ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
+ ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
VkResult err;
- if (!g_FontSampler)
+ if (!bd->FontSampler)
{
VkSamplerCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
@@ -876,13 +925,13 @@ bool ImGui_ImplVulkan_CreateDeviceObjects()
info.minLod = -1000;
info.maxLod = 1000;
info.maxAnisotropy = 1.0f;
- err = vkCreateSampler(v->Device, &info, v->Allocator, &g_FontSampler);
+ err = vkCreateSampler(v->Device, &info, v->Allocator, &bd->FontSampler);
check_vk_result(err);
}
- if (!g_DescriptorSetLayout)
+ if (!bd->DescriptorSetLayout)
{
- VkSampler sampler[1] = {g_FontSampler};
+ VkSampler sampler[1] = {bd->FontSampler};
VkDescriptorSetLayoutBinding binding[1] = {};
binding[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
binding[0].descriptorCount = 1;
@@ -892,74 +941,65 @@ bool ImGui_ImplVulkan_CreateDeviceObjects()
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);
+ err = vkCreateDescriptorSetLayout(v->Device, &info, v->Allocator, &bd->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)
+ if (!bd->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 };
+ VkDescriptorSetLayout set_layout[1] = { bd->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);
+ err = vkCreatePipelineLayout(v->Device, &layout_info, v->Allocator, &bd->PipelineLayout);
check_vk_result(err);
}
- ImGui_ImplVulkan_CreatePipeline(v->Device, v->Allocator, v->PipelineCache, g_RenderPass, v->MSAASamples, &g_Pipeline, g_Subpass);
+ ImGui_ImplVulkan_CreatePipeline(v->Device, v->Allocator, v->PipelineCache, bd->RenderPass, v->MSAASamples, &bd->Pipeline, bd->Subpass);
return true;
}
void ImGui_ImplVulkan_DestroyFontUploadObjects()
{
- ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
- if (g_UploadBuffer)
+ ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
+ ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
+ if (bd->UploadBuffer)
{
- vkDestroyBuffer(v->Device, g_UploadBuffer, v->Allocator);
- g_UploadBuffer = VK_NULL_HANDLE;
+ vkDestroyBuffer(v->Device, bd->UploadBuffer, v->Allocator);
+ bd->UploadBuffer = VK_NULL_HANDLE;
}
- if (g_UploadBufferMemory)
+ if (bd->UploadBufferMemory)
{
- vkFreeMemory(v->Device, g_UploadBufferMemory, v->Allocator);
- g_UploadBufferMemory = VK_NULL_HANDLE;
+ vkFreeMemory(v->Device, bd->UploadBufferMemory, v->Allocator);
+ bd->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_Data* bd = ImGui_ImplVulkan_GetBackendData();
+ ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
+ ImGui_ImplVulkanH_DestroyWindowRenderBuffers(v->Device, &bd->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; }
+ if (bd->ShaderModuleVert) { vkDestroyShaderModule(v->Device, bd->ShaderModuleVert, v->Allocator); bd->ShaderModuleVert = VK_NULL_HANDLE; }
+ if (bd->ShaderModuleFrag) { vkDestroyShaderModule(v->Device, bd->ShaderModuleFrag, v->Allocator); bd->ShaderModuleFrag = VK_NULL_HANDLE; }
+ if (bd->FontView) { vkDestroyImageView(v->Device, bd->FontView, v->Allocator); bd->FontView = VK_NULL_HANDLE; }
+ if (bd->FontImage) { vkDestroyImage(v->Device, bd->FontImage, v->Allocator); bd->FontImage = VK_NULL_HANDLE; }
+ if (bd->FontMemory) { vkFreeMemory(v->Device, bd->FontMemory, v->Allocator); bd->FontMemory = VK_NULL_HANDLE; }
+ if (bd->FontSampler) { vkDestroySampler(v->Device, bd->FontSampler, v->Allocator); bd->FontSampler = VK_NULL_HANDLE; }
+ if (bd->DescriptorSetLayout) { vkDestroyDescriptorSetLayout(v->Device, bd->DescriptorSetLayout, v->Allocator); bd->DescriptorSetLayout = VK_NULL_HANDLE; }
+ if (bd->PipelineLayout) { vkDestroyPipelineLayout(v->Device, bd->PipelineLayout, v->Allocator); bd->PipelineLayout = VK_NULL_HANDLE; }
+ if (bd->Pipeline) { vkDestroyPipeline(v->Device, bd->Pipeline, v->Allocator); bd->Pipeline = VK_NULL_HANDLE; }
}
bool ImGui_ImplVulkan_LoadFunctions(PFN_vkVoidFunction(*loader_func)(const char* function_name, void* user_data), void* user_data)
@@ -987,8 +1027,12 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass rend
{
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();
+ IM_ASSERT(io.BackendRendererUserData == NULL && "Already initialized a renderer backend!");
+
+ // Setup backend capabilities flags
+ ImGui_ImplVulkan_Data* bd = IM_NEW(ImGui_ImplVulkan_Data)();
+ io.BackendRendererUserData = (void*)bd;
io.BackendRendererName = "imgui_impl_vulkan";
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
@@ -1001,9 +1045,9 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass rend
IM_ASSERT(info->ImageCount >= info->MinImageCount);
IM_ASSERT(render_pass != VK_NULL_HANDLE);
- g_VulkanInitInfo = *info;
- g_RenderPass = render_pass;
- g_Subpass = info->Subpass;
+ bd->VulkanInitInfo = *info;
+ bd->RenderPass = render_pass;
+ bd->Subpass = info->Subpass;
ImGui_ImplVulkan_CreateDeviceObjects();
@@ -1012,26 +1056,72 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass rend
void ImGui_ImplVulkan_Shutdown()
{
+ ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
+ IM_ASSERT(bd != NULL && "No renderer backend to shutdown, or already shutdown?");
+ ImGuiIO& io = ImGui::GetIO();
+
ImGui_ImplVulkan_DestroyDeviceObjects();
+ io.BackendRendererName = NULL;
+ io.BackendRendererUserData = NULL;
+ IM_DELETE(bd);
}
void ImGui_ImplVulkan_NewFrame()
{
+ ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
+ IM_ASSERT(bd != NULL && "Did you call ImGui_ImplVulkan_Init()?");
+ IM_UNUSED(bd);
}
void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count)
{
+ ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
IM_ASSERT(min_image_count >= 2);
- if (g_VulkanInitInfo.MinImageCount == min_image_count)
+ if (bd->VulkanInitInfo.MinImageCount == min_image_count)
return;
- ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
+ ImGui_ImplVulkan_InitInfo* v = &bd->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;
+ ImGui_ImplVulkanH_DestroyWindowRenderBuffers(v->Device, &bd->MainWindowRenderBuffers, v->Allocator);
+ bd->VulkanInitInfo.MinImageCount = min_image_count;
}
+// Register a texture
+// FIXME: This is experimental in the sense that we are unsure how to best design/tackle this problem, please post to https://github.com/ocornut/imgui/pull/914 if you have suggestions.
+VkDescriptorSet ImGui_ImplVulkan_AddTexture(VkSampler sampler, VkImageView image_view, VkImageLayout image_layout)
+{
+ ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
+ ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
+
+ // Create Descriptor Set:
+ VkDescriptorSet 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 = &bd->DescriptorSetLayout;
+ VkResult err = vkAllocateDescriptorSets(v->Device, &alloc_info, &descriptor_set);
+ check_vk_result(err);
+ }
+
+ // Update the Descriptor Set:
+ {
+ VkDescriptorImageInfo desc_image[1] = {};
+ desc_image[0].sampler = sampler;
+ desc_image[0].imageView = image_view;
+ desc_image[0].imageLayout = image_layout;
+ VkWriteDescriptorSet write_desc[1] = {};
+ write_desc[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ write_desc[0].dstSet = descriptor_set;
+ 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);
+ }
+ return descriptor_set;
+}
//-------------------------------------------------------------------------
// Internal / Miscellaneous Vulkan Helpers
@@ -1181,7 +1271,7 @@ void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, V
{
VkResult err;
VkSwapchainKHR old_swapchain = wd->Swapchain;
- wd->Swapchain = NULL;
+ wd->Swapchain = VK_NULL_HANDLE;
err = vkDeviceWaitIdle(device);
check_vk_result(err);
@@ -1299,7 +1389,7 @@ void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, V
// 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);
+ //ImGui_ImplVulkan_CreatePipeline(device, allocator, VK_NULL_HANDLE, wd->RenderPass, VK_SAMPLE_COUNT_1_BIT, &wd->Pipeline, bd->Subpass);
}
// Create The Image Views
@@ -1356,7 +1446,7 @@ void ImGui_ImplVulkanH_CreateOrResizeWindow(VkInstance instance, VkPhysicalDevic
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);
+ //vkQueueWaitIdle(bd->Queue);
for (uint32_t i = 0; i < wd->ImageCount; i++)
{
diff --git a/3rdparty/imgui/backend/imgui_impl_vulkan.h b/3rdparty/imgui/backend/imgui_impl_vulkan.h
index 9f9010e..d80bfc4 100644
--- a/3rdparty/imgui/backend/imgui_impl_vulkan.h
+++ b/3rdparty/imgui/backend/imgui_impl_vulkan.h
@@ -3,10 +3,13 @@
// 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
+// [!] Renderer: User texture binding. Use 'VkDescriptorSet' as ImTextureID. Read the FAQ about ImTextureID! See https://github.com/ocornut/imgui/pull/914 for discussions.
-// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Important: on 32-bit systems, user texture binding is only supported if your imconfig file has '#define ImTextureID ImU64'.
+// See imgui_impl_vulkan.cpp file for details.
+
+// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// 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
@@ -55,23 +58,27 @@ struct ImGui_ImplVulkan_InitInfo
uint32_t Subpass;
uint32_t MinImageCount; // >= 2
uint32_t ImageCount; // >= MinImageCount
- VkSampleCountFlagBits MSAASamples; // >= VK_SAMPLE_COUNT_1_BIT
+ VkSampleCountFlagBits MSAASamples; // >= VK_SAMPLE_COUNT_1_BIT (0 -> default to 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)
+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)
+
+// Register a texture (VkDescriptorSet == ImTextureID)
+// FIXME: This is experimental in the sense that we are unsure how to best design/tackle this problem, please post to https://github.com/ocornut/imgui/pull/914 if you have suggestions.
+IMGUI_IMPL_API VkDescriptorSet ImGui_ImplVulkan_AddTexture(VkSampler sampler, VkImageView image_view, VkImageLayout image_layout);
// 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);
+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
diff --git a/3rdparty/imgui/backend/imgui_impl_win32.cpp b/3rdparty/imgui/backend/imgui_impl_win32.cpp
index 39e381f..157b57d 100644
--- a/3rdparty/imgui/backend/imgui_impl_win32.cpp
+++ b/3rdparty/imgui/backend/imgui_impl_win32.cpp
@@ -3,11 +3,12 @@
// Implemented features:
// [X] Platform: Clipboard support (for Win32 this is actually part of core dear imgui)
-// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
-// [X] Platform: Keyboard arrays indexed using VK_* Virtual Key Codes, e.g. ImGui::IsKeyPressed(VK_SPACE).
+// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy VK_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
+// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
-// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// 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
@@ -17,21 +18,35 @@
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
+#include <windowsx.h> // GET_X_LPARAM(), GET_Y_LPARAM()
#include <tchar.h>
#include <dwmapi.h>
// Configuration flags to add in your imconfig.h file:
-//#define IMGUI_IMPL_WIN32_DISABLE_GAMEPAD // Disable gamepad support (this used to be meaningful before <1.81) but we know load XInput dynamically so the option is less relevant now.
+//#define IMGUI_IMPL_WIN32_DISABLE_GAMEPAD // Disable gamepad support. This was meaningful before <1.81 but we now load XInput dynamically so the option is now less relevant.
// Using XInput for gamepad (will load DLL dynamically)
#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
-#include <XInput.h>
+#include <xinput.h>
typedef DWORD (WINAPI *PFN_XInputGetCapabilities)(DWORD, DWORD, XINPUT_CAPABILITIES*);
typedef DWORD (WINAPI *PFN_XInputGetState)(DWORD, XINPUT_STATE*);
#endif
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
+// 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago)with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion.
+// 2021-01-20: Inputs: calling new io.AddKeyAnalogEvent() for gamepad support, instead of writing directly to io.NavInputs[].
+// 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+).
+// 2022-01-17: Inputs: always update key mods next and before a key event (not in NewFrame) to fix input queue with very low framerates.
+// 2022-01-12: Inputs: Update mouse inputs using WM_MOUSEMOVE/WM_MOUSELEAVE + fallback to provide it when focused but not hovered/captured. More standard and will allow us to pass it to future input queue API.
+// 2022-01-12: Inputs: Maintain our own copy of MouseButtonsDown mask instead of using ImGui::IsAnyMouseDown() which will be obsoleted.
+// 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range.
+// 2021-12-16: Inputs: Fill VK_LCONTROL/VK_RCONTROL/VK_LSHIFT/VK_RSHIFT/VK_LMENU/VK_RMENU for completeness.
+// 2021-08-17: Calling io.AddFocusEvent() on WM_SETFOCUS/WM_KILLFOCUS messages.
+// 2021-08-02: Inputs: Fixed keyboard modifiers being reported when host window doesn't have focus.
+// 2021-07-29: Inputs: MousePos is correctly reported when the host platform window is hovered but not focused (using TrackMouseEvent() to receive WM_MOUSELEAVE events).
+// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
+// 2021-06-08: Fixed ImGui_ImplWin32_EnableDpiAwareness() and ImGui_ImplWin32_GetDpiScaleForMonitor() to handle Windows 8.1/10 features without a manifest (per-monitor DPI, and properly calls SetProcessDpiAwareness() on 8.1).
// 2021-03-23: Inputs: Clearing keyboard down array when losing focus (WM_KILLFOCUS).
// 2021-02-18: Added ImGui_ImplWin32_EnableAlphaCompositing(). Non Visual Studio users will need to link with dwmapi.lib (MinGW/gcc: use -ldwmapi).
// 2021-02-17: Fixed ImGui_ImplWin32_EnableDpiAwareness() attempting to get SetProcessDpiAwareness from shcore.dll on Windows 8 whereas it is only supported on Windows 8.1.
@@ -61,243 +76,407 @@ typedef DWORD (WINAPI *PFN_XInputGetState)(DWORD, XINPUT_STATE*);
// 2017-10-23: Inputs: Using Win32 ::SetCapture/::GetCapture() to retrieve mouse positions outside the client area when dragging.
// 2016-11-12: Inputs: Only call Win32 ::SetCursor(NULL) when io.MouseDrawCursor is set.
-// Win32 Data
-static HWND g_hWnd = NULL;
-static INT64 g_Time = 0;
-static INT64 g_TicksPerSecond = 0;
-static ImGuiMouseCursor g_LastMouseCursor = ImGuiMouseCursor_COUNT;
-static bool g_HasGamepad = false;
-static bool g_WantUpdateHasGamepad = true;
+struct ImGui_ImplWin32_Data
+{
+ HWND hWnd;
+ HWND MouseHwnd;
+ bool MouseTracked;
+ int MouseButtonsDown;
+ INT64 Time;
+ INT64 TicksPerSecond;
+ ImGuiMouseCursor LastMouseCursor;
+ bool HasGamepad;
+ bool WantUpdateHasGamepad;
-// XInput DLL and functions
#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
-static HMODULE g_XInputDLL = NULL;
-static PFN_XInputGetCapabilities g_XInputGetCapabilities = NULL;
-static PFN_XInputGetState g_XInputGetState = NULL;
+ HMODULE XInputDLL;
+ PFN_XInputGetCapabilities XInputGetCapabilities;
+ PFN_XInputGetState XInputGetState;
#endif
+ ImGui_ImplWin32_Data() { memset(this, 0, sizeof(*this)); }
+};
+
+// Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts
+// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
+// FIXME: multi-context support is not well tested and probably dysfunctional in this backend.
+// FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context.
+static ImGui_ImplWin32_Data* ImGui_ImplWin32_GetBackendData()
+{
+ return ImGui::GetCurrentContext() ? (ImGui_ImplWin32_Data*)ImGui::GetIO().BackendPlatformUserData : NULL;
+}
+
// Functions
bool ImGui_ImplWin32_Init(void* hwnd)
{
- if (!::QueryPerformanceFrequency((LARGE_INTEGER*)&g_TicksPerSecond))
- return false;
- if (!::QueryPerformanceCounter((LARGE_INTEGER*)&g_Time))
- return false;
+ ImGuiIO& io = ImGui::GetIO();
+ IM_ASSERT(io.BackendPlatformUserData == NULL && "Already initialized a platform backend!");
- // Setup backend capabilities flags
- g_hWnd = (HWND)hwnd;
- 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_win32";
- io.ImeWindowHandle = hwnd;
+ INT64 perf_frequency, perf_counter;
+ if (!::QueryPerformanceFrequency((LARGE_INTEGER*)&perf_frequency))
+ return false;
+ if (!::QueryPerformanceCounter((LARGE_INTEGER*)&perf_counter))
+ return false;
- // Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array that we will update during the application lifetime.
- io.KeyMap[ImGuiKey_Tab] = VK_TAB;
- io.KeyMap[ImGuiKey_LeftArrow] = VK_LEFT;
- io.KeyMap[ImGuiKey_RightArrow] = VK_RIGHT;
- io.KeyMap[ImGuiKey_UpArrow] = VK_UP;
- io.KeyMap[ImGuiKey_DownArrow] = VK_DOWN;
- io.KeyMap[ImGuiKey_PageUp] = VK_PRIOR;
- io.KeyMap[ImGuiKey_PageDown] = VK_NEXT;
- io.KeyMap[ImGuiKey_Home] = VK_HOME;
- io.KeyMap[ImGuiKey_End] = VK_END;
- io.KeyMap[ImGuiKey_Insert] = VK_INSERT;
- io.KeyMap[ImGuiKey_Delete] = VK_DELETE;
- io.KeyMap[ImGuiKey_Backspace] = VK_BACK;
- io.KeyMap[ImGuiKey_Space] = VK_SPACE;
- io.KeyMap[ImGuiKey_Enter] = VK_RETURN;
- io.KeyMap[ImGuiKey_Escape] = VK_ESCAPE;
- io.KeyMap[ImGuiKey_KeyPadEnter] = VK_RETURN;
- io.KeyMap[ImGuiKey_A] = 'A';
- io.KeyMap[ImGuiKey_C] = 'C';
- io.KeyMap[ImGuiKey_V] = 'V';
- io.KeyMap[ImGuiKey_X] = 'X';
- io.KeyMap[ImGuiKey_Y] = 'Y';
- io.KeyMap[ImGuiKey_Z] = 'Z';
+ // Setup backend capabilities flags
+ ImGui_ImplWin32_Data* bd = IM_NEW(ImGui_ImplWin32_Data)();
+ io.BackendPlatformUserData = (void*)bd;
+ io.BackendPlatformName = "imgui_impl_win32";
+ io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
+ io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
- // Dynamically load XInput library
+ bd->hWnd = (HWND)hwnd;
+ bd->WantUpdateHasGamepad = true;
+ bd->TicksPerSecond = perf_frequency;
+ bd->Time = perf_counter;
+ bd->LastMouseCursor = ImGuiMouseCursor_COUNT;
+
+ // Set platform dependent data in viewport
+ ImGui::GetMainViewport()->PlatformHandleRaw = (void*)hwnd;
+
+ // Dynamically load XInput library
#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
- const char* xinput_dll_names[] =
- {
- "xinput1_4.dll", // Windows 8+
- "xinput1_3.dll", // DirectX SDK
- "xinput9_1_0.dll", // Windows Vista, Windows 7
- "xinput1_2.dll", // DirectX SDK
- "xinput1_1.dll" // DirectX SDK
- };
- for (int n = 0; n < IM_ARRAYSIZE(xinput_dll_names); n++)
- if (HMODULE dll = ::LoadLibraryA(xinput_dll_names[n]))
- {
- g_XInputDLL = dll;
- g_XInputGetCapabilities = (PFN_XInputGetCapabilities)::GetProcAddress(dll, "XInputGetCapabilities");
- g_XInputGetState = (PFN_XInputGetState)::GetProcAddress(dll, "XInputGetState");
- break;
- }
+ const char* xinput_dll_names[] =
+ {
+ "xinput1_4.dll", // Windows 8+
+ "xinput1_3.dll", // DirectX SDK
+ "xinput9_1_0.dll", // Windows Vista, Windows 7
+ "xinput1_2.dll", // DirectX SDK
+ "xinput1_1.dll" // DirectX SDK
+ };
+ for (int n = 0; n < IM_ARRAYSIZE(xinput_dll_names); n++)
+ if (HMODULE dll = ::LoadLibraryA(xinput_dll_names[n]))
+ {
+ bd->XInputDLL = dll;
+ bd->XInputGetCapabilities = (PFN_XInputGetCapabilities)::GetProcAddress(dll, "XInputGetCapabilities");
+ bd->XInputGetState = (PFN_XInputGetState)::GetProcAddress(dll, "XInputGetState");
+ break;
+ }
#endif // IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
- return true;
+ return true;
}
void ImGui_ImplWin32_Shutdown()
{
- // Unload XInput library
+ ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
+ IM_ASSERT(bd != NULL && "No platform backend to shutdown, or already shutdown?");
+ ImGuiIO& io = ImGui::GetIO();
+
+ // Unload XInput library
#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
- if (g_XInputDLL)
- ::FreeLibrary(g_XInputDLL);
- g_XInputDLL = NULL;
- g_XInputGetCapabilities = NULL;
- g_XInputGetState = NULL;
+ if (bd->XInputDLL)
+ ::FreeLibrary(bd->XInputDLL);
#endif // IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
- g_hWnd = NULL;
- g_Time = 0;
- g_TicksPerSecond = 0;
- g_LastMouseCursor = ImGuiMouseCursor_COUNT;
- g_HasGamepad = false;
- g_WantUpdateHasGamepad = true;
+ io.BackendPlatformName = NULL;
+ io.BackendPlatformUserData = NULL;
+ IM_DELETE(bd);
}
static bool ImGui_ImplWin32_UpdateMouseCursor()
{
- ImGuiIO& io = ImGui::GetIO();
- if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
- return false;
+ ImGuiIO& io = ImGui::GetIO();
+ if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
+ return false;
- 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
- ::SetCursor(NULL);
- }
- else
- {
- // Show OS mouse cursor
- LPTSTR win32_cursor = IDC_ARROW;
- switch (imgui_cursor)
- {
- case ImGuiMouseCursor_Arrow: win32_cursor = IDC_ARROW; break;
- case ImGuiMouseCursor_TextInput: win32_cursor = IDC_IBEAM; break;
- case ImGuiMouseCursor_ResizeAll: win32_cursor = IDC_SIZEALL; break;
- case ImGuiMouseCursor_ResizeEW: win32_cursor = IDC_SIZEWE; break;
- case ImGuiMouseCursor_ResizeNS: win32_cursor = IDC_SIZENS; break;
- case ImGuiMouseCursor_ResizeNESW: win32_cursor = IDC_SIZENESW; break;
- case ImGuiMouseCursor_ResizeNWSE: win32_cursor = IDC_SIZENWSE; break;
- case ImGuiMouseCursor_Hand: win32_cursor = IDC_HAND; break;
- case ImGuiMouseCursor_NotAllowed: win32_cursor = IDC_NO; break;
- }
- ::SetCursor(::LoadCursor(NULL, win32_cursor));
- }
- return true;
+ 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
+ ::SetCursor(NULL);
+ }
+ else
+ {
+ // Show OS mouse cursor
+ LPTSTR win32_cursor = IDC_ARROW;
+ switch (imgui_cursor)
+ {
+ case ImGuiMouseCursor_Arrow: win32_cursor = IDC_ARROW; break;
+ case ImGuiMouseCursor_TextInput: win32_cursor = IDC_IBEAM; break;
+ case ImGuiMouseCursor_ResizeAll: win32_cursor = IDC_SIZEALL; break;
+ case ImGuiMouseCursor_ResizeEW: win32_cursor = IDC_SIZEWE; break;
+ case ImGuiMouseCursor_ResizeNS: win32_cursor = IDC_SIZENS; break;
+ case ImGuiMouseCursor_ResizeNESW: win32_cursor = IDC_SIZENESW; break;
+ case ImGuiMouseCursor_ResizeNWSE: win32_cursor = IDC_SIZENWSE; break;
+ case ImGuiMouseCursor_Hand: win32_cursor = IDC_HAND; break;
+ case ImGuiMouseCursor_NotAllowed: win32_cursor = IDC_NO; break;
+ }
+ ::SetCursor(::LoadCursor(NULL, win32_cursor));
+ }
+ return true;
+}
+
+static bool IsVkDown(int vk)
+{
+ return (::GetKeyState(vk) & 0x8000) != 0;
+}
+
+static void ImGui_ImplWin32_AddKeyEvent(ImGuiKey key, bool down, int native_keycode, int native_scancode = -1)
+{
+ ImGuiIO& io = ImGui::GetIO();
+ io.AddKeyEvent(key, down);
+ io.SetKeyEventNativeData(key, native_keycode, native_scancode); // To support legacy indexing (<1.87 user code)
+ IM_UNUSED(native_scancode);
+}
+
+static void ImGui_ImplWin32_ProcessKeyEventsWorkarounds()
+{
+ // Left & right Shift keys: when both are pressed together, Windows tend to not generate the WM_KEYUP event for the first released one.
+ if (ImGui::IsKeyDown(ImGuiKey_LeftShift) && !IsVkDown(VK_LSHIFT))
+ ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftShift, false, VK_LSHIFT);
+ if (ImGui::IsKeyDown(ImGuiKey_RightShift) && !IsVkDown(VK_RSHIFT))
+ ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightShift, false, VK_RSHIFT);
+
+ // Sometimes WM_KEYUP for Win key is not passed down to the app (e.g. for Win+V on some setups, according to GLFW).
+ if (ImGui::IsKeyDown(ImGuiKey_LeftSuper) && !IsVkDown(VK_LWIN))
+ ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftSuper, false, VK_LWIN);
+ if (ImGui::IsKeyDown(ImGuiKey_RightSuper) && !IsVkDown(VK_RWIN))
+ ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightSuper, false, VK_RWIN);
}
-static void ImGui_ImplWin32_UpdateMousePos()
+static void ImGui_ImplWin32_UpdateKeyModifiers()
{
- ImGuiIO& io = ImGui::GetIO();
- IM_ASSERT(g_hWnd != 0);
+ ImGuiIO& io = ImGui::GetIO();
+ io.AddKeyEvent(ImGuiKey_ModCtrl, IsVkDown(VK_CONTROL));
+ io.AddKeyEvent(ImGuiKey_ModShift, IsVkDown(VK_SHIFT));
+ io.AddKeyEvent(ImGuiKey_ModAlt, IsVkDown(VK_MENU));
+ io.AddKeyEvent(ImGuiKey_ModSuper, IsVkDown(VK_APPS));
+}
+
+static void ImGui_ImplWin32_UpdateMouseData()
+{
+ ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
+ ImGuiIO& io = ImGui::GetIO();
+ IM_ASSERT(bd->hWnd != 0);
- // Set OS mouse position if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
- if (io.WantSetMousePos)
- {
- POINT pos = { (int)io.MousePos.x, (int)io.MousePos.y };
- if (::ClientToScreen(g_hWnd, &pos))
- ::SetCursorPos(pos.x, pos.y);
- }
+ const bool is_app_focused = (::GetForegroundWindow() == bd->hWnd);
+ if (is_app_focused)
+ {
+ // (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
+ if (io.WantSetMousePos)
+ {
+ POINT pos = { (int)io.MousePos.x, (int)io.MousePos.y };
+ if (::ClientToScreen(bd->hWnd, &pos))
+ ::SetCursorPos(pos.x, pos.y);
+ }
- // Set mouse position
- io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
- POINT pos;
- if (HWND active_window = ::GetForegroundWindow())
- if (active_window == g_hWnd || ::IsChild(active_window, g_hWnd))
- if (::GetCursorPos(&pos) && ::ScreenToClient(g_hWnd, &pos))
- io.MousePos = ImVec2((float)pos.x, (float)pos.y);
+ // (Optional) Fallback to provide mouse position when focused (WM_MOUSEMOVE already provides this when hovered or captured)
+ if (!io.WantSetMousePos && !bd->MouseTracked)
+ {
+ POINT pos;
+ if (::GetCursorPos(&pos) && ::ScreenToClient(bd->hWnd, &pos))
+ io.AddMousePosEvent((float)pos.x, (float)pos.y);
+ }
+ }
}
// Gamepad navigation mapping
static void ImGui_ImplWin32_UpdateGamepads()
{
#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
- ImGuiIO& io = ImGui::GetIO();
- memset(io.NavInputs, 0, sizeof(io.NavInputs));
- if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
- return;
+ ImGuiIO& io = ImGui::GetIO();
+ ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
+ if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
+ return;
- // Calling XInputGetState() every frame on disconnected gamepads is unfortunately too slow.
- // Instead we refresh gamepad availability by calling XInputGetCapabilities() _only_ after receiving WM_DEVICECHANGE.
- if (g_WantUpdateHasGamepad)
- {
- XINPUT_CAPABILITIES caps;
- g_HasGamepad = g_XInputGetCapabilities ? (g_XInputGetCapabilities(0, XINPUT_FLAG_GAMEPAD, &caps) == ERROR_SUCCESS) : false;
- g_WantUpdateHasGamepad = false;
- }
+ // Calling XInputGetState() every frame on disconnected gamepads is unfortunately too slow.
+ // Instead we refresh gamepad availability by calling XInputGetCapabilities() _only_ after receiving WM_DEVICECHANGE.
+ if (bd->WantUpdateHasGamepad)
+ {
+ XINPUT_CAPABILITIES caps = {};
+ bd->HasGamepad = bd->XInputGetCapabilities ? (bd->XInputGetCapabilities(0, XINPUT_FLAG_GAMEPAD, &caps) == ERROR_SUCCESS) : false;
+ bd->WantUpdateHasGamepad = false;
+ }
- io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
- XINPUT_STATE xinput_state;
- if (g_HasGamepad && g_XInputGetState && g_XInputGetState(0, &xinput_state) == ERROR_SUCCESS)
- {
- const XINPUT_GAMEPAD& gamepad = xinput_state.Gamepad;
- io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
+ io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
+ XINPUT_STATE xinput_state;
+ XINPUT_GAMEPAD& gamepad = xinput_state.Gamepad;
+ if (!bd->HasGamepad || bd->XInputGetState == NULL || bd->XInputGetState(0, &xinput_state) != ERROR_SUCCESS)
+ return;
+ io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
-#define MAP_BUTTON(NAV_NO, BUTTON_ENUM) { io.NavInputs[NAV_NO] = (gamepad.wButtons & BUTTON_ENUM) ? 1.0f : 0.0f; }
-#define MAP_ANALOG(NAV_NO, VALUE, V0, V1) { float vn = (float)(VALUE - V0) / (float)(V1 - V0); if (vn > 1.0f) vn = 1.0f; if (vn > 0.0f && io.NavInputs[NAV_NO] < vn) io.NavInputs[NAV_NO] = vn; }
- MAP_BUTTON(ImGuiNavInput_Activate, XINPUT_GAMEPAD_A); // Cross / A
- MAP_BUTTON(ImGuiNavInput_Cancel, XINPUT_GAMEPAD_B); // Circle / B
- MAP_BUTTON(ImGuiNavInput_Menu, XINPUT_GAMEPAD_X); // Square / X
- MAP_BUTTON(ImGuiNavInput_Input, XINPUT_GAMEPAD_Y); // Triangle / Y
- MAP_BUTTON(ImGuiNavInput_DpadLeft, XINPUT_GAMEPAD_DPAD_LEFT); // D-Pad Left
- MAP_BUTTON(ImGuiNavInput_DpadRight, XINPUT_GAMEPAD_DPAD_RIGHT); // D-Pad Right
- MAP_BUTTON(ImGuiNavInput_DpadUp, XINPUT_GAMEPAD_DPAD_UP); // D-Pad Up
- MAP_BUTTON(ImGuiNavInput_DpadDown, XINPUT_GAMEPAD_DPAD_DOWN); // D-Pad Down
- MAP_BUTTON(ImGuiNavInput_FocusPrev, XINPUT_GAMEPAD_LEFT_SHOULDER); // L1 / LB
- MAP_BUTTON(ImGuiNavInput_FocusNext, XINPUT_GAMEPAD_RIGHT_SHOULDER); // R1 / RB
- MAP_BUTTON(ImGuiNavInput_TweakSlow, XINPUT_GAMEPAD_LEFT_SHOULDER); // L1 / LB
- MAP_BUTTON(ImGuiNavInput_TweakFast, XINPUT_GAMEPAD_RIGHT_SHOULDER); // R1 / RB
- MAP_ANALOG(ImGuiNavInput_LStickLeft, gamepad.sThumbLX, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768);
- MAP_ANALOG(ImGuiNavInput_LStickRight, gamepad.sThumbLX, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
- MAP_ANALOG(ImGuiNavInput_LStickUp, gamepad.sThumbLY, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
- MAP_ANALOG(ImGuiNavInput_LStickDown, gamepad.sThumbLY, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32767);
-#undef MAP_BUTTON
-#undef MAP_ANALOG
- }
+ #define IM_SATURATE(V) (V < 0.0f ? 0.0f : V > 1.0f ? 1.0f : V)
+ #define MAP_BUTTON(KEY_NO, BUTTON_ENUM) { io.AddKeyEvent(KEY_NO, (gamepad.wButtons & BUTTON_ENUM) != 0); }
+ #define MAP_ANALOG(KEY_NO, VALUE, V0, V1) { float vn = (float)(VALUE - V0) / (float)(V1 - V0); io.AddKeyAnalogEvent(KEY_NO, vn > 0.10f, IM_SATURATE(vn)); }
+ MAP_BUTTON(ImGuiKey_GamepadStart, XINPUT_GAMEPAD_START);
+ MAP_BUTTON(ImGuiKey_GamepadBack, XINPUT_GAMEPAD_BACK);
+ MAP_BUTTON(ImGuiKey_GamepadFaceDown, XINPUT_GAMEPAD_A);
+ MAP_BUTTON(ImGuiKey_GamepadFaceRight, XINPUT_GAMEPAD_B);
+ MAP_BUTTON(ImGuiKey_GamepadFaceLeft, XINPUT_GAMEPAD_X);
+ MAP_BUTTON(ImGuiKey_GamepadFaceUp, XINPUT_GAMEPAD_Y);
+ MAP_BUTTON(ImGuiKey_GamepadDpadLeft, XINPUT_GAMEPAD_DPAD_LEFT);
+ MAP_BUTTON(ImGuiKey_GamepadDpadRight, XINPUT_GAMEPAD_DPAD_RIGHT);
+ MAP_BUTTON(ImGuiKey_GamepadDpadUp, XINPUT_GAMEPAD_DPAD_UP);
+ MAP_BUTTON(ImGuiKey_GamepadDpadDown, XINPUT_GAMEPAD_DPAD_DOWN);
+ MAP_BUTTON(ImGuiKey_GamepadL1, XINPUT_GAMEPAD_LEFT_SHOULDER);
+ MAP_BUTTON(ImGuiKey_GamepadR1, XINPUT_GAMEPAD_RIGHT_SHOULDER);
+ MAP_ANALOG(ImGuiKey_GamepadL2, gamepad.bLeftTrigger, XINPUT_GAMEPAD_TRIGGER_THRESHOLD, 255);
+ MAP_ANALOG(ImGuiKey_GamepadR2, gamepad.bRightTrigger, XINPUT_GAMEPAD_TRIGGER_THRESHOLD, 255);
+ MAP_BUTTON(ImGuiKey_GamepadL3, XINPUT_GAMEPAD_LEFT_THUMB);
+ MAP_BUTTON(ImGuiKey_GamepadR3, XINPUT_GAMEPAD_RIGHT_THUMB);
+ MAP_ANALOG(ImGuiKey_GamepadLStickLeft, gamepad.sThumbLX, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768);
+ MAP_ANALOG(ImGuiKey_GamepadLStickRight, gamepad.sThumbLX, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
+ MAP_ANALOG(ImGuiKey_GamepadLStickUp, gamepad.sThumbLY, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
+ MAP_ANALOG(ImGuiKey_GamepadLStickDown, gamepad.sThumbLY, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768);
+ MAP_ANALOG(ImGuiKey_GamepadRStickLeft, gamepad.sThumbRX, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768);
+ MAP_ANALOG(ImGuiKey_GamepadRStickRight, gamepad.sThumbRX, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
+ MAP_ANALOG(ImGuiKey_GamepadRStickUp, gamepad.sThumbRY, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
+ MAP_ANALOG(ImGuiKey_GamepadRStickDown, gamepad.sThumbRY, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768);
+ #undef MAP_BUTTON
+ #undef MAP_ANALOG
#endif // #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
}
void ImGui_ImplWin32_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().");
+ ImGuiIO& io = ImGui::GetIO();
+ ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
+ IM_ASSERT(bd != NULL && "Did you call ImGui_ImplWin32_Init()?");
- // Setup display size (every frame to accommodate for window resizing)
- RECT rect = { 0, 0, 0, 0 };
- ::GetClientRect(g_hWnd, &rect);
- io.DisplaySize = ImVec2((float)(rect.right - rect.left), (float)(rect.bottom - rect.top));
+ // Setup display size (every frame to accommodate for window resizing)
+ RECT rect = { 0, 0, 0, 0 };
+ ::GetClientRect(bd->hWnd, &rect);
+ io.DisplaySize = ImVec2((float)(rect.right - rect.left), (float)(rect.bottom - rect.top));
- // Setup time step
- INT64 current_time = 0;
- ::QueryPerformanceCounter((LARGE_INTEGER*)&current_time);
- io.DeltaTime = (float)(current_time - g_Time) / g_TicksPerSecond;
- g_Time = current_time;
+ // Setup time step
+ INT64 current_time = 0;
+ ::QueryPerformanceCounter((LARGE_INTEGER*)&current_time);
+ io.DeltaTime = (float)(current_time - bd->Time) / bd->TicksPerSecond;
+ bd->Time = current_time;
- // Read keyboard modifiers inputs
- io.KeyCtrl = (::GetKeyState(VK_CONTROL) & 0x8000) != 0;
- io.KeyShift = (::GetKeyState(VK_SHIFT) & 0x8000) != 0;
- io.KeyAlt = (::GetKeyState(VK_MENU) & 0x8000) != 0;
- io.KeySuper = false;
- // io.KeysDown[], io.MousePos, io.MouseDown[], io.MouseWheel: filled by the WndProc handler below.
+ // Update OS mouse position
+ ImGui_ImplWin32_UpdateMouseData();
- // Update OS mouse position
- ImGui_ImplWin32_UpdateMousePos();
+ // Process workarounds for known Windows key handling issues
+ ImGui_ImplWin32_ProcessKeyEventsWorkarounds();
- // Update OS mouse cursor with the cursor requested by imgui
- ImGuiMouseCursor mouse_cursor = io.MouseDrawCursor ? ImGuiMouseCursor_None : ImGui::GetMouseCursor();
- if (g_LastMouseCursor != mouse_cursor)
- {
- g_LastMouseCursor = mouse_cursor;
- ImGui_ImplWin32_UpdateMouseCursor();
- }
+ // Update OS mouse cursor with the cursor requested by imgui
+ ImGuiMouseCursor mouse_cursor = io.MouseDrawCursor ? ImGuiMouseCursor_None : ImGui::GetMouseCursor();
+ if (bd->LastMouseCursor != mouse_cursor)
+ {
+ bd->LastMouseCursor = mouse_cursor;
+ ImGui_ImplWin32_UpdateMouseCursor();
+ }
- // Update game controllers (if enabled and available)
- ImGui_ImplWin32_UpdateGamepads();
+ // Update game controllers (if enabled and available)
+ ImGui_ImplWin32_UpdateGamepads();
+}
+
+// There is no distinct VK_xxx for keypad enter, instead it is VK_RETURN + KF_EXTENDED, we assign it an arbitrary value to make code more readable (VK_ codes go up to 255)
+#define IM_VK_KEYPAD_ENTER (VK_RETURN + 256)
+
+// Map VK_xxx to ImGuiKey_xxx.
+static ImGuiKey ImGui_ImplWin32_VirtualKeyToImGuiKey(WPARAM wParam)
+{
+ switch (wParam)
+ {
+ case VK_TAB: return ImGuiKey_Tab;
+ case VK_LEFT: return ImGuiKey_LeftArrow;
+ case VK_RIGHT: return ImGuiKey_RightArrow;
+ case VK_UP: return ImGuiKey_UpArrow;
+ case VK_DOWN: return ImGuiKey_DownArrow;
+ case VK_PRIOR: return ImGuiKey_PageUp;
+ case VK_NEXT: return ImGuiKey_PageDown;
+ case VK_HOME: return ImGuiKey_Home;
+ case VK_END: return ImGuiKey_End;
+ case VK_INSERT: return ImGuiKey_Insert;
+ case VK_DELETE: return ImGuiKey_Delete;
+ case VK_BACK: return ImGuiKey_Backspace;
+ case VK_SPACE: return ImGuiKey_Space;
+ case VK_RETURN: return ImGuiKey_Enter;
+ case VK_ESCAPE: return ImGuiKey_Escape;
+ case VK_OEM_7: return ImGuiKey_Apostrophe;
+ case VK_OEM_COMMA: return ImGuiKey_Comma;
+ case VK_OEM_MINUS: return ImGuiKey_Minus;
+ case VK_OEM_PERIOD: return ImGuiKey_Period;
+ case VK_OEM_2: return ImGuiKey_Slash;
+ case VK_OEM_1: return ImGuiKey_Semicolon;
+ case VK_OEM_PLUS: return ImGuiKey_Equal;
+ case VK_OEM_4: return ImGuiKey_LeftBracket;
+ case VK_OEM_5: return ImGuiKey_Backslash;
+ case VK_OEM_6: return ImGuiKey_RightBracket;
+ case VK_OEM_3: return ImGuiKey_GraveAccent;
+ case VK_CAPITAL: return ImGuiKey_CapsLock;
+ case VK_SCROLL: return ImGuiKey_ScrollLock;
+ case VK_NUMLOCK: return ImGuiKey_NumLock;
+ case VK_SNAPSHOT: return ImGuiKey_PrintScreen;
+ case VK_PAUSE: return ImGuiKey_Pause;
+ case VK_NUMPAD0: return ImGuiKey_Keypad0;
+ case VK_NUMPAD1: return ImGuiKey_Keypad1;
+ case VK_NUMPAD2: return ImGuiKey_Keypad2;
+ case VK_NUMPAD3: return ImGuiKey_Keypad3;
+ case VK_NUMPAD4: return ImGuiKey_Keypad4;
+ case VK_NUMPAD5: return ImGuiKey_Keypad5;
+ case VK_NUMPAD6: return ImGuiKey_Keypad6;
+ case VK_NUMPAD7: return ImGuiKey_Keypad7;
+ case VK_NUMPAD8: return ImGuiKey_Keypad8;
+ case VK_NUMPAD9: return ImGuiKey_Keypad9;
+ case VK_DECIMAL: return ImGuiKey_KeypadDecimal;
+ case VK_DIVIDE: return ImGuiKey_KeypadDivide;
+ case VK_MULTIPLY: return ImGuiKey_KeypadMultiply;
+ case VK_SUBTRACT: return ImGuiKey_KeypadSubtract;
+ case VK_ADD: return ImGuiKey_KeypadAdd;
+ case IM_VK_KEYPAD_ENTER: return ImGuiKey_KeypadEnter;
+ case VK_LSHIFT: return ImGuiKey_LeftShift;
+ case VK_LCONTROL: return ImGuiKey_LeftCtrl;
+ case VK_LMENU: return ImGuiKey_LeftAlt;
+ case VK_LWIN: return ImGuiKey_LeftSuper;
+ case VK_RSHIFT: return ImGuiKey_RightShift;
+ case VK_RCONTROL: return ImGuiKey_RightCtrl;
+ case VK_RMENU: return ImGuiKey_RightAlt;
+ case VK_RWIN: return ImGuiKey_RightSuper;
+ case VK_APPS: return ImGuiKey_Menu;
+ case '0': return ImGuiKey_0;
+ case '1': return ImGuiKey_1;
+ case '2': return ImGuiKey_2;
+ case '3': return ImGuiKey_3;
+ case '4': return ImGuiKey_4;
+ case '5': return ImGuiKey_5;
+ case '6': return ImGuiKey_6;
+ case '7': return ImGuiKey_7;
+ case '8': return ImGuiKey_8;
+ case '9': return ImGuiKey_9;
+ case 'A': return ImGuiKey_A;
+ case 'B': return ImGuiKey_B;
+ case 'C': return ImGuiKey_C;
+ case 'D': return ImGuiKey_D;
+ case 'E': return ImGuiKey_E;
+ case 'F': return ImGuiKey_F;
+ case 'G': return ImGuiKey_G;
+ case 'H': return ImGuiKey_H;
+ case 'I': return ImGuiKey_I;
+ case 'J': return ImGuiKey_J;
+ case 'K': return ImGuiKey_K;
+ case 'L': return ImGuiKey_L;
+ case 'M': return ImGuiKey_M;
+ case 'N': return ImGuiKey_N;
+ case 'O': return ImGuiKey_O;
+ case 'P': return ImGuiKey_P;
+ case 'Q': return ImGuiKey_Q;
+ case 'R': return ImGuiKey_R;
+ case 'S': return ImGuiKey_S;
+ case 'T': return ImGuiKey_T;
+ case 'U': return ImGuiKey_U;
+ case 'V': return ImGuiKey_V;
+ case 'W': return ImGuiKey_W;
+ case 'X': return ImGuiKey_X;
+ case 'Y': return ImGuiKey_Y;
+ case 'Z': return ImGuiKey_Z;
+ case VK_F1: return ImGuiKey_F1;
+ case VK_F2: return ImGuiKey_F2;
+ case VK_F3: return ImGuiKey_F3;
+ case VK_F4: return ImGuiKey_F4;
+ case VK_F5: return ImGuiKey_F5;
+ case VK_F6: return ImGuiKey_F6;
+ case VK_F7: return ImGuiKey_F7;
+ case VK_F8: return ImGuiKey_F8;
+ case VK_F9: return ImGuiKey_F9;
+ case VK_F10: return ImGuiKey_F10;
+ case VK_F11: return ImGuiKey_F11;
+ case VK_F12: return ImGuiKey_F12;
+ default: return ImGuiKey_None;
+ }
}
// Allow compilation with old Windows SDK. MinGW doesn't have default _WIN32_WINNT/WINVER versions.
@@ -322,76 +501,131 @@ extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg
#endif
IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
- if (ImGui::GetCurrentContext() == NULL)
- return 0;
+ if (ImGui::GetCurrentContext() == NULL)
+ return 0;
- ImGuiIO& io = ImGui::GetIO();
- switch (msg)
- {
- case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK:
- case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK:
- case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK:
- case WM_XBUTTONDOWN: case WM_XBUTTONDBLCLK:
- {
- int button = 0;
- if (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONDBLCLK) { button = 0; }
- if (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONDBLCLK) { button = 1; }
- if (msg == WM_MBUTTONDOWN || msg == WM_MBUTTONDBLCLK) { button = 2; }
- if (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONDBLCLK) { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; }
- if (!ImGui::IsAnyMouseDown() && ::GetCapture() == NULL)
- ::SetCapture(hwnd);
- io.MouseDown[button] = true;
- return 0;
- }
- case WM_LBUTTONUP:
- case WM_RBUTTONUP:
- case WM_MBUTTONUP:
- case WM_XBUTTONUP:
- {
- int button = 0;
- if (msg == WM_LBUTTONUP) { button = 0; }
- if (msg == WM_RBUTTONUP) { button = 1; }
- if (msg == WM_MBUTTONUP) { button = 2; }
- if (msg == WM_XBUTTONUP) { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; }
- io.MouseDown[button] = false;
- if (!ImGui::IsAnyMouseDown() && ::GetCapture() == hwnd)
- ::ReleaseCapture();
- return 0;
- }
- case WM_MOUSEWHEEL:
- io.MouseWheel += (float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA;
- return 0;
- case WM_MOUSEHWHEEL:
- io.MouseWheelH += (float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA;
- return 0;
- case WM_KEYDOWN:
- case WM_SYSKEYDOWN:
- if (wParam < 256)
- io.KeysDown[wParam] = 1;
- return 0;
- case WM_KEYUP:
- case WM_SYSKEYUP:
- if (wParam < 256)
- io.KeysDown[wParam] = 0;
- return 0;
- case WM_KILLFOCUS:
- memset(io.KeysDown, 0, sizeof(io.KeysDown));
- return 0;
- case WM_CHAR:
- // You can also use ToAscii()+GetKeyboardState() to retrieve characters.
- if (wParam > 0 && wParam < 0x10000)
- io.AddInputCharacterUTF16((unsigned short)wParam);
- return 0;
- case WM_SETCURSOR:
- if (LOWORD(lParam) == HTCLIENT && ImGui_ImplWin32_UpdateMouseCursor())
- return 1;
- return 0;
- case WM_DEVICECHANGE:
- if ((UINT)wParam == DBT_DEVNODES_CHANGED)
- g_WantUpdateHasGamepad = true;
- return 0;
- }
- return 0;
+ ImGuiIO& io = ImGui::GetIO();
+ ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
+
+ switch (msg)
+ {
+ case WM_MOUSEMOVE:
+ // We need to call TrackMouseEvent in order to receive WM_MOUSELEAVE events
+ bd->MouseHwnd = hwnd;
+ if (!bd->MouseTracked)
+ {
+ TRACKMOUSEEVENT tme = { sizeof(tme), TME_LEAVE, hwnd, 0 };
+ ::TrackMouseEvent(&tme);
+ bd->MouseTracked = true;
+ }
+ io.AddMousePosEvent((float)GET_X_LPARAM(lParam), (float)GET_Y_LPARAM(lParam));
+ break;
+ case WM_MOUSELEAVE:
+ if (bd->MouseHwnd == hwnd)
+ bd->MouseHwnd = NULL;
+ bd->MouseTracked = false;
+ io.AddMousePosEvent(-FLT_MAX, -FLT_MAX);
+ break;
+ case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK:
+ case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK:
+ case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK:
+ case WM_XBUTTONDOWN: case WM_XBUTTONDBLCLK:
+ {
+ int button = 0;
+ if (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONDBLCLK) { button = 0; }
+ if (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONDBLCLK) { button = 1; }
+ if (msg == WM_MBUTTONDOWN || msg == WM_MBUTTONDBLCLK) { button = 2; }
+ if (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONDBLCLK) { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; }
+ if (bd->MouseButtonsDown == 0 && ::GetCapture() == NULL)
+ ::SetCapture(hwnd);
+ bd->MouseButtonsDown |= 1 << button;
+ io.AddMouseButtonEvent(button, true);
+ return 0;
+ }
+ case WM_LBUTTONUP:
+ case WM_RBUTTONUP:
+ case WM_MBUTTONUP:
+ case WM_XBUTTONUP:
+ {
+ int button = 0;
+ if (msg == WM_LBUTTONUP) { button = 0; }
+ if (msg == WM_RBUTTONUP) { button = 1; }
+ if (msg == WM_MBUTTONUP) { button = 2; }
+ if (msg == WM_XBUTTONUP) { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; }
+ bd->MouseButtonsDown &= ~(1 << button);
+ if (bd->MouseButtonsDown == 0 && ::GetCapture() == hwnd)
+ ::ReleaseCapture();
+ io.AddMouseButtonEvent(button, false);
+ return 0;
+ }
+ case WM_MOUSEWHEEL:
+ io.AddMouseWheelEvent(0.0f, (float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA);
+ return 0;
+ case WM_MOUSEHWHEEL:
+ io.AddMouseWheelEvent((float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA, 0.0f);
+ return 0;
+ case WM_KEYDOWN:
+ case WM_KEYUP:
+ case WM_SYSKEYDOWN:
+ case WM_SYSKEYUP:
+ {
+ const bool is_key_down = (msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN);
+ if (wParam < 256)
+ {
+ // Submit modifiers
+ ImGui_ImplWin32_UpdateKeyModifiers();
+
+ // Obtain virtual key code
+ // (keypad enter doesn't have its own... VK_RETURN with KF_EXTENDED flag means keypad enter, see IM_VK_KEYPAD_ENTER definition for details, it is mapped to ImGuiKey_KeyPadEnter.)
+ int vk = (int)wParam;
+ if ((wParam == VK_RETURN) && (HIWORD(lParam) & KF_EXTENDED))
+ vk = IM_VK_KEYPAD_ENTER;
+
+ // Submit key event
+ const ImGuiKey key = ImGui_ImplWin32_VirtualKeyToImGuiKey(vk);
+ const int scancode = (int)LOBYTE(HIWORD(lParam));
+ if (key != ImGuiKey_None)
+ ImGui_ImplWin32_AddKeyEvent(key, is_key_down, vk, scancode);
+
+ // Submit individual left/right modifier events
+ if (vk == VK_SHIFT)
+ {
+ // Important: Shift keys tend to get stuck when pressed together, missing key-up events are corrected in ImGui_ImplWin32_ProcessKeyEventsWorkarounds()
+ if (IsVkDown(VK_LSHIFT) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftShift, is_key_down, VK_LSHIFT, scancode); }
+ if (IsVkDown(VK_RSHIFT) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightShift, is_key_down, VK_RSHIFT, scancode); }
+ }
+ else if (vk == VK_CONTROL)
+ {
+ if (IsVkDown(VK_LCONTROL) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftCtrl, is_key_down, VK_LCONTROL, scancode); }
+ if (IsVkDown(VK_RCONTROL) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightCtrl, is_key_down, VK_RCONTROL, scancode); }
+ }
+ else if (vk == VK_MENU)
+ {
+ if (IsVkDown(VK_LMENU) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftAlt, is_key_down, VK_LMENU, scancode); }
+ if (IsVkDown(VK_RMENU) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightAlt, is_key_down, VK_RMENU, scancode); }
+ }
+ }
+ return 0;
+ }
+ case WM_SETFOCUS:
+ case WM_KILLFOCUS:
+ io.AddFocusEvent(msg == WM_SETFOCUS);
+ return 0;
+ case WM_CHAR:
+ // You can also use ToAscii()+GetKeyboardState() to retrieve characters.
+ if (wParam > 0 && wParam < 0x10000)
+ io.AddInputCharacterUTF16((unsigned short)wParam);
+ return 0;
+ case WM_SETCURSOR:
+ if (LOWORD(lParam) == HTCLIENT && ImGui_ImplWin32_UpdateMouseCursor())
+ return 1;
+ return 0;
+ case WM_DEVICECHANGE:
+ if ((UINT)wParam == DBT_DEVNODES_CHANGED)
+ bd->WantUpdateHasGamepad = true;
+ return 0;
+ }
+ return 0;
}
@@ -409,21 +643,32 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA
// If you are trying to implement your own backend for your own engine, you may ignore that noise.
//---------------------------------------------------------------------------------------------------------
-// Implement some of the functions and types normally declared in recent Windows SDK.
-#if !defined(_versionhelpers_H_INCLUDED_) && !defined(_INC_VERSIONHELPERS)
-static BOOL IsWindowsVersionOrGreater(WORD major, WORD minor, WORD sp)
+// Perform our own check with RtlVerifyVersionInfo() instead of using functions from <VersionHelpers.h> as they
+// require a manifest to be functional for checks above 8.1. See https://github.com/ocornut/imgui/issues/4200
+static BOOL _IsWindowsVersionOrGreater(WORD major, WORD minor, WORD)
{
- OSVERSIONINFOEXW osvi = { sizeof(osvi), major, minor, 0, 0, { 0 }, sp, 0, 0, 0, 0 };
- DWORD mask = VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR;
- ULONGLONG cond = ::VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL);
- cond = ::VerSetConditionMask(cond, VER_MINORVERSION, VER_GREATER_EQUAL);
- cond = ::VerSetConditionMask(cond, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
- return ::VerifyVersionInfoW(&osvi, mask, cond);
+ typedef LONG(WINAPI* PFN_RtlVerifyVersionInfo)(OSVERSIONINFOEXW*, ULONG, ULONGLONG);
+ static PFN_RtlVerifyVersionInfo RtlVerifyVersionInfoFn = NULL;
+ if (RtlVerifyVersionInfoFn == NULL)
+ if (HMODULE ntdllModule = ::GetModuleHandleA("ntdll.dll"))
+ RtlVerifyVersionInfoFn = (PFN_RtlVerifyVersionInfo)GetProcAddress(ntdllModule, "RtlVerifyVersionInfo");
+ if (RtlVerifyVersionInfoFn == NULL)
+ return FALSE;
+
+ RTL_OSVERSIONINFOEXW versionInfo = { };
+ ULONGLONG conditionMask = 0;
+ versionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
+ versionInfo.dwMajorVersion = major;
+ versionInfo.dwMinorVersion = minor;
+ VER_SET_CONDITION(conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
+ VER_SET_CONDITION(conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
+ return (RtlVerifyVersionInfoFn(&versionInfo, VER_MAJORVERSION | VER_MINORVERSION, conditionMask) == 0) ? TRUE : FALSE;
}
-#define IsWindowsVistaOrGreater() IsWindowsVersionOrGreater(HIBYTE(0x0600), LOBYTE(0x0600), 0) // _WIN32_WINNT_VISTA
-#define IsWindows8OrGreater() IsWindowsVersionOrGreater(HIBYTE(0x0602), LOBYTE(0x0602), 0) // _WIN32_WINNT_WIN8
-#define IsWindows8Point1OrGreater() IsWindowsVersionOrGreater(HIBYTE(0x0603), LOBYTE(0x0603), 0) // _WIN32_WINNT_WINBLUE
-#endif
+
+#define _IsWindowsVistaOrGreater() _IsWindowsVersionOrGreater(HIBYTE(0x0600), LOBYTE(0x0600), 0) // _WIN32_WINNT_VISTA
+#define _IsWindows8OrGreater() _IsWindowsVersionOrGreater(HIBYTE(0x0602), LOBYTE(0x0602), 0) // _WIN32_WINNT_WIN8
+#define _IsWindows8Point1OrGreater() _IsWindowsVersionOrGreater(HIBYTE(0x0603), LOBYTE(0x0603), 0) // _WIN32_WINNT_WINBLUE
+#define _IsWindows10OrGreater() _IsWindowsVersionOrGreater(HIBYTE(0x0A00), LOBYTE(0x0A00), 0) // _WIN32_WINNT_WINTHRESHOLD / _WIN32_WINNT_WIN10
#ifndef DPI_ENUMS_DECLARED
typedef enum { PROCESS_DPI_UNAWARE = 0, PROCESS_SYSTEM_DPI_AWARE = 1, PROCESS_PER_MONITOR_DPI_AWARE = 2 } PROCESS_DPI_AWARENESS;
@@ -443,26 +688,26 @@ typedef DPI_AWARENESS_CONTEXT(WINAPI* PFN_SetThreadDpiAwarenessContext)(DPI_AWAR
// Helper function to enable DPI awareness without setting up a manifest
void ImGui_ImplWin32_EnableDpiAwareness()
{
- // if (IsWindows10OrGreater()) // This needs a manifest to succeed. Instead we try to grab the function pointer!
- {
- static HINSTANCE user32_dll = ::LoadLibraryA("user32.dll"); // Reference counted per-process
- if (PFN_SetThreadDpiAwarenessContext SetThreadDpiAwarenessContextFn = (PFN_SetThreadDpiAwarenessContext)::GetProcAddress(user32_dll, "SetThreadDpiAwarenessContext"))
- {
- SetThreadDpiAwarenessContextFn(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
- return;
- }
- }
- if (IsWindows8Point1OrGreater())
- {
- static HINSTANCE shcore_dll = ::LoadLibraryA("shcore.dll"); // Reference counted per-process
- if (PFN_SetProcessDpiAwareness SetProcessDpiAwarenessFn = (PFN_SetProcessDpiAwareness)::GetProcAddress(shcore_dll, "SetProcessDpiAwareness"))
- {
- SetProcessDpiAwarenessFn(PROCESS_PER_MONITOR_DPI_AWARE);
- return;
- }
- }
+ if (_IsWindows10OrGreater())
+ {
+ static HINSTANCE user32_dll = ::LoadLibraryA("user32.dll"); // Reference counted per-process
+ if (PFN_SetThreadDpiAwarenessContext SetThreadDpiAwarenessContextFn = (PFN_SetThreadDpiAwarenessContext)::GetProcAddress(user32_dll, "SetThreadDpiAwarenessContext"))
+ {
+ SetThreadDpiAwarenessContextFn(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
+ return;
+ }
+ }
+ if (_IsWindows8Point1OrGreater())
+ {
+ static HINSTANCE shcore_dll = ::LoadLibraryA("shcore.dll"); // Reference counted per-process
+ if (PFN_SetProcessDpiAwareness SetProcessDpiAwarenessFn = (PFN_SetProcessDpiAwareness)::GetProcAddress(shcore_dll, "SetProcessDpiAwareness"))
+ {
+ SetProcessDpiAwarenessFn(PROCESS_PER_MONITOR_DPI_AWARE);
+ return;
+ }
+ }
#if _WIN32_WINNT >= 0x0600
- ::SetProcessDPIAware();
+ ::SetProcessDPIAware();
#endif
}
@@ -472,31 +717,34 @@ void ImGui_ImplWin32_EnableDpiAwareness()
float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor)
{
- UINT xdpi = 96, ydpi = 96;
- static BOOL bIsWindows8Point1OrGreater = IsWindows8Point1OrGreater();
- if (bIsWindows8Point1OrGreater)
- {
+ UINT xdpi = 96, ydpi = 96;
+ if (_IsWindows8Point1OrGreater())
+ {
static HINSTANCE shcore_dll = ::LoadLibraryA("shcore.dll"); // Reference counted per-process
- if (PFN_GetDpiForMonitor GetDpiForMonitorFn = (PFN_GetDpiForMonitor)::GetProcAddress(shcore_dll, "GetDpiForMonitor"))
+ static PFN_GetDpiForMonitor GetDpiForMonitorFn = NULL;
+ if (GetDpiForMonitorFn == NULL && shcore_dll != NULL)
+ GetDpiForMonitorFn = (PFN_GetDpiForMonitor)::GetProcAddress(shcore_dll, "GetDpiForMonitor");
+ if (GetDpiForMonitorFn != NULL)
+ {
GetDpiForMonitorFn((HMONITOR)monitor, MDT_EFFECTIVE_DPI, &xdpi, &ydpi);
- }
+ IM_ASSERT(xdpi == ydpi); // Please contact me if you hit this assert!
+ return xdpi / 96.0f;
+ }
+ }
#ifndef NOGDI
- else
- {
- const HDC dc = ::GetDC(NULL);
- xdpi = ::GetDeviceCaps(dc, LOGPIXELSX);
- ydpi = ::GetDeviceCaps(dc, LOGPIXELSY);
- ::ReleaseDC(NULL, dc);
- }
+ const HDC dc = ::GetDC(NULL);
+ xdpi = ::GetDeviceCaps(dc, LOGPIXELSX);
+ ydpi = ::GetDeviceCaps(dc, LOGPIXELSY);
+ IM_ASSERT(xdpi == ydpi); // Please contact me if you hit this assert!
+ ::ReleaseDC(NULL, dc);
#endif
- IM_ASSERT(xdpi == ydpi); // Please contact me if you hit this assert!
- return xdpi / 96.0f;
+ return xdpi / 96.0f;
}
float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd)
{
- HMONITOR monitor = ::MonitorFromWindow((HWND)hwnd, MONITOR_DEFAULTTONEAREST);
- return ImGui_ImplWin32_GetDpiScaleForMonitor(monitor);
+ HMONITOR monitor = ::MonitorFromWindow((HWND)hwnd, MONITOR_DEFAULTTONEAREST);
+ return ImGui_ImplWin32_GetDpiScaleForMonitor(monitor);
}
//---------------------------------------------------------------------------------------------------------
@@ -512,31 +760,31 @@ float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd)
// (the Dwm* functions are Vista era functions but we are borrowing logic from GLFW)
void ImGui_ImplWin32_EnableAlphaCompositing(void* hwnd)
{
- if (!IsWindowsVistaOrGreater())
- return;
+ if (!_IsWindowsVistaOrGreater())
+ return;
- BOOL composition;
- if (FAILED(::DwmIsCompositionEnabled(&composition)) || !composition)
- return;
+ BOOL composition;
+ if (FAILED(::DwmIsCompositionEnabled(&composition)) || !composition)
+ return;
- BOOL opaque;
- DWORD color;
- if (IsWindows8OrGreater() || (SUCCEEDED(::DwmGetColorizationColor(&color, &opaque)) && !opaque))
- {
- HRGN region = ::CreateRectRgn(0, 0, -1, -1);
- DWM_BLURBEHIND bb = {};
- bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
- bb.hRgnBlur = region;
- bb.fEnable = TRUE;
- ::DwmEnableBlurBehindWindow((HWND)hwnd, &bb);
- ::DeleteObject(region);
- }
- else
- {
- DWM_BLURBEHIND bb = {};
- bb.dwFlags = DWM_BB_ENABLE;
- ::DwmEnableBlurBehindWindow((HWND)hwnd, &bb);
- }
+ BOOL opaque;
+ DWORD color;
+ if (_IsWindows8OrGreater() || (SUCCEEDED(::DwmGetColorizationColor(&color, &opaque)) && !opaque))
+ {
+ HRGN region = ::CreateRectRgn(0, 0, -1, -1);
+ DWM_BLURBEHIND bb = {};
+ bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
+ bb.hRgnBlur = region;
+ bb.fEnable = TRUE;
+ ::DwmEnableBlurBehindWindow((HWND)hwnd, &bb);
+ ::DeleteObject(region);
+ }
+ else
+ {
+ DWM_BLURBEHIND bb = {};
+ bb.dwFlags = DWM_BB_ENABLE;
+ ::DwmEnableBlurBehindWindow((HWND)hwnd, &bb);
+ }
}
//---------------------------------------------------------------------------------------------------------
diff --git a/3rdparty/imgui/backend/imgui_impl_win32.h b/3rdparty/imgui/backend/imgui_impl_win32.h
index 5197b7f..a04b6a7 100644
--- a/3rdparty/imgui/backend/imgui_impl_win32.h
+++ b/3rdparty/imgui/backend/imgui_impl_win32.h
@@ -3,11 +3,12 @@
// Implemented features:
// [X] Platform: Clipboard support (for Win32 this is actually part of core dear imgui)
-// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
-// [X] Platform: Keyboard arrays indexed using VK_* Virtual Key Codes, e.g. ImGui::IsKeyPressed(VK_SPACE).
+// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy VK_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
+// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
-// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// 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