diff --git a/examples/README.txt b/examples/README.txt
index 6ad61da0..e6ce70c9 100644
--- a/examples/README.txt
+++ b/examples/README.txt
@@ -1,16 +1,18 @@
-directx9_example/
- DirectX9 example application (Windows).
-
-directx11_example/
- DirectX11 example (Windows).
-
opengl_example/
- OpenGL exemple, using fixed pipeline (Windows/OSX/Linux etc., using glfw+glew)
+ OpenGL example, using GLFW + fixed pipeline.
This is simple and should work for all OpenGL enabled applications.
+ Prefer following this example since it is the shortest one!
opengl3_example/
- OpenGL exemple, using programmable pipeline (Windows/OSX/Linux etc., using glfw+glew)
+ OpenGL exemple, using GLFW/GL3W + programmable pipeline.
This uses more modern calls and custom shaders.
- I don't think there is an advantage using this over the "simpler example, but it is provided for information.
-
\ No newline at end of file
+ I don't think there is an advantage using this over the simpler example, but it is provided for reference.
+
+directx9_example/
+ DirectX9 example, Windows only.
+
+directx11_example/
+ DirectX11 example, Windows only.
+ This is quite long and tedious, because: DirectX11.
+
diff --git a/examples/directx11_example/directx11_example.vcxproj b/examples/directx11_example/directx11_example.vcxproj
index ec95e4ab..beddb330 100644
--- a/examples/directx11_example/directx11_example.vcxproj
+++ b/examples/directx11_example/directx11_example.vcxproj
@@ -48,7 +48,7 @@
Level3
Disabled
- $(DXSDK_DIR)/Include;%(AdditionalIncludeDirectories)
+ ..\..;$(DXSDK_DIR)/Include;%(AdditionalIncludeDirectories)
true
@@ -63,7 +63,7 @@
MaxSpeed
true
true
- $(DXSDK_DIR)/Include;%(AdditionalIncludeDirectories)
+ ..\..;$(DXSDK_DIR)/Include;%(AdditionalIncludeDirectories)
true
@@ -77,9 +77,11 @@
+
+
diff --git a/examples/directx11_example/directx11_example.vcxproj.filters b/examples/directx11_example/directx11_example.vcxproj.filters
index ab9c654e..fca4dcfd 100644
--- a/examples/directx11_example/directx11_example.vcxproj.filters
+++ b/examples/directx11_example/directx11_example.vcxproj.filters
@@ -15,6 +15,9 @@
imgui
+
+ sources
+
@@ -23,5 +26,8 @@
sources
+
+ sources
+
\ No newline at end of file
diff --git a/examples/directx11_example/imgui_impl_dx11.cpp b/examples/directx11_example/imgui_impl_dx11.cpp
new file mode 100644
index 00000000..727b5eeb
--- /dev/null
+++ b/examples/directx11_example/imgui_impl_dx11.cpp
@@ -0,0 +1,465 @@
+// ImGui Win32 + DirectX11 binding
+// https://github.com/ocornut/imgui
+
+#include
+#include "imgui_impl_dx11.h"
+
+// DirectX
+#include
+#include
+#define DIRECTINPUT_VERSION 0x0800
+#include
+
+// Data
+static INT64 g_Time = 0;
+static INT64 g_TicksPerSecond = 0;
+
+static HWND g_hWnd = 0;
+static ID3D11Device* g_pd3dDevice = NULL;
+static ID3D11DeviceContext* g_pd3dDeviceContext = NULL;
+static ID3D11Buffer* g_pVB = NULL;
+static ID3D10Blob * g_pVertexShaderBlob = NULL;
+static ID3D11VertexShader* g_pVertexShader = NULL;
+static ID3D11InputLayout* g_pInputLayout = NULL;
+static ID3D11Buffer* g_pVertexConstantBuffer = NULL;
+static ID3D10Blob * g_pPixelShaderBlob = NULL;
+static ID3D11PixelShader* g_pPixelShader = NULL;
+static ID3D11SamplerState* g_pFontSampler = NULL;
+static ID3D11ShaderResourceView*g_pFontTextureView = NULL;
+static ID3D11BlendState* g_blendState = NULL;
+
+struct CUSTOMVERTEX
+{
+ float pos[2];
+ float uv[2];
+ unsigned int col;
+};
+
+struct VERTEX_CONSTANT_BUFFER
+{
+ float mvp[4][4];
+};
+
+// This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure)
+// If text or lines are blurry when integrating ImGui in your engine:
+// - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f)
+static void ImGui_ImplDX11_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count)
+{
+ // Copy and convert all vertices into a single contiguous buffer
+ D3D11_MAPPED_SUBRESOURCE mappedResource;
+ if (g_pd3dDeviceContext->Map(g_pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource) != S_OK)
+ return;
+ CUSTOMVERTEX* vtx_dst = (CUSTOMVERTEX*)mappedResource.pData;
+ for (int n = 0; n < cmd_lists_count; n++)
+ {
+ const ImDrawList* cmd_list = cmd_lists[n];
+ const ImDrawVert* vtx_src = &cmd_list->vtx_buffer[0];
+ for (size_t i = 0; i < cmd_list->vtx_buffer.size(); i++)
+ {
+ vtx_dst->pos[0] = vtx_src->pos.x;
+ vtx_dst->pos[1] = vtx_src->pos.y;
+ vtx_dst->uv[0] = vtx_src->uv.x;
+ vtx_dst->uv[1] = vtx_src->uv.y;
+ vtx_dst->col = vtx_src->col;
+ vtx_dst++;
+ vtx_src++;
+ }
+ }
+ g_pd3dDeviceContext->Unmap(g_pVB, 0);
+
+ // Setup orthographic projection matrix into our constant buffer
+ {
+ D3D11_MAPPED_SUBRESOURCE mappedResource;
+ if (g_pd3dDeviceContext->Map(g_pVertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource) != S_OK)
+ return;
+
+ VERTEX_CONSTANT_BUFFER* pConstantBuffer = (VERTEX_CONSTANT_BUFFER*)mappedResource.pData;
+ const float L = 0.0f;
+ const float R = ImGui::GetIO().DisplaySize.x;
+ const float B = ImGui::GetIO().DisplaySize.y;
+ const float T = 0.0f;
+ const float mvp[4][4] =
+ {
+ { 2.0f/(R-L), 0.0f, 0.0f, 0.0f},
+ { 0.0f, 2.0f/(T-B), 0.0f, 0.0f,},
+ { 0.0f, 0.0f, 0.5f, 0.0f },
+ { (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f },
+ };
+ memcpy(&pConstantBuffer->mvp, mvp, sizeof(mvp));
+ g_pd3dDeviceContext->Unmap(g_pVertexConstantBuffer, 0);
+ }
+
+ // Setup viewport
+ {
+ D3D11_VIEWPORT vp;
+ memset(&vp, 0, sizeof(D3D11_VIEWPORT));
+ vp.Width = ImGui::GetIO().DisplaySize.x;
+ vp.Height = ImGui::GetIO().DisplaySize.y;
+ vp.MinDepth = 0.0f;
+ vp.MaxDepth = 1.0f;
+ vp.TopLeftX = 0;
+ vp.TopLeftY = 0;
+ g_pd3dDeviceContext->RSSetViewports(1, &vp);
+ }
+
+ // Bind shader and vertex buffers
+ unsigned int stride = sizeof(CUSTOMVERTEX);
+ unsigned int offset = 0;
+ g_pd3dDeviceContext->IASetInputLayout(g_pInputLayout);
+ g_pd3dDeviceContext->IASetVertexBuffers(0, 1, &g_pVB, &stride, &offset);
+ g_pd3dDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
+ g_pd3dDeviceContext->VSSetShader(g_pVertexShader, NULL, 0);
+ g_pd3dDeviceContext->VSSetConstantBuffers(0, 1, &g_pVertexConstantBuffer);
+ g_pd3dDeviceContext->PSSetShader(g_pPixelShader, NULL, 0);
+ g_pd3dDeviceContext->PSSetSamplers(0, 1, &g_pFontSampler);
+
+ // Setup render state
+ const float blendFactor[4] = { 0.f, 0.f, 0.f, 0.f };
+ g_pd3dDeviceContext->OMSetBlendState(g_blendState, blendFactor, 0xffffffff);
+
+ // Render command lists
+ int vtx_offset = 0;
+ for (int n = 0; n < cmd_lists_count; n++)
+ {
+ const ImDrawList* cmd_list = cmd_lists[n];
+ for (size_t cmd_i = 0; cmd_i < cmd_list->commands.size(); cmd_i++)
+ {
+ const ImDrawCmd* pcmd = &cmd_list->commands[cmd_i];
+ if (pcmd->user_callback)
+ {
+ pcmd->user_callback(cmd_list, pcmd);
+ }
+ else
+ {
+ const D3D11_RECT r = { (LONG)pcmd->clip_rect.x, (LONG)pcmd->clip_rect.y, (LONG)pcmd->clip_rect.z, (LONG)pcmd->clip_rect.w };
+ g_pd3dDeviceContext->PSSetShaderResources(0, 1, (ID3D11ShaderResourceView**)&pcmd->texture_id);
+ g_pd3dDeviceContext->RSSetScissorRects(1, &r);
+ g_pd3dDeviceContext->Draw(pcmd->vtx_count, vtx_offset);
+ }
+ vtx_offset += pcmd->vtx_count;
+ }
+ }
+
+ // Restore modified state
+ g_pd3dDeviceContext->IASetInputLayout(NULL);
+ g_pd3dDeviceContext->PSSetShader(NULL, NULL, 0);
+ g_pd3dDeviceContext->VSSetShader(NULL, NULL, 0);
+}
+
+LRESULT ImGui_ImplDX11_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ ImGuiIO& io = ImGui::GetIO();
+ switch (msg)
+ {
+ case WM_LBUTTONDOWN:
+ io.MouseDown[0] = true;
+ return true;
+ case WM_LBUTTONUP:
+ io.MouseDown[0] = false;
+ return true;
+ case WM_RBUTTONDOWN:
+ io.MouseDown[1] = true;
+ return true;
+ case WM_RBUTTONUP:
+ io.MouseDown[1] = false;
+ return true;
+ case WM_MOUSEWHEEL:
+ io.MouseWheel += GET_WHEEL_DELTA_WPARAM(wParam) > 0 ? +1.0f : -1.0f;
+ return true;
+ case WM_MOUSEMOVE:
+ io.MousePos.x = (signed short)(lParam);
+ io.MousePos.y = (signed short)(lParam >> 16);
+ return true;
+ case WM_KEYDOWN:
+ if (wParam >= 0 && wParam < 256)
+ io.KeysDown[wParam] = 1;
+ return true;
+ case WM_KEYUP:
+ if (wParam >= 0 && wParam < 256)
+ io.KeysDown[wParam] = 0;
+ return true;
+ case WM_CHAR:
+ // You can also use ToAscii()+GetKeyboardState() to retrieve characters.
+ if (wParam > 0 && wParam < 0x10000)
+ io.AddInputCharacter((unsigned short)wParam);
+ return true;
+ }
+ return 0;
+}
+
+static void ImGui_ImplDX11_CreateFontsTexture()
+{
+ ImGuiIO& io = ImGui::GetIO();
+
+ // Build
+ unsigned char* pixels;
+ int width, height;
+ io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
+
+ // Create DX11 texture
+ {
+ D3D11_TEXTURE2D_DESC texDesc;
+ ZeroMemory(&texDesc, sizeof(texDesc));
+ texDesc.Width = width;
+ texDesc.Height = height;
+ texDesc.MipLevels = 1;
+ texDesc.ArraySize = 1;
+ texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ texDesc.SampleDesc.Count = 1;
+ texDesc.Usage = D3D11_USAGE_DEFAULT;
+ texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
+ texDesc.CPUAccessFlags = 0;
+
+ ID3D11Texture2D *pTexture = NULL;
+ D3D11_SUBRESOURCE_DATA subResource;
+ subResource.pSysMem = pixels;
+ subResource.SysMemPitch = texDesc.Width * 4;
+ subResource.SysMemSlicePitch = 0;
+ g_pd3dDevice->CreateTexture2D(&texDesc, &subResource, &pTexture);
+
+ // Create texture view
+ D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
+ ZeroMemory(&srvDesc, sizeof(srvDesc));
+ srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
+ srvDesc.Texture2D.MipLevels = texDesc.MipLevels;
+ srvDesc.Texture2D.MostDetailedMip = 0;
+ g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &g_pFontTextureView);
+ pTexture->Release();
+ }
+
+ // Store our identifier
+ io.Fonts->TexID = (void *)g_pFontTextureView;
+
+ // Create texture sampler
+ {
+ D3D11_SAMPLER_DESC samplerDesc;
+ ZeroMemory(&samplerDesc, sizeof(samplerDesc));
+ samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
+ samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
+ samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
+ samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
+ samplerDesc.MipLODBias = 0.f;
+ samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
+ samplerDesc.MinLOD = 0.f;
+ samplerDesc.MaxLOD = 0.f;
+ g_pd3dDevice->CreateSamplerState(&samplerDesc, &g_pFontSampler);
+ }
+}
+
+bool ImGui_ImplDX11_CreateDeviceObjects()
+{
+ if (!g_pd3dDevice)
+ return false;
+ if (g_pVB)
+ ImGui_ImplDX11_InvalidateDeviceObjects();
+
+ // Create the vertex shader
+ {
+ static const char* vertexShader =
+ "cbuffer vertexBuffer : register(c0) \
+ {\
+ float4x4 ProjectionMatrix; \
+ };\
+ struct VS_INPUT\
+ {\
+ float2 pos : POSITION;\
+ float4 col : COLOR0;\
+ float2 uv : TEXCOORD0;\
+ };\
+ \
+ struct PS_INPUT\
+ {\
+ float4 pos : SV_POSITION;\
+ float4 col : COLOR0;\
+ float2 uv : TEXCOORD0;\
+ };\
+ \
+ PS_INPUT main(VS_INPUT input)\
+ {\
+ PS_INPUT output;\
+ output.pos = mul( ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));\
+ output.col = input.col;\
+ output.uv = input.uv;\
+ return output;\
+ }";
+
+ D3DCompile(vertexShader, strlen(vertexShader), NULL, NULL, NULL, "main", "vs_5_0", 0, 0, &g_pVertexShaderBlob, NULL);
+ if (g_pVertexShaderBlob == NULL) // NB: Pass ID3D10Blob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
+ return false;
+ if (g_pd3dDevice->CreateVertexShader((DWORD*)g_pVertexShaderBlob->GetBufferPointer(), g_pVertexShaderBlob->GetBufferSize(), NULL, &g_pVertexShader) != S_OK)
+ return false;
+
+ // Create the input layout
+ D3D11_INPUT_ELEMENT_DESC localLayout[] = {
+ { "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, (size_t)(&((CUSTOMVERTEX*)0)->pos), D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (size_t)(&((CUSTOMVERTEX*)0)->col), D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((CUSTOMVERTEX*)0)->uv), D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ };
+
+ if (g_pd3dDevice->CreateInputLayout(localLayout, 3, g_pVertexShaderBlob->GetBufferPointer(), g_pVertexShaderBlob->GetBufferSize(), &g_pInputLayout) != S_OK)
+ return false;
+
+ // Create the constant buffer
+ {
+ D3D11_BUFFER_DESC cbDesc;
+ cbDesc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER);
+ cbDesc.Usage = D3D11_USAGE_DYNAMIC;
+ cbDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
+ cbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ cbDesc.MiscFlags = 0;
+ g_pd3dDevice->CreateBuffer(&cbDesc, NULL, &g_pVertexConstantBuffer);
+ }
+ }
+
+ // Create the pixel shader
+ {
+ static const char* pixelShader =
+ "struct PS_INPUT\
+ {\
+ float4 pos : SV_POSITION;\
+ float4 col : COLOR0;\
+ float2 uv : TEXCOORD0;\
+ };\
+ sampler sampler0;\
+ Texture2D texture0;\
+ \
+ float4 main(PS_INPUT input) : SV_Target\
+ {\
+ float4 out_col = input.col * texture0.Sample(sampler0, input.uv); \
+ return out_col; \
+ }";
+
+ D3DCompile(pixelShader, strlen(pixelShader), NULL, NULL, NULL, "main", "ps_5_0", 0, 0, &g_pPixelShaderBlob, NULL);
+ if (g_pPixelShaderBlob == NULL) // NB: Pass ID3D10Blob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
+ return false;
+ if (g_pd3dDevice->CreatePixelShader((DWORD*)g_pPixelShaderBlob->GetBufferPointer(), g_pPixelShaderBlob->GetBufferSize(), NULL, &g_pPixelShader) != S_OK)
+ return false;
+ }
+
+ // Create the blending setup
+ {
+ D3D11_BLEND_DESC desc;
+ ZeroMemory(&desc, sizeof(desc));
+ desc.AlphaToCoverageEnable = false;
+ desc.RenderTarget[0].BlendEnable = true;
+ desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
+ desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
+ desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
+ desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
+ desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
+ desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
+ desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
+ g_pd3dDevice->CreateBlendState(&desc, &g_blendState);
+ }
+
+ // Create the vertex buffer
+ {
+ D3D11_BUFFER_DESC bufferDesc;
+ memset(&bufferDesc, 0, sizeof(D3D11_BUFFER_DESC));
+ bufferDesc.Usage = D3D11_USAGE_DYNAMIC;
+ bufferDesc.ByteWidth = 100000 * sizeof(CUSTOMVERTEX); // Maybe we should handle that more dynamically?
+ bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
+ bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ bufferDesc.MiscFlags = 0;
+ if (g_pd3dDevice->CreateBuffer(&bufferDesc, NULL, &g_pVB) < 0)
+ return false;
+ }
+
+ ImGui_ImplDX11_CreateFontsTexture();
+
+ return true;
+}
+
+void ImGui_ImplDX11_InvalidateDeviceObjects()
+{
+ if (!g_pd3dDevice)
+ return;
+
+ if (g_pFontSampler) { g_pFontSampler->Release(); g_pFontSampler = NULL; }
+ if (g_pFontTextureView) { g_pFontTextureView->Release(); ImGui::GetIO().Fonts->TexID = 0; }
+ if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
+
+ if (g_blendState) { g_blendState->Release(); g_blendState = NULL; }
+ if (g_pPixelShader) { g_pPixelShader->Release(); g_pPixelShader = NULL; }
+ if (g_pPixelShaderBlob) { g_pPixelShaderBlob->Release(); g_pPixelShaderBlob = 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 (g_pVertexShaderBlob) { g_pVertexShaderBlob->Release(); g_pVertexShaderBlob = NULL; }
+}
+
+bool ImGui_ImplDX11_Init(void* hwnd, ID3D11Device* device, ID3D11DeviceContext* device_context)
+{
+ g_hWnd = (HWND)hwnd;
+ g_pd3dDevice = device;
+ g_pd3dDeviceContext = device_context;
+
+ if (!QueryPerformanceFrequency((LARGE_INTEGER *)&g_TicksPerSecond))
+ return false;
+ if (!QueryPerformanceCounter((LARGE_INTEGER *)&g_Time))
+ return false;
+
+ ImGuiIO& io = ImGui::GetIO();
+ io.KeyMap[ImGuiKey_Tab] = VK_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array that we will update during the application lifetime.
+ io.KeyMap[ImGuiKey_LeftArrow] = VK_LEFT;
+ io.KeyMap[ImGuiKey_RightArrow] = VK_RIGHT;
+ io.KeyMap[ImGuiKey_UpArrow] = VK_UP;
+ io.KeyMap[ImGuiKey_DownArrow] = VK_UP;
+ io.KeyMap[ImGuiKey_Home] = VK_HOME;
+ io.KeyMap[ImGuiKey_End] = VK_END;
+ io.KeyMap[ImGuiKey_Delete] = VK_DELETE;
+ io.KeyMap[ImGuiKey_Backspace] = VK_BACK;
+ io.KeyMap[ImGuiKey_Enter] = VK_RETURN;
+ io.KeyMap[ImGuiKey_Escape] = VK_ESCAPE;
+ 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';
+
+ io.RenderDrawListsFn = ImGui_ImplDX11_RenderDrawLists;
+ io.ImeWindowHandle = g_hWnd;
+
+ return true;
+}
+
+void ImGui_ImplDX11_Shutdown()
+{
+ ImGui_ImplDX11_InvalidateDeviceObjects();
+ ImGui::Shutdown();
+ g_pd3dDevice = NULL;
+ g_pd3dDeviceContext = NULL;
+ g_hWnd = (HWND)0;
+}
+
+void ImGui_ImplDX11_NewFrame()
+{
+ if (!g_pVB)
+ ImGui_ImplDX11_CreateDeviceObjects();
+
+ ImGuiIO& io = ImGui::GetIO();
+
+ // Setup display size (every frame to accommodate for window resizing)
+ RECT rect;
+ GetClientRect(g_hWnd, &rect);
+ io.DisplaySize = ImVec2((float)(rect.right - rect.left), (float)(rect.bottom - rect.top));
+
+ // Setup time step
+ INT64 current_time;
+ QueryPerformanceCounter((LARGE_INTEGER *)¤t_time);
+ io.DeltaTime = (float)(current_time - g_Time) / g_TicksPerSecond;
+ g_Time = current_time;
+
+ // Read keyboard modifiers inputs
+ io.KeyCtrl = (GetKeyState(VK_CONTROL) & 0x8000) != 0;
+ io.KeyShift = (GetKeyState(VK_SHIFT) & 0x8000) != 0;
+ // io.KeysDown : filled by WM_KEYDOWN/WM_KEYUP events
+ // io.MousePos : filled by WM_MOUSEMOVE events
+ // io.MouseDown : filled by WM_*BUTTON* events
+ // io.MouseWheel : filled by WM_MOUSEWHEEL events
+
+ // Start the frame
+ ImGui::NewFrame();
+}
diff --git a/examples/directx11_example/imgui_impl_dx11.h b/examples/directx11_example/imgui_impl_dx11.h
new file mode 100644
index 00000000..c920d0b9
--- /dev/null
+++ b/examples/directx11_example/imgui_impl_dx11.h
@@ -0,0 +1,20 @@
+// ImGui Win32 + DirectX11 binding
+// https://github.com/ocornut/imgui
+
+struct ID3D11Device;
+struct ID3D11DeviceContext;
+
+bool ImGui_ImplDX11_Init(void* hwnd, ID3D11Device* device, ID3D11DeviceContext* device_context);
+void ImGui_ImplDX11_Shutdown();
+void ImGui_ImplDX11_NewFrame();
+
+// Use if you want to reset your rendering device without losing ImGui state.
+void ImGui_ImplDX11_InvalidateDeviceObjects();
+bool ImGui_ImplDX11_CreateDeviceObjects();
+
+// Handler for Win32 messages, update mouse/keyboard data.
+// You may or not need this for your implementation, but it can serve as reference for handling inputs.
+// Commented out to avoid dragging dependencies on types. You can copy the extern declaration in your code.
+/*
+extern LRESULT ImGui_ImplDX11_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+*/
diff --git a/examples/directx11_example/main.cpp b/examples/directx11_example/main.cpp
index a7f7a993..0620245b 100644
--- a/examples/directx11_example/main.cpp
+++ b/examples/directx11_example/main.cpp
@@ -1,149 +1,41 @@
// ImGui - standalone example application for DirectX 11
-#include
-#include "../../imgui.h"
-
-// DirectX 11
+#include
+#include "imgui_impl_dx11.h"
#include
#include
#define DIRECTINPUT_VERSION 0x0800
#include
-#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strdup
-
-static HWND hWnd;
+// Data
static ID3D11Device* g_pd3dDevice = NULL;
-static ID3D11DeviceContext* g_pd3dDeviceImmediateContext = NULL;
+static ID3D11DeviceContext* g_pd3dDeviceContext = NULL;
static IDXGISwapChain* g_pSwapChain = NULL;
-static ID3D11Buffer* g_pVB = NULL;
-static ID3D11RenderTargetView* g_mainRenderTargetView;
-
-static ID3D10Blob * g_pVertexShaderBlob = NULL;
-static ID3D11VertexShader* g_pVertexShader = NULL;
-static ID3D11InputLayout* g_pInputLayout = NULL;
-static ID3D11Buffer* g_pVertexConstantBuffer = NULL;
-
-static ID3D10Blob * g_pPixelShaderBlob = NULL;
-static ID3D11PixelShader* g_pPixelShader = NULL;
+static ID3D11RenderTargetView* g_mainRenderTargetView = NULL;
-static ID3D11SamplerState* g_pFontSampler = NULL;
-static ID3D11BlendState* g_blendState = NULL;
-
-struct CUSTOMVERTEX
+void CreateRenderTarget()
{
- float pos[2];
- float uv[2];
- unsigned int col;
-};
+ DXGI_SWAP_CHAIN_DESC sd;
+ g_pSwapChain->GetDesc(&sd);
-struct VERTEX_CONSTANT_BUFFER
-{
- float mvp[4][4];
-};
+ // Create the render target
+ ID3D11Texture2D* pBackBuffer;
+ D3D11_RENDER_TARGET_VIEW_DESC render_target_view_desc;
+ ZeroMemory(&render_target_view_desc, sizeof(render_target_view_desc));
+ render_target_view_desc.Format = sd.BufferDesc.Format;
+ render_target_view_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
+ g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
+ g_pd3dDevice->CreateRenderTargetView(pBackBuffer, &render_target_view_desc, &g_mainRenderTargetView);
+ g_pd3dDeviceContext->OMSetRenderTargets(1, &g_mainRenderTargetView, NULL);
+ pBackBuffer->Release();
+}
-// This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure)
-// If text or lines are blurry when integrating ImGui in your engine:
-// - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f)
-static void ImImpl_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count)
+void CleanupRenderTarget()
{
- // Copy and convert all vertices into a single contiguous buffer
- D3D11_MAPPED_SUBRESOURCE mappedResource;
- if (g_pd3dDeviceImmediateContext->Map(g_pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource) != S_OK)
- return;
- CUSTOMVERTEX* vtx_dst = (CUSTOMVERTEX*)mappedResource.pData;
- for (int n = 0; n < cmd_lists_count; n++)
- {
- const ImDrawList* cmd_list = cmd_lists[n];
- const ImDrawVert* vtx_src = &cmd_list->vtx_buffer[0];
- for (size_t i = 0; i < cmd_list->vtx_buffer.size(); i++)
- {
- vtx_dst->pos[0] = vtx_src->pos.x;
- vtx_dst->pos[1] = vtx_src->pos.y;
- vtx_dst->uv[0] = vtx_src->uv.x;
- vtx_dst->uv[1] = vtx_src->uv.y;
- vtx_dst->col = vtx_src->col;
- vtx_dst++;
- vtx_src++;
- }
- }
- g_pd3dDeviceImmediateContext->Unmap(g_pVB, 0);
-
- // Setup orthographic projection matrix into our constant buffer
- {
- D3D11_MAPPED_SUBRESOURCE mappedResource;
- if (g_pd3dDeviceImmediateContext->Map(g_pVertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource) != S_OK)
- return;
-
- VERTEX_CONSTANT_BUFFER* pConstantBuffer = (VERTEX_CONSTANT_BUFFER*)mappedResource.pData;
- const float L = 0.0f;
- const float R = ImGui::GetIO().DisplaySize.x;
- const float B = ImGui::GetIO().DisplaySize.y;
- const float T = 0.0f;
- const float mvp[4][4] =
- {
- { 2.0f/(R-L), 0.0f, 0.0f, 0.0f},
- { 0.0f, 2.0f/(T-B), 0.0f, 0.0f,},
- { 0.0f, 0.0f, 0.5f, 0.0f },
- { (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f },
- };
- memcpy(&pConstantBuffer->mvp, mvp, sizeof(mvp));
- g_pd3dDeviceImmediateContext->Unmap(g_pVertexConstantBuffer, 0);
- }
-
- // Setup viewport
- {
- D3D11_VIEWPORT vp;
- memset(&vp, 0, sizeof(D3D11_VIEWPORT));
- vp.Width = ImGui::GetIO().DisplaySize.x;
- vp.Height = ImGui::GetIO().DisplaySize.y;
- vp.MinDepth = 0.0f;
- vp.MaxDepth = 1.0f;
- vp.TopLeftX = 0;
- vp.TopLeftY = 0;
- g_pd3dDeviceImmediateContext->RSSetViewports(1, &vp);
- }
-
- // Bind shader and vertex buffers
- unsigned int stride = sizeof(CUSTOMVERTEX);
- unsigned int offset = 0;
- g_pd3dDeviceImmediateContext->IASetInputLayout(g_pInputLayout);
- g_pd3dDeviceImmediateContext->IASetVertexBuffers(0, 1, &g_pVB, &stride, &offset);
- g_pd3dDeviceImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
-
- g_pd3dDeviceImmediateContext->VSSetShader(g_pVertexShader, NULL, 0);
- g_pd3dDeviceImmediateContext->VSSetConstantBuffers(0, 1, &g_pVertexConstantBuffer);
-
- g_pd3dDeviceImmediateContext->PSSetShader(g_pPixelShader, NULL, 0);
- g_pd3dDeviceImmediateContext->PSSetSamplers(0, 1, &g_pFontSampler);
-
- // Setup render state
- const float blendFactor[4] = { 0.f, 0.f, 0.f, 0.f };
- g_pd3dDeviceImmediateContext->OMSetBlendState(g_blendState, blendFactor, 0xffffffff);
-
- // Render command lists
- int vtx_offset = 0;
- for (int n = 0; n < cmd_lists_count; n++)
- {
- // Render command list
- const ImDrawList* cmd_list = cmd_lists[n];
- for (size_t cmd_i = 0; cmd_i < cmd_list->commands.size(); cmd_i++)
- {
- const ImDrawCmd* pcmd = &cmd_list->commands[cmd_i];
- const D3D11_RECT r = { (LONG)pcmd->clip_rect.x, (LONG)pcmd->clip_rect.y, (LONG)pcmd->clip_rect.z, (LONG)pcmd->clip_rect.w };
- g_pd3dDeviceImmediateContext->PSSetShaderResources(0, 1, (ID3D11ShaderResourceView**)&pcmd->texture_id);
- g_pd3dDeviceImmediateContext->RSSetScissorRects(1, &r);
- g_pd3dDeviceImmediateContext->Draw(pcmd->vtx_count, vtx_offset);
- vtx_offset += pcmd->vtx_count;
- }
- }
-
- // Restore modified state
- g_pd3dDeviceImmediateContext->IASetInputLayout(NULL);
- g_pd3dDeviceImmediateContext->PSSetShader(NULL, NULL, 0);
- g_pd3dDeviceImmediateContext->VSSetShader(NULL, NULL, 0);
+ if (g_mainRenderTargetView) { g_mainRenderTargetView->Release(); g_mainRenderTargetView = NULL; }
}
-HRESULT InitDeviceD3D(HWND hWnd)
+HRESULT CreateDeviceD3D(HWND hWnd)
{
// Setup swap chain
DXGI_SWAP_CHAIN_DESC sd;
@@ -170,7 +62,7 @@ HRESULT InitDeviceD3D(HWND hWnd)
#endif
D3D_FEATURE_LEVEL featureLevel;
const D3D_FEATURE_LEVEL featureLevelArray[1] = { D3D_FEATURE_LEVEL_11_0, };
- if (D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, createDeviceFlags, featureLevelArray, 1, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceImmediateContext) != S_OK)
+ if (D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, createDeviceFlags, featureLevelArray, 1, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceContext) != S_OK)
return E_FAIL;
// Setup rasterizer
@@ -190,369 +82,81 @@ HRESULT InitDeviceD3D(HWND hWnd)
ID3D11RasterizerState* pRState = NULL;
g_pd3dDevice->CreateRasterizerState(&RSDesc, &pRState);
- g_pd3dDeviceImmediateContext->RSSetState(pRState);
+ g_pd3dDeviceContext->RSSetState(pRState);
pRState->Release();
}
- // Create the render target
- {
- ID3D11Texture2D* pBackBuffer;
- D3D11_RENDER_TARGET_VIEW_DESC render_target_view_desc;
- ZeroMemory(&render_target_view_desc, sizeof(render_target_view_desc));
- render_target_view_desc.Format = sd.BufferDesc.Format;
- render_target_view_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
- g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
- g_pd3dDevice->CreateRenderTargetView(pBackBuffer, &render_target_view_desc, &g_mainRenderTargetView);
- g_pd3dDeviceImmediateContext->OMSetRenderTargets(1, &g_mainRenderTargetView, NULL);
- pBackBuffer->Release();
- }
-
- // Create the vertex shader
- {
- static const char* vertexShader =
- "cbuffer vertexBuffer : register(c0) \
- {\
- float4x4 ProjectionMatrix; \
- };\
- struct VS_INPUT\
- {\
- float2 pos : POSITION;\
- float4 col : COLOR0;\
- float2 uv : TEXCOORD0;\
- };\
- \
- struct PS_INPUT\
- {\
- float4 pos : SV_POSITION;\
- float4 col : COLOR0;\
- float2 uv : TEXCOORD0;\
- };\
- \
- PS_INPUT main(VS_INPUT input)\
- {\
- PS_INPUT output;\
- output.pos = mul( ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));\
- output.col = input.col;\
- output.uv = input.uv;\
- return output;\
- }";
-
- D3DCompile(vertexShader, strlen(vertexShader), NULL, NULL, NULL, "main", "vs_5_0", 0, 0, &g_pVertexShaderBlob, NULL);
- if (g_pVertexShaderBlob == NULL) // NB: Pass ID3D10Blob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
- return E_FAIL;
- if (g_pd3dDevice->CreateVertexShader((DWORD*)g_pVertexShaderBlob->GetBufferPointer(), g_pVertexShaderBlob->GetBufferSize(), NULL, &g_pVertexShader) != S_OK)
- return E_FAIL;
-
- // Create the input layout
- D3D11_INPUT_ELEMENT_DESC localLayout[] = {
- { "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, (size_t)(&((CUSTOMVERTEX*)0)->pos), D3D11_INPUT_PER_VERTEX_DATA, 0 },
- { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (size_t)(&((CUSTOMVERTEX*)0)->col), D3D11_INPUT_PER_VERTEX_DATA, 0 },
- { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((CUSTOMVERTEX*)0)->uv), D3D11_INPUT_PER_VERTEX_DATA, 0 },
- };
-
- if (g_pd3dDevice->CreateInputLayout(localLayout, 3, g_pVertexShaderBlob->GetBufferPointer(), g_pVertexShaderBlob->GetBufferSize(), &g_pInputLayout) != S_OK)
- return E_FAIL;
-
- // Create the constant buffer
- {
- D3D11_BUFFER_DESC cbDesc;
- cbDesc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER);
- cbDesc.Usage = D3D11_USAGE_DYNAMIC;
- cbDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
- cbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
- cbDesc.MiscFlags = 0;
- g_pd3dDevice->CreateBuffer(&cbDesc, NULL, &g_pVertexConstantBuffer);
- }
- }
-
- // Create the pixel shader
- {
- static const char* pixelShader =
- "struct PS_INPUT\
- {\
- float4 pos : SV_POSITION;\
- float4 col : COLOR0;\
- float2 uv : TEXCOORD0;\
- };\
- sampler sampler0;\
- Texture2D texture0;\
- \
- float4 main(PS_INPUT input) : SV_Target\
- {\
- float4 out_col = input.col * texture0.Sample(sampler0, input.uv); \
- return out_col; \
- }";
-
- D3DCompile(pixelShader, strlen(pixelShader), NULL, NULL, NULL, "main", "ps_5_0", 0, 0, &g_pPixelShaderBlob, NULL);
- if (g_pPixelShaderBlob == NULL) // NB: Pass ID3D10Blob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
- return E_FAIL;
- if (g_pd3dDevice->CreatePixelShader((DWORD*)g_pPixelShaderBlob->GetBufferPointer(), g_pPixelShaderBlob->GetBufferSize(), NULL, &g_pPixelShader) != S_OK)
- return E_FAIL;
- }
-
- // Create the blending setup
- {
- D3D11_BLEND_DESC desc;
- ZeroMemory(&desc, sizeof(desc));
- desc.AlphaToCoverageEnable = false;
- desc.RenderTarget[0].BlendEnable = true;
- desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
- desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
- desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
- desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
- desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
- desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
- desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
- g_pd3dDevice->CreateBlendState(&desc, &g_blendState);
- }
+ CreateRenderTarget();
return S_OK;
}
-void CleanupDevice()
+void CleanupDeviceD3D()
{
- if (g_pd3dDeviceImmediateContext) g_pd3dDeviceImmediateContext->ClearState();
-
- // InitImGui
- if (g_pFontSampler) g_pFontSampler->Release();
- if (ID3D11ShaderResourceView* font_texture_view = (ID3D11ShaderResourceView*)ImGui::GetIO().Fonts->TexID)
- font_texture_view->Release();
- if (g_pVB) g_pVB->Release();
-
- // InitDeviceD3D
- if (g_blendState) g_blendState->Release();
- if (g_pPixelShader) g_pPixelShader->Release();
- if (g_pPixelShaderBlob) g_pPixelShaderBlob->Release();
- if (g_pVertexConstantBuffer) g_pVertexConstantBuffer->Release();
- if (g_pInputLayout) g_pInputLayout->Release();
- if (g_pVertexShader) g_pVertexShader->Release();
- if (g_pVertexShaderBlob) g_pVertexShaderBlob->Release();
- if (g_mainRenderTargetView) g_mainRenderTargetView->Release();
- if (g_pSwapChain) g_pSwapChain->Release();
- if (g_pd3dDeviceImmediateContext) g_pd3dDeviceImmediateContext->Release();
- if (g_pd3dDevice) g_pd3dDevice->Release();
+ CleanupRenderTarget();
+ if (g_pSwapChain) { g_pSwapChain->Release(); g_pSwapChain = NULL; }
+ if (g_pd3dDeviceContext) { g_pd3dDeviceContext->Release(); g_pd3dDeviceContext = NULL; }
+ if (g_pd3dDevice) { g_pd3dDevice->Release(); g_pd3dDevice = NULL; }
}
+extern LRESULT ImGui_ImplDX11_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
- ImGuiIO& io = ImGui::GetIO();
+ if (ImGui_ImplDX11_WndProcHandler(hWnd, msg, wParam, lParam))
+ return true;
+
switch (msg)
{
- case WM_LBUTTONDOWN:
- io.MouseDown[0] = true;
- return true;
- case WM_LBUTTONUP:
- io.MouseDown[0] = false;
- return true;
- case WM_RBUTTONDOWN:
- io.MouseDown[1] = true;
- return true;
- case WM_RBUTTONUP:
- io.MouseDown[1] = false;
- return true;
- case WM_MOUSEWHEEL:
- io.MouseWheel += GET_WHEEL_DELTA_WPARAM(wParam) > 0 ? +1.0f : -1.0f;
- return true;
- case WM_MOUSEMOVE:
- // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.)
- io.MousePos.x = (signed short)(lParam);
- io.MousePos.y = (signed short)(lParam >> 16);
- return true;
- case WM_KEYDOWN:
- if (wParam >= 0 && wParam < 256)
- io.KeysDown[wParam] = 1;
- return true;
- case WM_KEYUP:
- if (wParam >= 0 && wParam < 256)
- io.KeysDown[wParam] = 0;
- return true;
- case WM_CHAR:
- // You can also use ToAscii()+GetKeyboardState() to retrieve characters.
- if (wParam > 0 && wParam < 0x10000)
- io.AddInputCharacter((unsigned short)wParam);
- return true;
+ case WM_SIZE:
+ if (g_pd3dDevice != NULL && wParam != SIZE_MINIMIZED)
+ {
+ ImGui_ImplDX11_InvalidateDeviceObjects();
+ CleanupRenderTarget();
+ g_pSwapChain->ResizeBuffers(0, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam), DXGI_FORMAT_UNKNOWN, 0);
+ CreateRenderTarget();
+ ImGui_ImplDX11_CreateDeviceObjects();
+ }
+ return 0;
case WM_DESTROY:
- CleanupDevice();
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
-void LoadFontsTexture()
-{
- // Load one or more font
- ImGuiIO& io = ImGui::GetIO();
- //ImFont* my_font1 = io.Fonts->AddFontDefault();
- //ImFont* my_font2 = io.Fonts->AddFontFromFileTTF("extra_fonts/Karla-Regular.ttf", 15.0f);
- //ImFont* my_font3 = io.Fonts->AddFontFromFileTTF("extra_fonts/ProggyClean.ttf", 13.0f); my_font3->DisplayOffset.y += 1;
- //ImFont* my_font4 = io.Fonts->AddFontFromFileTTF("extra_fonts/ProggyTiny.ttf", 10.0f); my_font4->DisplayOffset.y += 1;
- //ImFont* my_font5 = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, io.Fonts->GetGlyphRangesJapanese());
-
- // Build
- unsigned char* pixels;
- int width, height;
- io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
-
- // Create texture
- D3D11_TEXTURE2D_DESC desc;
- ZeroMemory(&desc, sizeof(desc));
- desc.Width = width;
- desc.Height = height;
- desc.MipLevels = 1;
- desc.ArraySize = 1;
- desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
- desc.SampleDesc.Count = 1;
- desc.Usage = D3D11_USAGE_DEFAULT;
- desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
- desc.CPUAccessFlags = 0;
-
- ID3D11Texture2D *pTexture = NULL;
- D3D11_SUBRESOURCE_DATA subResource;
- subResource.pSysMem = pixels;
- subResource.SysMemPitch = desc.Width * 4;
- subResource.SysMemSlicePitch = 0;
- g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
-
- // Create texture view
- D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
- ZeroMemory(&srvDesc, sizeof(srvDesc));
- srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
- srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
- srvDesc.Texture2D.MipLevels = desc.MipLevels;
- srvDesc.Texture2D.MostDetailedMip = 0;
- ID3D11ShaderResourceView* font_texture_view = NULL;
- g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &font_texture_view);
- pTexture->Release();
-
- // Store our identifier
- io.Fonts->TexID = (void *)font_texture_view;
-}
-
-void InitImGui()
-{
- RECT rect;
- GetClientRect(hWnd, &rect);
- int display_w = (int)(rect.right - rect.left);
- int display_h = (int)(rect.bottom - rect.top);
-
- ImGuiIO& io = ImGui::GetIO();
- io.DisplaySize = ImVec2((float)display_w, (float)display_h); // Display size, in pixels. For clamping windows positions.
- io.DeltaTime = 1.0f/60.0f; // Time elapsed since last frame, in seconds (in this sample app we'll override this every frame because our time step is variable)
- io.KeyMap[ImGuiKey_Tab] = VK_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array that we will update during the application lifetime.
- io.KeyMap[ImGuiKey_LeftArrow] = VK_LEFT;
- io.KeyMap[ImGuiKey_RightArrow] = VK_RIGHT;
- io.KeyMap[ImGuiKey_UpArrow] = VK_UP;
- io.KeyMap[ImGuiKey_DownArrow] = VK_UP;
- io.KeyMap[ImGuiKey_Home] = VK_HOME;
- io.KeyMap[ImGuiKey_End] = VK_END;
- io.KeyMap[ImGuiKey_Delete] = VK_DELETE;
- io.KeyMap[ImGuiKey_Backspace] = VK_BACK;
- io.KeyMap[ImGuiKey_Enter] = VK_RETURN;
- io.KeyMap[ImGuiKey_Escape] = VK_ESCAPE;
- 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';
-
- io.RenderDrawListsFn = ImImpl_RenderDrawLists;
- io.ImeWindowHandle = hWnd;
-
- // Create the vertex buffer
- {
- D3D11_BUFFER_DESC bufferDesc;
- memset(&bufferDesc, 0, sizeof(D3D11_BUFFER_DESC));
- bufferDesc.Usage = D3D11_USAGE_DYNAMIC;
- bufferDesc.ByteWidth = 100000 * sizeof(CUSTOMVERTEX); // Maybe we should handle that more dynamically?
- bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
- bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
- bufferDesc.MiscFlags = 0;
- if (g_pd3dDevice->CreateBuffer(&bufferDesc, NULL, &g_pVB) < 0)
- {
- IM_ASSERT(0);
- return;
- }
- }
-
- // Load fonts
- LoadFontsTexture();
-
- // Create texture sampler
- {
- D3D11_SAMPLER_DESC desc;
- ZeroMemory(&desc, sizeof(desc));
- desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
- desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
- desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
- desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
- desc.MipLODBias = 0.f;
- desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
- desc.MinLOD = 0.f;
- desc.MaxLOD = 0.f;
- g_pd3dDevice->CreateSamplerState(&desc, &g_pFontSampler);
- }
-}
-
-INT64 ticks_per_second = 0;
-INT64 last_time = 0;
-
-void UpdateImGui()
-{
- ImGuiIO& io = ImGui::GetIO();
-
- // Setup time step
- INT64 current_time;
- QueryPerformanceCounter((LARGE_INTEGER *)¤t_time);
- io.DeltaTime = (float)(current_time - last_time) / ticks_per_second;
- last_time = current_time;
-
- // Read keyboard modifiers inputs
- io.KeyCtrl = (GetKeyState(VK_CONTROL) & 0x8000) != 0;
- io.KeyShift = (GetKeyState(VK_SHIFT) & 0x8000) != 0;
- // io.KeysDown : filled by WM_KEYDOWN/WM_KEYUP events
- // io.MousePos : filled by WM_MOUSEMOVE events
- // io.MouseDown : filled by WM_*BUTTON* events
- // io.MouseWheel : filled by WM_MOUSEWHEEL events
-
- // Start the frame
- ImGui::NewFrame();
-}
-
int main(int argc, char** argv)
{
- // Register the window class
+ // Create application window
WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(NULL), NULL, LoadCursor(NULL, IDC_ARROW), NULL, NULL, L"ImGui Example", NULL };
RegisterClassEx(&wc);
-
- // Create the application's window
- hWnd = CreateWindow(L"ImGui Example", L"ImGui DirectX11 Example", WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL);
-
- if (!QueryPerformanceFrequency((LARGE_INTEGER *)&ticks_per_second))
- return 1;
- if (!QueryPerformanceCounter((LARGE_INTEGER *)&last_time))
- return 1;
+ HWND hwnd = CreateWindow(L"ImGui Example", L"ImGui DirectX11 Example", WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL);
// Initialize Direct3D
- if (InitDeviceD3D(hWnd) < 0)
+ if (CreateDeviceD3D(hwnd) < 0)
{
- CleanupDevice();
+ CleanupDeviceD3D();
UnregisterClass(L"ImGui Example", wc.hInstance);
return 1;
}
// Show the window
- ShowWindow(hWnd, SW_SHOWDEFAULT);
- UpdateWindow(hWnd);
+ ShowWindow(hwnd, SW_SHOWDEFAULT);
+ UpdateWindow(hwnd);
- InitImGui();
+ // Setup ImGui binding
+ ImGui_ImplDX11_Init(hwnd, g_pd3dDevice, g_pd3dDeviceContext);
+ //ImGuiIO& io = ImGui::GetIO();
+ //ImFont* my_font1 = io.Fonts->AddFontDefault();
+ //ImFont* my_font2 = io.Fonts->AddFontFromFileTTF("extra_fonts/Karla-Regular.ttf", 15.0f);
+ //ImFont* my_font3 = io.Fonts->AddFontFromFileTTF("extra_fonts/ProggyClean.ttf", 13.0f); my_font3->DisplayOffset.y += 1;
+ //ImFont* my_font4 = io.Fonts->AddFontFromFileTTF("extra_fonts/ProggyTiny.ttf", 10.0f); my_font4->DisplayOffset.y += 1;
+ //ImFont* my_font5 = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, io.Fonts->GetGlyphRangesJapanese());
bool show_test_window = true;
bool show_another_window = false;
ImVec4 clear_col = ImColor(114, 144, 154);
- // Enter the message loop
+ // Main loop
MSG msg;
ZeroMemory(&msg, sizeof(msg));
while (msg.message != WM_QUIT)
@@ -563,7 +167,7 @@ int main(int argc, char** argv)
DispatchMessage(&msg);
continue;
}
- UpdateImGui();
+ ImGui_ImplDX11_NewFrame();
// 1. Show a simple window
// Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets appears in a window automatically called "Debug"
@@ -593,12 +197,13 @@ int main(int argc, char** argv)
}
// Rendering
- g_pd3dDeviceImmediateContext->ClearRenderTargetView(g_mainRenderTargetView, (float*)&clear_col);
+ g_pd3dDeviceContext->ClearRenderTargetView(g_mainRenderTargetView, (float*)&clear_col);
ImGui::Render();
g_pSwapChain->Present(0, 0);
}
- ImGui::Shutdown();
+ ImGui_ImplDX11_Shutdown();
+ CleanupDeviceD3D();
UnregisterClass(L"ImGui Example", wc.hInstance);
return 0;
diff --git a/examples/directx9_example/directx9_example.vcxproj b/examples/directx9_example/directx9_example.vcxproj
index 548f1d3d..3b638b7b 100644
--- a/examples/directx9_example/directx9_example.vcxproj
+++ b/examples/directx9_example/directx9_example.vcxproj
@@ -48,7 +48,7 @@
Level3
Disabled
- $(DXSDK_DIR)Include;%(AdditionalIncludeDirectories)
+ ..\..;$(DXSDK_DIR)Include;%(AdditionalIncludeDirectories)
true
@@ -63,7 +63,7 @@
MaxSpeed
true
true
- $(DXSDK_DIR)Include;%(AdditionalIncludeDirectories)
+ ..\..;$(DXSDK_DIR)Include;%(AdditionalIncludeDirectories)
true
@@ -76,11 +76,13 @@
+
+
diff --git a/examples/directx9_example/directx9_example.vcxproj.filters b/examples/directx9_example/directx9_example.vcxproj.filters
index 06afcb03..13e1f412 100644
--- a/examples/directx9_example/directx9_example.vcxproj.filters
+++ b/examples/directx9_example/directx9_example.vcxproj.filters
@@ -16,6 +16,9 @@
imgui
+
+ sources
+
@@ -24,5 +27,8 @@
imgui
+
+ sources
+
\ No newline at end of file
diff --git a/examples/directx9_example/imgui_impl_dx9.cpp b/examples/directx9_example/imgui_impl_dx9.cpp
new file mode 100644
index 00000000..e47ddea9
--- /dev/null
+++ b/examples/directx9_example/imgui_impl_dx9.cpp
@@ -0,0 +1,286 @@
+// ImGui Win32 + DirectX9 binding
+// https://github.com/ocornut/imgui
+
+#include
+#include "imgui_impl_dx9.h"
+
+// DirectX
+#include
+#define DIRECTINPUT_VERSION 0x0800
+#include
+
+// Data
+static HWND g_hWnd = 0;
+static INT64 g_Time = 0;
+static INT64 g_TicksPerSecond = 0;
+static LPDIRECT3DDEVICE9 g_pd3dDevice = NULL;
+static LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL;
+
+struct CUSTOMVERTEX
+{
+ D3DXVECTOR3 pos;
+ D3DCOLOR col;
+ D3DXVECTOR2 uv;
+};
+#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)
+
+// This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure)
+// If text or lines are blurry when integrating ImGui in your engine:
+// - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f)
+static void ImGui_ImplDX9_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count)
+{
+ size_t total_vtx_count = 0;
+ for (int n = 0; n < cmd_lists_count; n++)
+ total_vtx_count += cmd_lists[n]->vtx_buffer.size();
+ if (total_vtx_count == 0)
+ return;
+
+ // Copy and convert all vertices into a single contiguous buffer
+ CUSTOMVERTEX* vtx_dst;
+ if (g_pVB->Lock(0, (UINT)total_vtx_count, (void**)&vtx_dst, D3DLOCK_DISCARD) < 0)
+ return;
+ for (int n = 0; n < cmd_lists_count; n++)
+ {
+ const ImDrawList* cmd_list = cmd_lists[n];
+ const ImDrawVert* vtx_src = &cmd_list->vtx_buffer[0];
+ for (size_t i = 0; i < cmd_list->vtx_buffer.size(); i++)
+ {
+ vtx_dst->pos.x = vtx_src->pos.x;
+ vtx_dst->pos.y = vtx_src->pos.y;
+ vtx_dst->pos.z = 0.0f;
+ vtx_dst->col = (vtx_src->col & 0xFF00FF00) | ((vtx_src->col & 0xFF0000)>>16) | ((vtx_src->col & 0xFF) << 16); // RGBA --> ARGB for DirectX9
+ vtx_dst->uv.x = vtx_src->uv.x;
+ vtx_dst->uv.y = vtx_src->uv.y;
+ vtx_dst++;
+ vtx_src++;
+ }
+ }
+ g_pVB->Unlock();
+
+ g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof( CUSTOMVERTEX ) );
+ g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX );
+
+ // Setup render state: alpha-blending, no face culling, no depth testing
+ g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
+ g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, false );
+ g_pd3dDevice->SetRenderState( D3DRS_ZENABLE, false );
+ g_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, true );
+ g_pd3dDevice->SetRenderState( D3DRS_BLENDOP, D3DBLENDOP_ADD );
+ g_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, false );
+ g_pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
+ g_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
+ g_pd3dDevice->SetRenderState( D3DRS_SCISSORTESTENABLE, true );
+ g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1 );
+ g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_DIFFUSE );
+ g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
+ g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
+ g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
+ g_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
+ g_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
+
+ // Setup orthographic projection matrix
+ D3DXMATRIXA16 mat;
+ D3DXMatrixIdentity(&mat);
+ g_pd3dDevice->SetTransform(D3DTS_WORLD, &mat);
+ g_pd3dDevice->SetTransform(D3DTS_VIEW, &mat);
+ D3DXMatrixOrthoOffCenterLH(&mat, 0.5f, ImGui::GetIO().DisplaySize.x+0.5f, ImGui::GetIO().DisplaySize.y+0.5f, 0.5f, -1.0f, +1.0f);
+ g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &mat);
+
+ // Render command lists
+ int vtx_offset = 0;
+ for (int n = 0; n < cmd_lists_count; n++)
+ {
+ const ImDrawList* cmd_list = cmd_lists[n];
+ for (size_t cmd_i = 0; cmd_i < cmd_list->commands.size(); cmd_i++)
+ {
+ const ImDrawCmd* pcmd = &cmd_list->commands[cmd_i];
+ if (pcmd->user_callback)
+ {
+ pcmd->user_callback(cmd_list, pcmd);
+ }
+ else
+ {
+ const RECT r = { (LONG)pcmd->clip_rect.x, (LONG)pcmd->clip_rect.y, (LONG)pcmd->clip_rect.z, (LONG)pcmd->clip_rect.w };
+ g_pd3dDevice->SetTexture( 0, (LPDIRECT3DTEXTURE9)pcmd->texture_id );
+ g_pd3dDevice->SetScissorRect(&r);
+ g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, vtx_offset, pcmd->vtx_count/3);
+ }
+ vtx_offset += pcmd->vtx_count;
+ }
+ }
+}
+
+LRESULT ImGui_ImplDX9_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ ImGuiIO& io = ImGui::GetIO();
+ switch (msg)
+ {
+ case WM_LBUTTONDOWN:
+ io.MouseDown[0] = true;
+ return true;
+ case WM_LBUTTONUP:
+ io.MouseDown[0] = false;
+ return true;
+ case WM_RBUTTONDOWN:
+ io.MouseDown[1] = true;
+ return true;
+ case WM_RBUTTONUP:
+ io.MouseDown[1] = false;
+ return true;
+ case WM_MOUSEWHEEL:
+ io.MouseWheel += GET_WHEEL_DELTA_WPARAM(wParam) > 0 ? +1.0f : -1.0f;
+ return true;
+ case WM_MOUSEMOVE:
+ io.MousePos.x = (signed short)(lParam);
+ io.MousePos.y = (signed short)(lParam >> 16);
+ return true;
+ case WM_KEYDOWN:
+ if (wParam >= 0 && wParam < 256)
+ io.KeysDown[wParam] = 1;
+ return true;
+ case WM_KEYUP:
+ if (wParam >= 0 && wParam < 256)
+ io.KeysDown[wParam] = 0;
+ return true;
+ case WM_CHAR:
+ // You can also use ToAscii()+GetKeyboardState() to retrieve characters.
+ if (wParam > 0 && wParam < 0x10000)
+ io.AddInputCharacter((unsigned short)wParam);
+ return true;
+ }
+ return 0;
+}
+
+bool ImGui_ImplDX9_Init(void* hwnd, IDirect3DDevice9* device)
+{
+ g_hWnd = (HWND)hwnd;
+ g_pd3dDevice = device;
+
+ if (!QueryPerformanceFrequency((LARGE_INTEGER *)&g_TicksPerSecond))
+ return false;
+ if (!QueryPerformanceCounter((LARGE_INTEGER *)&g_Time))
+ return false;
+
+ ImGuiIO& io = ImGui::GetIO();
+ io.KeyMap[ImGuiKey_Tab] = VK_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array that we will update during the application lifetime.
+ io.KeyMap[ImGuiKey_LeftArrow] = VK_LEFT;
+ io.KeyMap[ImGuiKey_RightArrow] = VK_RIGHT;
+ io.KeyMap[ImGuiKey_UpArrow] = VK_UP;
+ io.KeyMap[ImGuiKey_DownArrow] = VK_UP;
+ io.KeyMap[ImGuiKey_Home] = VK_HOME;
+ io.KeyMap[ImGuiKey_End] = VK_END;
+ io.KeyMap[ImGuiKey_Delete] = VK_DELETE;
+ io.KeyMap[ImGuiKey_Backspace] = VK_BACK;
+ io.KeyMap[ImGuiKey_Enter] = VK_RETURN;
+ io.KeyMap[ImGuiKey_Escape] = VK_ESCAPE;
+ 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';
+
+ io.RenderDrawListsFn = ImGui_ImplDX9_RenderDrawLists;
+ io.ImeWindowHandle = g_hWnd;
+
+ if (g_pd3dDevice->CreateVertexBuffer(10000 * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB, NULL) < 0)
+ return false;
+
+ return true;
+}
+
+void ImGui_ImplDX9_Shutdown()
+{
+ ImGui_ImplDX9_InvalidateDeviceObjects();
+ ImGui::Shutdown();
+ g_pd3dDevice = NULL;
+ g_hWnd = 0;
+}
+
+static void ImGui_ImplDX9_CreateFontsTexture()
+{
+ ImGuiIO& io = ImGui::GetIO();
+
+ // Build
+ unsigned char* pixels;
+ int width, height, bytes_per_pixel;
+ io.Fonts->GetTexDataAsAlpha8(&pixels, &width, &height, &bytes_per_pixel);
+
+ // Create DX9 texture
+ LPDIRECT3DTEXTURE9 pTexture = NULL;
+ if (D3DXCreateTexture(g_pd3dDevice, width, height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8, D3DPOOL_DEFAULT, &pTexture) < 0)
+ {
+ IM_ASSERT(0);
+ return;
+ }
+ D3DLOCKED_RECT tex_locked_rect;
+ if (pTexture->LockRect(0, &tex_locked_rect, NULL, 0) != D3D_OK)
+ {
+ IM_ASSERT(0);
+ return;
+ }
+ for (int y = 0; y < height; y++)
+ memcpy((unsigned char *)tex_locked_rect.pBits + tex_locked_rect.Pitch * y, pixels + (width * bytes_per_pixel) * y, (width * bytes_per_pixel));
+ pTexture->UnlockRect(0);
+
+ // Store our identifier
+ io.Fonts->TexID = (void *)pTexture;
+}
+
+bool ImGui_ImplDX9_CreateDeviceObjects()
+{
+ if (!g_pd3dDevice)
+ return false;
+
+ if (g_pd3dDevice->CreateVertexBuffer(10000 * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB, NULL) < 0)
+ return false;
+
+ ImGui_ImplDX9_CreateFontsTexture();
+ return true;
+}
+
+void ImGui_ImplDX9_InvalidateDeviceObjects()
+{
+ if (!g_pd3dDevice)
+ return;
+ if (g_pVB)
+ {
+ g_pVB->Release();
+ g_pVB = NULL;
+ }
+ if (LPDIRECT3DTEXTURE9 tex = (LPDIRECT3DTEXTURE9)ImGui::GetIO().Fonts->TexID)
+ {
+ tex->Release();
+ ImGui::GetIO().Fonts->TexID = 0;
+ }
+}
+
+void ImGui_ImplDX9_NewFrame()
+{
+ if (!g_pVB)
+ ImGui_ImplDX9_CreateDeviceObjects();
+
+ ImGuiIO& io = ImGui::GetIO();
+
+ // Setup display size (every frame to accommodate for window resizing)
+ RECT rect;
+ GetClientRect(g_hWnd, &rect);
+ io.DisplaySize = ImVec2((float)(rect.right - rect.left), (float)(rect.bottom - rect.top));
+
+ // Setup time step
+ INT64 current_time;
+ QueryPerformanceCounter((LARGE_INTEGER *)¤t_time);
+ io.DeltaTime = (float)(current_time - g_Time) / g_TicksPerSecond;
+ g_Time = current_time;
+
+ // Read keyboard modifiers inputs
+ io.KeyCtrl = (GetKeyState(VK_CONTROL) & 0x8000) != 0;
+ io.KeyShift = (GetKeyState(VK_SHIFT) & 0x8000) != 0;
+ // io.KeysDown : filled by WM_KEYDOWN/WM_KEYUP events
+ // io.MousePos : filled by WM_MOUSEMOVE events
+ // io.MouseDown : filled by WM_*BUTTON* events
+ // io.MouseWheel : filled by WM_MOUSEWHEEL events
+
+ // Start the frame
+ ImGui::NewFrame();
+}
diff --git a/examples/directx9_example/imgui_impl_dx9.h b/examples/directx9_example/imgui_impl_dx9.h
new file mode 100644
index 00000000..0f53b3d5
--- /dev/null
+++ b/examples/directx9_example/imgui_impl_dx9.h
@@ -0,0 +1,19 @@
+// ImGui Win32 + DirectX9 binding
+// https://github.com/ocornut/imgui
+
+struct IDirect3DDevice9;
+
+bool ImGui_ImplDX9_Init(void* hwnd, IDirect3DDevice9* device);
+void ImGui_ImplDX9_Shutdown();
+void ImGui_ImplDX9_NewFrame();
+
+// Use if you want to reset your rendering device without losing ImGui state.
+void ImGui_ImplDX9_InvalidateDeviceObjects();
+bool ImGui_ImplDX9_CreateDeviceObjects();
+
+// Handler for Win32 messages, update mouse/keyboard data.
+// You may or not need this for your implementation, but it can serve as reference for handling inputs.
+// Commented out to avoid dragging dependencies on types. You can copy the extern declaration in your code.
+/*
+extern LRESULT ImGui_ImplDX9_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+*/
diff --git a/examples/directx9_example/main.cpp b/examples/directx9_example/main.cpp
index 4b73328c..75892ffb 100644
--- a/examples/directx9_example/main.cpp
+++ b/examples/directx9_example/main.cpp
@@ -1,323 +1,89 @@
// ImGui - standalone example application for DirectX 9
-#include
-#include "../../imgui.h"
-
-// DirectX 9
+#include
+#include "imgui_impl_dx9.h"
#include
#define DIRECTINPUT_VERSION 0x0800
#include
-#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strdup
-
-static HWND hWnd;
-static LPDIRECT3D9 g_pD3D = NULL; // Used to create the D3DDevice
-static LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; // Our rendering device
-static LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL; // Buffer to hold vertices
-struct CUSTOMVERTEX
-{
- D3DXVECTOR3 pos;
- D3DCOLOR col;
- D3DXVECTOR2 uv;
-};
-#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)
+// Data
+static LPDIRECT3DDEVICE9 g_pd3dDevice = NULL;
+static D3DPRESENT_PARAMETERS g_d3dpp;
-// This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure)
-// If text or lines are blurry when integrating ImGui in your engine:
-// - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f)
-static void ImImpl_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count)
+extern LRESULT ImGui_ImplDX9_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
- size_t total_vtx_count = 0;
- for (int n = 0; n < cmd_lists_count; n++)
- total_vtx_count += cmd_lists[n]->vtx_buffer.size();
- if (total_vtx_count == 0)
- return;
-
- // Copy and convert all vertices into a single contiguous buffer
- CUSTOMVERTEX* vtx_dst;
- if (g_pVB->Lock(0, (UINT)total_vtx_count, (void**)&vtx_dst, D3DLOCK_DISCARD) < 0)
- return;
- for (int n = 0; n < cmd_lists_count; n++)
- {
- const ImDrawList* cmd_list = cmd_lists[n];
- const ImDrawVert* vtx_src = &cmd_list->vtx_buffer[0];
- for (size_t i = 0; i < cmd_list->vtx_buffer.size(); i++)
- {
- vtx_dst->pos.x = vtx_src->pos.x;
- vtx_dst->pos.y = vtx_src->pos.y;
- vtx_dst->pos.z = 0.0f;
- vtx_dst->col = (vtx_src->col & 0xFF00FF00) | ((vtx_src->col & 0xFF0000)>>16) | ((vtx_src->col & 0xFF) << 16); // RGBA --> ARGB for DirectX9
- vtx_dst->uv.x = vtx_src->uv.x;
- vtx_dst->uv.y = vtx_src->uv.y;
- vtx_dst++;
- vtx_src++;
- }
- }
- g_pVB->Unlock();
-
- g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof( CUSTOMVERTEX ) );
- g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX );
-
- // Setup render state: alpha-blending, no face culling, no depth testing
- g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
- g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, false );
- g_pd3dDevice->SetRenderState( D3DRS_ZENABLE, false );
- g_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, true );
- g_pd3dDevice->SetRenderState( D3DRS_BLENDOP, D3DBLENDOP_ADD );
- g_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, false );
- g_pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
- g_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
- g_pd3dDevice->SetRenderState( D3DRS_SCISSORTESTENABLE, true );
- g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1 );
- g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_DIFFUSE );
- g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
- g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
- g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
- g_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
- g_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
-
- // Setup orthographic projection matrix
- D3DXMATRIXA16 mat;
- D3DXMatrixIdentity(&mat);
- g_pd3dDevice->SetTransform(D3DTS_WORLD, &mat);
- g_pd3dDevice->SetTransform(D3DTS_VIEW, &mat);
- D3DXMatrixOrthoOffCenterLH(&mat, 0.5f, ImGui::GetIO().DisplaySize.x+0.5f, ImGui::GetIO().DisplaySize.y+0.5f, 0.5f, -1.0f, +1.0f);
- g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &mat);
+ if (ImGui_ImplDX9_WndProcHandler(hWnd, msg, wParam, lParam))
+ return true;
- // Render command lists
- int vtx_offset = 0;
- for (int n = 0; n < cmd_lists_count; n++)
+ switch (msg)
{
- // Render command list
- const ImDrawList* cmd_list = cmd_lists[n];
- for (size_t cmd_i = 0; cmd_i < cmd_list->commands.size(); cmd_i++)
+ case WM_SIZE:
+ if (g_pd3dDevice != NULL && wParam != SIZE_MINIMIZED)
{
- const ImDrawCmd* pcmd = &cmd_list->commands[cmd_i];
- const RECT r = { (LONG)pcmd->clip_rect.x, (LONG)pcmd->clip_rect.y, (LONG)pcmd->clip_rect.z, (LONG)pcmd->clip_rect.w };
- g_pd3dDevice->SetTexture( 0, (LPDIRECT3DTEXTURE9)pcmd->texture_id );
- g_pd3dDevice->SetScissorRect(&r);
- g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, vtx_offset, pcmd->vtx_count/3);
- vtx_offset += pcmd->vtx_count;
+ ImGui_ImplDX9_InvalidateDeviceObjects();
+ g_d3dpp.BackBufferWidth = LOWORD(lParam);
+ g_d3dpp.BackBufferHeight = HIWORD(lParam);
+ HRESULT hr = g_pd3dDevice->Reset(&g_d3dpp);
+ if (hr == D3DERR_INVALIDCALL)
+ IM_ASSERT(0);
+ ImGui_ImplDX9_CreateDeviceObjects();
}
- }
-}
-
-HRESULT InitDeviceD3D(HWND hWnd)
-{
- if (NULL == (g_pD3D = Direct3DCreate9(D3D_SDK_VERSION)))
- return E_FAIL;
-
- D3DPRESENT_PARAMETERS d3dpp;
- ZeroMemory(&d3dpp, sizeof(d3dpp));
- d3dpp.Windowed = TRUE;
- d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
- d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
- d3dpp.EnableAutoDepthStencil = TRUE;
- d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
- d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
-
- // Create the D3DDevice
- if (g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &g_pd3dDevice) < 0)
- return E_FAIL;
-
- return S_OK;
-}
-
-void CleanupDevice()
-{
- // InitImGui
- if (g_pVB) g_pVB->Release();
-
- // InitDeviceD3D
- if (LPDIRECT3DTEXTURE9 tex = (LPDIRECT3DTEXTURE9)ImGui::GetIO().Fonts->TexID)
- tex->Release();
- if (g_pd3dDevice) g_pd3dDevice->Release();
- if (g_pD3D) g_pD3D->Release();
-}
-
-LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- ImGuiIO& io = ImGui::GetIO();
- switch (msg)
- {
- case WM_LBUTTONDOWN:
- io.MouseDown[0] = true;
- return true;
- case WM_LBUTTONUP:
- io.MouseDown[0] = false;
- return true;
- case WM_RBUTTONDOWN:
- io.MouseDown[1] = true;
- return true;
- case WM_RBUTTONUP:
- io.MouseDown[1] = false;
- return true;
- case WM_MOUSEWHEEL:
- io.MouseWheel += GET_WHEEL_DELTA_WPARAM(wParam) > 0 ? +1.0f : -1.0f;
- return true;
- case WM_MOUSEMOVE:
- // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.)
- io.MousePos.x = (signed short)(lParam);
- io.MousePos.y = (signed short)(lParam >> 16);
- return true;
- case WM_KEYDOWN:
- if (wParam >= 0 && wParam < 256)
- io.KeysDown[wParam] = 1;
- return true;
- case WM_KEYUP:
- if (wParam >= 0 && wParam < 256)
- io.KeysDown[wParam] = 0;
- return true;
- case WM_CHAR:
- // You can also use ToAscii()+GetKeyboardState() to retrieve characters.
- if (wParam > 0 && wParam < 0x10000)
- io.AddInputCharacter((unsigned short)wParam);
- return true;
+ return 0;
case WM_DESTROY:
- CleanupDevice();
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
-void LoadFontsTexture()
-{
- // Load one or more font
- ImGuiIO& io = ImGui::GetIO();
- //ImFont* my_font1 = io.Fonts->AddFontDefault();
- //ImFont* my_font2 = io.Fonts->AddFontFromFileTTF("extra_fonts/Karla-Regular.ttf", 15.0f);
- //ImFont* my_font3 = io.Fonts->AddFontFromFileTTF("extra_fonts/ProggyClean.ttf", 13.0f); my_font3->DisplayOffset.y += 1;
- //ImFont* my_font4 = io.Fonts->AddFontFromFileTTF("extra_fonts/ProggyTiny.ttf", 10.0f); my_font4->DisplayOffset.y += 1;
- //ImFont* my_font5 = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, io.Fonts->GetGlyphRangesJapanese());
-
- // Build
- unsigned char* pixels;
- int width, height, bytes_per_pixel;
- io.Fonts->GetTexDataAsAlpha8(&pixels, &width, &height, &bytes_per_pixel);
-
- // Create texture
- LPDIRECT3DTEXTURE9 pTexture = NULL;
- if (D3DXCreateTexture(g_pd3dDevice, width, height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8, D3DPOOL_DEFAULT, &pTexture) < 0)
- {
- IM_ASSERT(0);
- return;
- }
-
- // Copy pixels
- D3DLOCKED_RECT tex_locked_rect;
- if (pTexture->LockRect(0, &tex_locked_rect, NULL, 0) != D3D_OK)
- {
- IM_ASSERT(0);
- return;
- }
- for (int y = 0; y < height; y++)
- memcpy((unsigned char *)tex_locked_rect.pBits + tex_locked_rect.Pitch * y, pixels + (width * bytes_per_pixel) * y, (width * bytes_per_pixel));
- pTexture->UnlockRect(0);
-
- // Store our identifier
- io.Fonts->TexID = (void *)pTexture;
-}
-
-void InitImGui()
-{
- RECT rect;
- GetClientRect(hWnd, &rect);
- int display_w = (int)(rect.right - rect.left);
- int display_h = (int)(rect.bottom - rect.top);
-
- ImGuiIO& io = ImGui::GetIO();
- io.DisplaySize = ImVec2((float)display_w, (float)display_h); // Display size, in pixels. For clamping windows positions.
- io.DeltaTime = 1.0f/60.0f; // Time elapsed since last frame, in seconds (in this sample app we'll override this every frame because our time step is variable)
- io.KeyMap[ImGuiKey_Tab] = VK_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array that we will update during the application lifetime.
- io.KeyMap[ImGuiKey_LeftArrow] = VK_LEFT;
- io.KeyMap[ImGuiKey_RightArrow] = VK_RIGHT;
- io.KeyMap[ImGuiKey_UpArrow] = VK_UP;
- io.KeyMap[ImGuiKey_DownArrow] = VK_UP;
- io.KeyMap[ImGuiKey_Home] = VK_HOME;
- io.KeyMap[ImGuiKey_End] = VK_END;
- io.KeyMap[ImGuiKey_Delete] = VK_DELETE;
- io.KeyMap[ImGuiKey_Backspace] = VK_BACK;
- io.KeyMap[ImGuiKey_Enter] = VK_RETURN;
- io.KeyMap[ImGuiKey_Escape] = VK_ESCAPE;
- 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';
-
- io.RenderDrawListsFn = ImImpl_RenderDrawLists;
- io.ImeWindowHandle = hWnd;
-
- // Create the vertex buffer
- if (g_pd3dDevice->CreateVertexBuffer(10000 * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB, NULL) < 0)
- {
- IM_ASSERT(0);
- return;
- }
-
- LoadFontsTexture();
-}
-
-INT64 ticks_per_second = 0;
-INT64 last_time = 0;
-
-void UpdateImGui()
-{
- ImGuiIO& io = ImGui::GetIO();
-
- // Setup time step
- INT64 current_time;
- QueryPerformanceCounter((LARGE_INTEGER *)¤t_time);
- io.DeltaTime = (float)(current_time - last_time) / ticks_per_second;
- last_time = current_time;
-
- // Read keyboard modifiers inputs
- io.KeyCtrl = (GetKeyState(VK_CONTROL) & 0x8000) != 0;
- io.KeyShift = (GetKeyState(VK_SHIFT) & 0x8000) != 0;
- // io.KeysDown : filled by WM_KEYDOWN/WM_KEYUP events
- // io.MousePos : filled by WM_MOUSEMOVE events
- // io.MouseDown : filled by WM_*BUTTON* events
- // io.MouseWheel : filled by WM_MOUSEWHEEL events
-
- // Start the frame
- ImGui::NewFrame();
-}
-
int main(int argc, char** argv)
{
- // Register the window class
+ // Create application window
WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(NULL), NULL, LoadCursor(NULL, IDC_ARROW), NULL, NULL, L"ImGui Example", NULL };
RegisterClassEx(&wc);
-
- // Create the application's window
- hWnd = CreateWindow(L"ImGui Example", L"ImGui DirectX9 Example", WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL);
-
- if (!QueryPerformanceFrequency((LARGE_INTEGER *)&ticks_per_second))
- return 1;
- if (!QueryPerformanceCounter((LARGE_INTEGER *)&last_time))
- return 1;
+ HWND hwnd = CreateWindow(L"ImGui Example", L"ImGui DirectX9 Example", WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL);
// Initialize Direct3D
- if (InitDeviceD3D(hWnd) < 0)
+ LPDIRECT3D9 pD3D;
+ if ((pD3D = Direct3DCreate9(D3D_SDK_VERSION)) == NULL)
+ {
+ UnregisterClass(L"ImGui Example", wc.hInstance);
+ return 0;
+ }
+ ZeroMemory(&g_d3dpp, sizeof(g_d3dpp));
+ g_d3dpp.Windowed = TRUE;
+ g_d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
+ g_d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
+ g_d3dpp.EnableAutoDepthStencil = TRUE;
+ g_d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
+ g_d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
+
+ // Create the D3DDevice
+ if (pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &g_d3dpp, &g_pd3dDevice) < 0)
{
- CleanupDevice();
+ pD3D->Release();
UnregisterClass(L"ImGui Example", wc.hInstance);
- return 1;
+ return 0;
}
- // Show the window
- ShowWindow(hWnd, SW_SHOWDEFAULT);
- UpdateWindow(hWnd);
+ // Setup ImGui binding
+ ImGui_ImplDX9_Init(hwnd, g_pd3dDevice);
+ //ImGuiIO& io = ImGui::GetIO();
+ //ImFont* my_font1 = io.Fonts->AddFontDefault();
+ //ImFont* my_font2 = io.Fonts->AddFontFromFileTTF("extra_fonts/Karla-Regular.ttf", 15.0f);
+ //ImFont* my_font3 = io.Fonts->AddFontFromFileTTF("extra_fonts/ProggyClean.ttf", 13.0f); my_font3->DisplayOffset.y += 1;
+ //ImFont* my_font4 = io.Fonts->AddFontFromFileTTF("extra_fonts/ProggyTiny.ttf", 10.0f); my_font4->DisplayOffset.y += 1;
+ //ImFont* my_font5 = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, io.Fonts->GetGlyphRangesJapanese());
- InitImGui();
+ ShowWindow(hwnd, SW_SHOWDEFAULT);
+ UpdateWindow(hwnd);
bool show_test_window = true;
bool show_another_window = false;
ImVec4 clear_col = ImColor(114, 144, 154);
- // Enter the message loop
+ // Main loop
MSG msg;
ZeroMemory(&msg, sizeof(msg));
while (msg.message != WM_QUIT)
@@ -328,7 +94,7 @@ int main(int argc, char** argv)
DispatchMessage(&msg);
continue;
}
- UpdateImGui();
+ ImGui_ImplDX9_NewFrame();
// 1. Show a simple window
// Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets appears in a window automatically called "Debug"
@@ -371,8 +137,10 @@ int main(int argc, char** argv)
g_pd3dDevice->Present(NULL, NULL, NULL, NULL);
}
- ImGui::Shutdown();
-
+ ImGui_ImplDX9_Shutdown();
+ if (g_pd3dDevice) g_pd3dDevice->Release();
+ if (pD3D) pD3D->Release();
UnregisterClass(L"ImGui Example", wc.hInstance);
+
return 0;
}
diff --git a/examples/opengl3_example/Makefile b/examples/opengl3_example/Makefile
index bb0a1946..208d279f 100644
--- a/examples/opengl3_example/Makefile
+++ b/examples/opengl3_example/Makefile
@@ -1,6 +1,5 @@
#
-# Cross Platform Make file
-#
+# Cross Platform Makefile
# Compatible with Ubuntu 14.04.1 and Mac OS X
#
#
@@ -11,9 +10,8 @@
#CXX = g++
-OBJS = main.o
+OBJS = main.o imgui_impl_glfw_gl3.o gl3w/GL/gl3w.o
OBJS += ../../imgui.o
-OBJS += ../opengl_example/gl3w/GL/gl3w.o
UNAME_S := $(shell uname -s)
@@ -22,7 +20,7 @@ ifeq ($(UNAME_S), Linux) #LINUX
ECHO_MESSAGE = "Linux"
LIBS = `pkg-config --static --libs glfw3`
- CXXFLAGS = -I../../ -I../opengl_example/gl3w `pkg-config --cflags glfw3`
+ CXXFLAGS = -I../../ -Igl3w `pkg-config --cflags glfw3`
CXXFLAGS += -Wall
CFLAGS = $(CXXFLAGS)
endif
@@ -33,7 +31,7 @@ ifeq ($(UNAME_S), Darwin) #APPLE
LIBS += -L/usr/local/lib
LIBS += -lglfw3
- CXXFLAGS = -I../../ -I../opengl_example/gl3w -I/usr/local/Cellar/glew/1.10.0/include -I/usr/local/include
+ CXXFLAGS = -I../../ -Igl3w -I/usr/local/Cellar/glew/1.10.0/include -I/usr/local/include
CXXFLAGS += -Wall
# CXXFLAGS += -D__APPLE__
CFLAGS = $(CXXFLAGS)
diff --git a/examples/opengl_example/gl3w/GL/gl3w.c b/examples/opengl3_example/gl3w/GL/gl3w.c
similarity index 100%
rename from examples/opengl_example/gl3w/GL/gl3w.c
rename to examples/opengl3_example/gl3w/GL/gl3w.c
diff --git a/examples/opengl_example/gl3w/GL/gl3w.h b/examples/opengl3_example/gl3w/GL/gl3w.h
similarity index 100%
rename from examples/opengl_example/gl3w/GL/gl3w.h
rename to examples/opengl3_example/gl3w/GL/gl3w.h
diff --git a/examples/opengl_example/gl3w/GL/glcorearb.h b/examples/opengl3_example/gl3w/GL/glcorearb.h
similarity index 100%
rename from examples/opengl_example/gl3w/GL/glcorearb.h
rename to examples/opengl3_example/gl3w/GL/glcorearb.h
diff --git a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp
new file mode 100644
index 00000000..adc2d673
--- /dev/null
+++ b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp
@@ -0,0 +1,348 @@
+// ImGui GLFW binding with OpenGL3 + shaders
+// https://github.com/ocornut/imgui
+
+#include
+#include "imgui_impl_glfw_gl3.h"
+
+// GL3W/GLFW
+#include
+#include
+#ifdef _MSC_VER
+#undef APIENTRY
+#define GLFW_EXPOSE_NATIVE_WIN32
+#define GLFW_EXPOSE_NATIVE_WGL
+#include
+#endif
+
+// Data
+static GLFWwindow* g_Window = NULL;
+static double g_Time = 0.0f;
+static bool g_MousePressed[3] = { false, false, false };
+static float g_MouseWheel = 0.0f;
+static GLuint g_FontTexture = 0;
+static int g_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0;
+static int g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0;
+static int g_AttribLocationPosition = 0, g_AttribLocationUV = 0, g_AttribLocationColor = 0;
+static size_t g_VboMaxSize = 20000;
+static unsigned int g_VboHandle = 0, g_VaoHandle = 0;
+
+// This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure)
+// If text or lines are blurry when integrating ImGui in your engine:
+// - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f)
+static void ImGui_ImplGlfwGL3_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count)
+{
+ if (cmd_lists_count == 0)
+ return;
+
+ // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled
+ glEnable(GL_BLEND);
+ glBlendEquation(GL_FUNC_ADD);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_SCISSOR_TEST);
+ glActiveTexture(GL_TEXTURE0);
+
+ // Setup orthographic projection matrix
+ const float width = ImGui::GetIO().DisplaySize.x;
+ const float height = ImGui::GetIO().DisplaySize.y;
+ const float ortho_projection[4][4] =
+ {
+ { 2.0f/width, 0.0f, 0.0f, 0.0f },
+ { 0.0f, 2.0f/-height, 0.0f, 0.0f },
+ { 0.0f, 0.0f, -1.0f, 0.0f },
+ { -1.0f, 1.0f, 0.0f, 1.0f },
+ };
+ glUseProgram(g_ShaderHandle);
+ glUniform1i(g_AttribLocationTex, 0);
+ glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
+
+ // Grow our buffer according to what we need
+ size_t total_vtx_count = 0;
+ for (int n = 0; n < cmd_lists_count; n++)
+ total_vtx_count += cmd_lists[n]->vtx_buffer.size();
+ glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle);
+ size_t neededBufferSize = total_vtx_count * sizeof(ImDrawVert);
+ if (neededBufferSize > g_VboMaxSize)
+ {
+ g_VboMaxSize = neededBufferSize + 5000; // Grow buffer
+ glBufferData(GL_ARRAY_BUFFER, g_VboMaxSize, NULL, GL_STREAM_DRAW);
+ }
+
+ // Copy and convert all vertices into a single contiguous buffer
+ unsigned char* buffer_data = (unsigned char*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
+ if (!buffer_data)
+ return;
+ for (int n = 0; n < cmd_lists_count; n++)
+ {
+ const ImDrawList* cmd_list = cmd_lists[n];
+ memcpy(buffer_data, &cmd_list->vtx_buffer[0], cmd_list->vtx_buffer.size() * sizeof(ImDrawVert));
+ buffer_data += cmd_list->vtx_buffer.size() * sizeof(ImDrawVert);
+ }
+ glUnmapBuffer(GL_ARRAY_BUFFER);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindVertexArray(g_VaoHandle);
+
+ int cmd_offset = 0;
+ for (int n = 0; n < cmd_lists_count; n++)
+ {
+ const ImDrawList* cmd_list = cmd_lists[n];
+ int vtx_offset = cmd_offset;
+ const ImDrawCmd* pcmd_end = cmd_list->commands.end();
+ for (const ImDrawCmd* pcmd = cmd_list->commands.begin(); pcmd != pcmd_end; pcmd++)
+ {
+ if (pcmd->user_callback)
+ {
+ pcmd->user_callback(cmd_list, pcmd);
+ }
+ else
+ {
+ glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->texture_id);
+ glScissor((int)pcmd->clip_rect.x, (int)(height - pcmd->clip_rect.w), (int)(pcmd->clip_rect.z - pcmd->clip_rect.x), (int)(pcmd->clip_rect.w - pcmd->clip_rect.y));
+ glDrawArrays(GL_TRIANGLES, vtx_offset, pcmd->vtx_count);
+ }
+ vtx_offset += pcmd->vtx_count;
+ }
+ cmd_offset = vtx_offset;
+ }
+
+ // Restore modified state
+ glBindVertexArray(0);
+ glUseProgram(0);
+ glDisable(GL_SCISSOR_TEST);
+ glBindTexture(GL_TEXTURE_2D, 0);
+}
+
+static const char* ImGui_ImplGlfwGL3_GetClipboardText()
+{
+ return glfwGetClipboardString(g_Window);
+}
+
+static void ImGui_ImplGlfwGL3_SetClipboardText(const char* text)
+{
+ glfwSetClipboardString(g_Window, text);
+}
+
+void ImGui_ImplGlfwGL3_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
+{
+ if (action == GLFW_PRESS && button >= 0 && button < 3)
+ g_MousePressed[button] = true;
+}
+
+void ImGui_ImplGlfwGL3_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset)
+{
+ g_MouseWheel += (float)yoffset; // Use fractional mouse wheel, 1.0 unit 5 lines.
+}
+
+void ImGui_ImplGlfwGL3_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
+{
+ ImGuiIO& io = ImGui::GetIO();
+ if (action == GLFW_PRESS)
+ io.KeysDown[key] = true;
+ if (action == GLFW_RELEASE)
+ io.KeysDown[key] = false;
+ io.KeyCtrl = (mods & GLFW_MOD_CONTROL) != 0;
+ io.KeyShift = (mods & GLFW_MOD_SHIFT) != 0;
+}
+
+void ImGui_ImplGlfwGL3_CharCallback(GLFWwindow* window, unsigned int c)
+{
+ ImGuiIO& io = ImGui::GetIO();
+ if (c > 0 && c < 0x10000)
+ io.AddInputCharacter((unsigned short)c);
+}
+
+void ImGui_ImplGlfwGL3_CreateFontsTexture()
+{
+ ImGuiIO& io = ImGui::GetIO();
+
+ unsigned char* pixels;
+ int width, height;
+ io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bits for OpenGL3 demo because it is more likely to be compatible with user's existing shader.
+
+ glGenTextures(1, &g_FontTexture);
+ glBindTexture(GL_TEXTURE_2D, g_FontTexture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+
+ // Store our identifier
+ io.Fonts->TexID = (void *)(intptr_t)g_FontTexture;
+}
+
+bool ImGui_ImplGlfwGL3_CreateDeviceObjects()
+{
+ const GLchar *vertex_shader =
+ "#version 330\n"
+ "uniform mat4 ProjMtx;\n"
+ "in vec2 Position;\n"
+ "in vec2 UV;\n"
+ "in vec4 Color;\n"
+ "out vec2 Frag_UV;\n"
+ "out vec4 Frag_Color;\n"
+ "void main()\n"
+ "{\n"
+ " Frag_UV = UV;\n"
+ " Frag_Color = Color;\n"
+ " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
+ "}\n";
+
+ const GLchar* fragment_shader =
+ "#version 330\n"
+ "uniform sampler2D Texture;\n"
+ "in vec2 Frag_UV;\n"
+ "in vec4 Frag_Color;\n"
+ "out vec4 Out_Color;\n"
+ "void main()\n"
+ "{\n"
+ " Out_Color = Frag_Color * texture( Texture, Frag_UV.st);\n"
+ "}\n";
+
+ g_ShaderHandle = glCreateProgram();
+ g_VertHandle = glCreateShader(GL_VERTEX_SHADER);
+ g_FragHandle = glCreateShader(GL_FRAGMENT_SHADER);
+ glShaderSource(g_VertHandle, 1, &vertex_shader, 0);
+ glShaderSource(g_FragHandle, 1, &fragment_shader, 0);
+ glCompileShader(g_VertHandle);
+ glCompileShader(g_FragHandle);
+ glAttachShader(g_ShaderHandle, g_VertHandle);
+ glAttachShader(g_ShaderHandle, g_FragHandle);
+ glLinkProgram(g_ShaderHandle);
+
+ g_AttribLocationTex = glGetUniformLocation(g_ShaderHandle, "Texture");
+ g_AttribLocationProjMtx = glGetUniformLocation(g_ShaderHandle, "ProjMtx");
+ g_AttribLocationPosition = glGetAttribLocation(g_ShaderHandle, "Position");
+ g_AttribLocationUV = glGetAttribLocation(g_ShaderHandle, "UV");
+ g_AttribLocationColor = glGetAttribLocation(g_ShaderHandle, "Color");
+
+ glGenBuffers(1, &g_VboHandle);
+ glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle);
+ glBufferData(GL_ARRAY_BUFFER, g_VboMaxSize, NULL, GL_DYNAMIC_DRAW);
+
+ glGenVertexArrays(1, &g_VaoHandle);
+ glBindVertexArray(g_VaoHandle);
+ glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle);
+ glEnableVertexAttribArray(g_AttribLocationPosition);
+ glEnableVertexAttribArray(g_AttribLocationUV);
+ glEnableVertexAttribArray(g_AttribLocationColor);
+
+#define OFFSETOF(TYPE, ELEMENT) ((size_t)&(((TYPE *)0)->ELEMENT))
+ glVertexAttribPointer(g_AttribLocationPosition, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, pos));
+ glVertexAttribPointer(g_AttribLocationUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, uv));
+ glVertexAttribPointer(g_AttribLocationColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, col));
+#undef OFFSETOF
+ glBindVertexArray(0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ ImGui_ImplGlfwGL3_CreateFontsTexture();
+
+ return true;
+}
+
+bool ImGui_ImplGlfwGL3_Init(GLFWwindow* window, bool install_callbacks)
+{
+ g_Window = window;
+
+ ImGuiIO& io = ImGui::GetIO();
+ io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array.
+ 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_Home] = GLFW_KEY_HOME;
+ io.KeyMap[ImGuiKey_End] = GLFW_KEY_END;
+ io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE;
+ io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE;
+ io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER;
+ io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE;
+ io.KeyMap[ImGuiKey_A] = GLFW_KEY_A;
+ io.KeyMap[ImGuiKey_C] = GLFW_KEY_C;
+ io.KeyMap[ImGuiKey_V] = GLFW_KEY_V;
+ io.KeyMap[ImGuiKey_X] = GLFW_KEY_X;
+ io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y;
+ io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z;
+
+ io.RenderDrawListsFn = ImGui_ImplGlfwGL3_RenderDrawLists;
+ io.SetClipboardTextFn = ImGui_ImplGlfwGL3_SetClipboardText;
+ io.GetClipboardTextFn = ImGui_ImplGlfwGL3_GetClipboardText;
+#ifdef _MSC_VER
+ io.ImeWindowHandle = glfwGetWin32Window(g_Window);
+#endif
+
+ if (install_callbacks)
+ {
+ glfwSetMouseButtonCallback(window, ImGui_ImplGlfwGL3_MouseButtonCallback);
+ glfwSetScrollCallback(window, ImGui_ImplGlfwGL3_ScrollCallback);
+ glfwSetKeyCallback(window, ImGui_ImplGlfwGL3_KeyCallback);
+ glfwSetCharCallback(window, ImGui_ImplGlfwGL3_CharCallback);
+ }
+
+ return true;
+}
+
+void ImGui_ImplGlfwGL3_Shutdown()
+{
+ if (g_VaoHandle) glDeleteVertexArrays(1, &g_VaoHandle);
+ if (g_VboHandle) glDeleteBuffers(1, &g_VboHandle);
+ g_VaoHandle = 0;
+ g_VboHandle = 0;
+
+ glDetachShader(g_ShaderHandle, g_VertHandle);
+ glDeleteShader(g_VertHandle);
+ g_VertHandle = 0;
+
+ glDetachShader(g_ShaderHandle, g_FragHandle);
+ glDeleteShader(g_FragHandle);
+ g_FragHandle = 0;
+
+ glDeleteProgram(g_ShaderHandle);
+ g_ShaderHandle = 0;
+
+ if (g_FontTexture)
+ {
+ glDeleteTextures(1, &g_FontTexture);
+ ImGui::GetIO().Fonts->TexID = 0;
+ g_FontTexture = 0;
+ }
+ ImGui::Shutdown();
+}
+
+void ImGui_ImplGlfwGL3_NewFrame()
+{
+ if (!g_FontTexture)
+ ImGui_ImplGlfwGL3_CreateDeviceObjects();
+
+ ImGuiIO& io = ImGui::GetIO();
+
+ // Setup display size (every frame to accommodate for window resizing)
+ int w, h;
+ int display_w, display_h;
+ glfwGetWindowSize(g_Window, &w, &h);
+ glfwGetFramebufferSize(g_Window, &display_w, &display_h);
+ io.DisplaySize = ImVec2((float)display_w, (float)display_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;
+
+ // Setup inputs
+ // (we already got mouse wheel, keyboard keys & characters from glfw callbacks polled in glfwPollEvents())
+ double mouse_x, mouse_y;
+ glfwGetCursorPos(g_Window, &mouse_x, &mouse_y);
+ mouse_x *= (float)display_w / w; // Convert mouse coordinates to pixels
+ mouse_y *= (float)display_h / h;
+ io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.)
+
+ for (int i = 0; i < 3; i++)
+ {
+ io.MouseDown[i] = g_MousePressed[i] || glfwGetMouseButton(g_Window, i) != 0; // 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.
+ g_MousePressed[i] = false;
+ }
+
+ io.MouseWheel = g_MouseWheel;
+ g_MouseWheel = 0.0f;
+
+ // Start the frame
+ ImGui::NewFrame();
+}
diff --git a/examples/opengl3_example/imgui_impl_glfw_gl3.h b/examples/opengl3_example/imgui_impl_glfw_gl3.h
new file mode 100644
index 00000000..7b181577
--- /dev/null
+++ b/examples/opengl3_example/imgui_impl_glfw_gl3.h
@@ -0,0 +1,20 @@
+// ImGui GLFW binding with OpenGL3 + shaders
+// https://github.com/ocornut/imgui
+
+struct GLFWwindow;
+
+bool ImGui_ImplGlfwGL3_Init(GLFWwindow* window, bool install_callbacks);
+void ImGui_ImplGlfwGL3_Shutdown();
+void ImGui_ImplGlfwGL3_NewFrame();
+
+// Use if you want to reset your rendering device without losing ImGui state.
+void ImGui_ImplGlfwGL3_InvalidateDeviceObjects();
+bool ImGui_ImplGlfwGL3_CreateDeviceObjects();
+
+// GLFW callbacks (installed by default if you enable 'install_callbacks' during initialization)
+// Provided here if you want to chain callbacks.
+// You can also handle inputs yourself and use those as a reference.
+void ImGui_ImplGlfwGL3_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods);
+void ImGui_ImplGlfwGL3_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset);
+void ImGui_ImplGlFwGL3_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
+void ImGui_ImplGlfwGL3_CharCallback(GLFWwindow* window, unsigned int c);
diff --git a/examples/opengl3_example/main.cpp b/examples/opengl3_example/main.cpp
index 88dbdda4..9651970b 100644
--- a/examples/opengl3_example/main.cpp
+++ b/examples/opengl3_example/main.cpp
@@ -1,346 +1,48 @@
-// ImGui - standalone example application for OpenGL 3, using programmable pipeline
+// ImGui - standalone example application for Glfw + OpenGL 3, using programmable pipeline
-#ifdef _MSC_VER
-#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
-#endif
-#ifdef __clang__
-#pragma clang diagnostic ignored "-Wunused-function" // warning: unused function
-#endif
-
-#include "../../imgui.h"
+#include
+#include "imgui_impl_glfw_gl3.h"
#include
-
-// Gl3W / GLFW
#include
#include
-#ifdef _MSC_VER
-#undef APIENTRY
-#define GLFW_EXPOSE_NATIVE_WIN32
-#define GLFW_EXPOSE_NATIVE_WGL
-#include
-#endif
-
-static GLFWwindow* window;
-static bool mousePressed[2] = { false, false };
-
-#define OFFSETOF(TYPE, ELEMENT) ((size_t)&(((TYPE *)0)->ELEMENT))
-
-// Shader variables
-static int shader_handle, vert_handle, frag_handle;
-static int texture_location, proj_mtx_location;
-static int position_location, uv_location, colour_location;
-static size_t vbo_max_size = 20000;
-static unsigned int vbo_handle, vao_handle;
-
-// This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure)
-// If text or lines are blurry when integrating ImGui in your engine:
-// - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f)
-static void ImImpl_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count)
-{
- if (cmd_lists_count == 0)
- return;
-
- // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled
- glEnable(GL_BLEND);
- glBlendEquation(GL_FUNC_ADD);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glDisable(GL_CULL_FACE);
- glDisable(GL_DEPTH_TEST);
- glEnable(GL_SCISSOR_TEST);
- glActiveTexture(GL_TEXTURE0);
-
- // Setup orthographic projection matrix
- const float width = ImGui::GetIO().DisplaySize.x;
- const float height = ImGui::GetIO().DisplaySize.y;
- const float ortho_projection[4][4] =
- {
- { 2.0f/width, 0.0f, 0.0f, 0.0f },
- { 0.0f, 2.0f/-height, 0.0f, 0.0f },
- { 0.0f, 0.0f, -1.0f, 0.0f },
- { -1.0f, 1.0f, 0.0f, 1.0f },
- };
- glUseProgram(shader_handle);
- glUniform1i(texture_location, 0);
- glUniformMatrix4fv(proj_mtx_location, 1, GL_FALSE, &ortho_projection[0][0]);
-
- // Grow our buffer according to what we need
- size_t total_vtx_count = 0;
- for (int n = 0; n < cmd_lists_count; n++)
- total_vtx_count += cmd_lists[n]->vtx_buffer.size();
- glBindBuffer(GL_ARRAY_BUFFER, vbo_handle);
- size_t neededBufferSize = total_vtx_count * sizeof(ImDrawVert);
- if (neededBufferSize > vbo_max_size)
- {
- vbo_max_size = neededBufferSize + 5000; // Grow buffer
- glBufferData(GL_ARRAY_BUFFER, vbo_max_size, NULL, GL_STREAM_DRAW);
- }
-
- // Copy and convert all vertices into a single contiguous buffer
- unsigned char* buffer_data = (unsigned char*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
- if (!buffer_data)
- return;
- for (int n = 0; n < cmd_lists_count; n++)
- {
- const ImDrawList* cmd_list = cmd_lists[n];
- memcpy(buffer_data, &cmd_list->vtx_buffer[0], cmd_list->vtx_buffer.size() * sizeof(ImDrawVert));
- buffer_data += cmd_list->vtx_buffer.size() * sizeof(ImDrawVert);
- }
- glUnmapBuffer(GL_ARRAY_BUFFER);
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- glBindVertexArray(vao_handle);
-
- int cmd_offset = 0;
- for (int n = 0; n < cmd_lists_count; n++)
- {
- const ImDrawList* cmd_list = cmd_lists[n];
- int vtx_offset = cmd_offset;
- const ImDrawCmd* pcmd_end = cmd_list->commands.end();
- for (const ImDrawCmd* pcmd = cmd_list->commands.begin(); pcmd != pcmd_end; pcmd++)
- {
- glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->texture_id);
- glScissor((int)pcmd->clip_rect.x, (int)(height - pcmd->clip_rect.w), (int)(pcmd->clip_rect.z - pcmd->clip_rect.x), (int)(pcmd->clip_rect.w - pcmd->clip_rect.y));
- glDrawArrays(GL_TRIANGLES, vtx_offset, pcmd->vtx_count);
- vtx_offset += pcmd->vtx_count;
- }
- cmd_offset = vtx_offset;
- }
-
- // Restore modified state
- glBindVertexArray(0);
- glUseProgram(0);
- glDisable(GL_SCISSOR_TEST);
- glBindTexture(GL_TEXTURE_2D, 0);
-}
-
-static const char* ImImpl_GetClipboardTextFn()
-{
- return glfwGetClipboardString(window);
-}
-
-static void ImImpl_SetClipboardTextFn(const char* text)
-{
- glfwSetClipboardString(window, text);
-}
-
-// GLFW callbacks to get events
-static void glfw_error_callback(int error, const char* description)
-{
- fputs(description, stderr);
-}
-
-static void glfw_mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
-{
- if (action == GLFW_PRESS && button >= 0 && button < 2)
- mousePressed[button] = true;
-}
-
-static void glfw_scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
-{
- ImGuiIO& io = ImGui::GetIO();
- io.MouseWheel += (float)yoffset; // Use fractional mouse wheel, 1.0 unit 5 lines.
-}
-static void glfw_key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
+static void error_callback(int error, const char* description)
{
- ImGuiIO& io = ImGui::GetIO();
- if (action == GLFW_PRESS)
- io.KeysDown[key] = true;
- if (action == GLFW_RELEASE)
- io.KeysDown[key] = false;
- io.KeyCtrl = (mods & GLFW_MOD_CONTROL) != 0;
- io.KeyShift = (mods & GLFW_MOD_SHIFT) != 0;
+ fprintf(stderr, "Error: %s\n", description);
}
-static void glfw_char_callback(GLFWwindow* window, unsigned int c)
-{
- if (c > 0 && c < 0x10000)
- ImGui::GetIO().AddInputCharacter((unsigned short)c);
-}
-
-void InitGL()
+int main(int argc, char** argv)
{
- glfwSetErrorCallback(glfw_error_callback);
+ // Setup window
+ glfwSetErrorCallback(error_callback);
if (!glfwInit())
exit(1);
-
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
-
- window = glfwCreateWindow(1280, 720, "ImGui OpenGL3 example", NULL, NULL);
+ GLFWwindow* window = glfwCreateWindow(1280, 720, "ImGui OpenGL3 example", NULL, NULL);
glfwMakeContextCurrent(window);
- glfwSetKeyCallback(window, glfw_key_callback);
- glfwSetMouseButtonCallback(window, glfw_mouse_button_callback);
- glfwSetScrollCallback(window, glfw_scroll_callback);
- glfwSetCharCallback(window, glfw_char_callback);
-
gl3wInit();
- const GLchar *vertex_shader =
- "#version 330\n"
- "uniform mat4 ProjMtx;\n"
- "in vec2 Position;\n"
- "in vec2 UV;\n"
- "in vec4 Color;\n"
- "out vec2 Frag_UV;\n"
- "out vec4 Frag_Color;\n"
- "void main()\n"
- "{\n"
- " Frag_UV = UV;\n"
- " Frag_Color = Color;\n"
- " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
- "}\n";
-
- const GLchar* fragment_shader =
- "#version 330\n"
- "uniform sampler2D Texture;\n"
- "in vec2 Frag_UV;\n"
- "in vec4 Frag_Color;\n"
- "out vec4 Out_Color;\n"
- "void main()\n"
- "{\n"
- " Out_Color = Frag_Color * texture( Texture, Frag_UV.st);\n"
- "}\n";
-
- shader_handle = glCreateProgram();
- vert_handle = glCreateShader(GL_VERTEX_SHADER);
- frag_handle = glCreateShader(GL_FRAGMENT_SHADER);
- glShaderSource(vert_handle, 1, &vertex_shader, 0);
- glShaderSource(frag_handle, 1, &fragment_shader, 0);
- glCompileShader(vert_handle);
- glCompileShader(frag_handle);
- glAttachShader(shader_handle, vert_handle);
- glAttachShader(shader_handle, frag_handle);
- glLinkProgram(shader_handle);
-
- texture_location = glGetUniformLocation(shader_handle, "Texture");
- proj_mtx_location = glGetUniformLocation(shader_handle, "ProjMtx");
- position_location = glGetAttribLocation(shader_handle, "Position");
- uv_location = glGetAttribLocation(shader_handle, "UV");
- colour_location = glGetAttribLocation(shader_handle, "Color");
-
- glGenBuffers(1, &vbo_handle);
- glBindBuffer(GL_ARRAY_BUFFER, vbo_handle);
- glBufferData(GL_ARRAY_BUFFER, vbo_max_size, NULL, GL_DYNAMIC_DRAW);
-
- glGenVertexArrays(1, &vao_handle);
- glBindVertexArray(vao_handle);
- glBindBuffer(GL_ARRAY_BUFFER, vbo_handle);
- glEnableVertexAttribArray(position_location);
- glEnableVertexAttribArray(uv_location);
- glEnableVertexAttribArray(colour_location);
-
- glVertexAttribPointer(position_location, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, pos));
- glVertexAttribPointer(uv_location, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, uv));
- glVertexAttribPointer(colour_location, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, col));
- glBindVertexArray(0);
- glBindBuffer(GL_ARRAY_BUFFER, 0);
-}
-
-void LoadFontsTexture()
-{
- ImGuiIO& io = ImGui::GetIO();
+ // Setup ImGui binding
+ ImGui_ImplGlfwGL3_Init(window, true);
+ //ImGuiIO& io = ImGui::GetIO();
//ImFont* my_font1 = io.Fonts->AddFontDefault();
//ImFont* my_font2 = io.Fonts->AddFontFromFileTTF("extra_fonts/Karla-Regular.ttf", 15.0f);
//ImFont* my_font3 = io.Fonts->AddFontFromFileTTF("extra_fonts/ProggyClean.ttf", 13.0f); my_font3->DisplayOffset.y += 1;
//ImFont* my_font4 = io.Fonts->AddFontFromFileTTF("extra_fonts/ProggyTiny.ttf", 10.0f); my_font4->DisplayOffset.y += 1;
//ImFont* my_font5 = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, io.Fonts->GetGlyphRangesJapanese());
- unsigned char* pixels;
- int width, height;
- io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bits for OpenGL3 demo because it is more likely to be compatible with user's existing shader.
-
- GLuint tex_id;
- glGenTextures(1, &tex_id);
- glBindTexture(GL_TEXTURE_2D, tex_id);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
-
- // Store our identifier
- io.Fonts->TexID = (void *)(intptr_t)tex_id;
-}
-
-void InitImGui()
-{
- ImGuiIO& io = ImGui::GetIO();
- io.DeltaTime = 1.0f / 60.0f; // Time elapsed since last frame, in seconds (in this sample app we'll override this every frame because our timestep is variable)
- io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array.
- 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_Home] = GLFW_KEY_HOME;
- io.KeyMap[ImGuiKey_End] = GLFW_KEY_END;
- io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE;
- io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE;
- io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER;
- io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE;
- io.KeyMap[ImGuiKey_A] = GLFW_KEY_A;
- io.KeyMap[ImGuiKey_C] = GLFW_KEY_C;
- io.KeyMap[ImGuiKey_V] = GLFW_KEY_V;
- io.KeyMap[ImGuiKey_X] = GLFW_KEY_X;
- io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y;
- io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z;
-
- io.RenderDrawListsFn = ImImpl_RenderDrawLists;
- io.SetClipboardTextFn = ImImpl_SetClipboardTextFn;
- io.GetClipboardTextFn = ImImpl_GetClipboardTextFn;
-#ifdef _MSC_VER
- io.ImeWindowHandle = glfwGetWin32Window(window);
-#endif
-
- LoadFontsTexture();
-}
-
-void UpdateImGui()
-{
- ImGuiIO& io = ImGui::GetIO();
-
- // Setup resolution (every frame to accommodate for window resizing)
- int w, h;
- int display_w, display_h;
- glfwGetWindowSize(window, &w, &h);
- glfwGetFramebufferSize(window, &display_w, &display_h);
- io.DisplaySize = ImVec2((float)display_w, (float)display_h); // Display size, in pixels. For clamping windows positions.
-
- // Setup time step
- static double time = 0.0f;
- const double current_time = glfwGetTime();
- io.DeltaTime = (float)(current_time - time);
- time = current_time;
-
- // Setup inputs
- // (we already got mouse wheel, keyboard keys & characters from glfw callbacks polled in glfwPollEvents())
- double mouse_x, mouse_y;
- glfwGetCursorPos(window, &mouse_x, &mouse_y);
- mouse_x *= (float)display_w / w; // Convert mouse coordinates to pixels
- mouse_y *= (float)display_h / h;
- io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.)
- io.MouseDown[0] = mousePressed[0] || glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) != 0; // 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[1] = mousePressed[1] || glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) != 0;
-
- // Start the frame
- ImGui::NewFrame();
-}
-
-// Application code
-int main(int argc, char** argv)
-{
- InitGL();
- InitImGui();
-
bool show_test_window = true;
bool show_another_window = false;
- ImVec4 clear_col = ImColor(114, 144, 154);
+ ImVec4 clear_color = ImColor(114, 144, 154);
+ // Main loop
while (!glfwWindowShouldClose(window))
{
ImGuiIO& io = ImGui::GetIO();
- io.MouseWheel = 0;
- mousePressed[0] = mousePressed[1] = false;
glfwPollEvents();
- UpdateImGui();
+ ImGui_ImplGlfwGL3_NewFrame();
// 1. Show a simple window
// Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets appears in a window automatically called "Debug"
@@ -348,7 +50,7 @@ int main(int argc, char** argv)
static float f;
ImGui::Text("Hello, world!");
ImGui::SliderFloat("float", &f, 0.0f, 1.0f);
- ImGui::ColorEdit3("clear color", (float*)&clear_col);
+ ImGui::ColorEdit3("clear color", (float*)&clear_color);
if (ImGui::Button("Test Window")) show_test_window ^= 1;
if (ImGui::Button("Another Window")) show_another_window ^= 1;
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
@@ -371,22 +73,14 @@ int main(int argc, char** argv)
// Rendering
glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y);
- glClearColor(clear_col.x, clear_col.y, clear_col.z, clear_col.w);
+ glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w);
glClear(GL_COLOR_BUFFER_BIT);
ImGui::Render();
glfwSwapBuffers(window);
}
// Cleanup
- if (vao_handle) glDeleteVertexArrays(1, &vao_handle);
- if (vbo_handle) glDeleteBuffers(1, &vbo_handle);
- glDetachShader(shader_handle, vert_handle);
- glDetachShader(shader_handle, frag_handle);
- glDeleteShader(vert_handle);
- glDeleteShader(frag_handle);
- glDeleteProgram(shader_handle);
-
- ImGui::Shutdown();
+ ImGui_ImplGlfwGL3_Shutdown();
glfwTerminate();
return 0;
diff --git a/examples/opengl3_example/opengl3_example.vcxproj b/examples/opengl3_example/opengl3_example.vcxproj
index 01b4d947..cda336d2 100644
--- a/examples/opengl3_example/opengl3_example.vcxproj
+++ b/examples/opengl3_example/opengl3_example.vcxproj
@@ -39,16 +39,18 @@
$(ProjectDir)$(Configuration)\
$(ProjectDir)$(Configuration)\
+ $(IncludePath)
$(ProjectDir)$(Configuration)\
$(ProjectDir)$(Configuration)\
+ $(IncludePath)
Level3
Disabled
- $(ProjectDir)..\opengl_example\glfw\include;$(ProjectDir)..\opengl_example\glew\include;$(ProjectDir)..\opengl_example\gl3w;%(AdditionalIncludeDirectories)
+ $(ProjectDir)..\opengl_example\glfw\include;gl3w;..\..;%(AdditionalIncludeDirectories)
true
@@ -64,7 +66,7 @@
MaxSpeed
true
true
- $(ProjectDir)..\opengl_example\glfw\include;$(ProjectDir)..\opengl_example\glew\include;$(ProjectDir)..\opengl_example\gl3w;%(AdditionalIncludeDirectories)
+ $(ProjectDir)..\opengl_example\glfw\include;gl3w;..\..;%(AdditionalIncludeDirectories)
true
@@ -79,12 +81,16 @@
-
+
+
+
+
+
diff --git a/examples/opengl3_example/opengl3_example.vcxproj.filters b/examples/opengl3_example/opengl3_example.vcxproj.filters
index cb06331d..1c00552d 100644
--- a/examples/opengl3_example/opengl3_example.vcxproj.filters
+++ b/examples/opengl3_example/opengl3_example.vcxproj.filters
@@ -8,6 +8,9 @@
{f18ab499-84e1-499f-8eff-9754361e0e52}
cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+ {42f99867-3108-43b8-99d0-fabefaf1f2e3}
+
@@ -16,9 +19,12 @@
imgui
-
+
sources
+
+ gl3w
+
@@ -27,5 +33,14 @@
imgui
+
+ sources
+
+
+ gl3w
+
+
+ gl3w
+
\ No newline at end of file
diff --git a/examples/opengl_example/Makefile b/examples/opengl_example/Makefile
index 2563bdb8..966e9338 100644
--- a/examples/opengl_example/Makefile
+++ b/examples/opengl_example/Makefile
@@ -1,6 +1,5 @@
#
-# Cross Platform Make file
-#
+# Cross Platform Makefile
# Compatible with Ubuntu 14.04.1 and Mac OS X
#
#
@@ -11,7 +10,7 @@
#CXX = g++
-OBJS = main.o
+OBJS = main.o imgui_impl_glfw.o
OBJS += ../../imgui.o
UNAME_S := $(shell uname -s)
diff --git a/examples/opengl_example/imgui_impl_glfw.cpp b/examples/opengl_example/imgui_impl_glfw.cpp
new file mode 100644
index 00000000..2be01de0
--- /dev/null
+++ b/examples/opengl_example/imgui_impl_glfw.cpp
@@ -0,0 +1,252 @@
+// ImGui GLFW binding with OpenGL
+// https://github.com/ocornut/imgui
+
+#include
+#include "imgui_impl_glfw.h"
+
+// GLFW
+#include
+#ifdef _MSC_VER
+#undef APIENTRY
+#define GLFW_EXPOSE_NATIVE_WIN32
+#define GLFW_EXPOSE_NATIVE_WGL
+#include
+#endif
+
+// Data
+static GLFWwindow* g_Window = NULL;
+static double g_Time = 0.0f;
+static bool g_MousePressed[3] = { false, false, false };
+static float g_MouseWheel = 0.0f;
+static GLuint g_FontTexture = 0;
+
+// This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure)
+// If text or lines are blurry when integrating ImGui in your engine:
+// - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f)
+static void ImGui_ImplGlfw_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count)
+{
+ if (cmd_lists_count == 0)
+ return;
+
+ // We are using the OpenGL fixed pipeline to make the example code simpler to read!
+ // A probable faster way to render would be to collate all vertices from all cmd_lists into a single vertex buffer.
+ // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers.
+ glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_SCISSOR_TEST);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glEnableClientState(GL_COLOR_ARRAY);
+ glEnable(GL_TEXTURE_2D);
+
+ // Setup orthographic projection matrix
+ const float width = ImGui::GetIO().DisplaySize.x;
+ const float height = ImGui::GetIO().DisplaySize.y;
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ glOrtho(0.0f, width, height, 0.0f, -1.0f, +1.0f);
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+
+ // Render command lists
+ #define OFFSETOF(TYPE, ELEMENT) ((size_t)&(((TYPE *)0)->ELEMENT))
+ for (int n = 0; n < cmd_lists_count; n++)
+ {
+ const ImDrawList* cmd_list = cmd_lists[n];
+ const unsigned char* vtx_buffer = (const unsigned char*)&cmd_list->vtx_buffer.front();
+ glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)(vtx_buffer + OFFSETOF(ImDrawVert, pos)));
+ glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)(vtx_buffer + OFFSETOF(ImDrawVert, uv)));
+ glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (void*)(vtx_buffer + OFFSETOF(ImDrawVert, col)));
+
+ int vtx_offset = 0;
+ for (size_t cmd_i = 0; cmd_i < cmd_list->commands.size(); cmd_i++)
+ {
+ const ImDrawCmd* pcmd = &cmd_list->commands[cmd_i];
+ if (pcmd->user_callback)
+ {
+ pcmd->user_callback(cmd_list, pcmd);
+ }
+ else
+ {
+ glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->texture_id);
+ glScissor((int)pcmd->clip_rect.x, (int)(height - pcmd->clip_rect.w), (int)(pcmd->clip_rect.z - pcmd->clip_rect.x), (int)(pcmd->clip_rect.w - pcmd->clip_rect.y));
+ glDrawArrays(GL_TRIANGLES, vtx_offset, pcmd->vtx_count);
+ }
+ vtx_offset += pcmd->vtx_count;
+ }
+ }
+ #undef OFFSETOF
+
+ // Restore modified state
+ glDisableClientState(GL_COLOR_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glPopAttrib();
+}
+
+static const char* ImGui_ImplGlfw_GetClipboardText()
+{
+ return glfwGetClipboardString(g_Window);
+}
+
+static void ImGui_ImplGlfw_SetClipboardText(const char* text)
+{
+ glfwSetClipboardString(g_Window, text);
+}
+
+void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
+{
+ if (action == GLFW_PRESS && button >= 0 && button < 3)
+ g_MousePressed[button] = true;
+}
+
+void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset)
+{
+ g_MouseWheel += (float)yoffset; // Use fractional mouse wheel, 1.0 unit 5 lines.
+}
+
+void ImGui_ImplGlFw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
+{
+ ImGuiIO& io = ImGui::GetIO();
+ if (action == GLFW_PRESS)
+ io.KeysDown[key] = true;
+ if (action == GLFW_RELEASE)
+ io.KeysDown[key] = false;
+ io.KeyCtrl = (mods & GLFW_MOD_CONTROL) != 0;
+ io.KeyShift = (mods & GLFW_MOD_SHIFT) != 0;
+}
+
+void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c)
+{
+ ImGuiIO& io = ImGui::GetIO();
+ if (c > 0 && c < 0x10000)
+ io.AddInputCharacter((unsigned short)c);
+}
+
+bool ImGui_ImplGlfw_CreateDeviceObjects()
+{
+ ImGuiIO& io = ImGui::GetIO();
+
+ // Build texture
+ unsigned char* pixels;
+ int width, height;
+ io.Fonts->GetTexDataAsAlpha8(&pixels, &width, &height);
+
+ // Create texture
+ glGenTextures(1, &g_FontTexture);
+ glBindTexture(GL_TEXTURE_2D, g_FontTexture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, pixels);
+
+ // Store our identifier
+ io.Fonts->TexID = (void *)(intptr_t)g_FontTexture;
+
+ return true;
+}
+
+void ImGui_ImplGlfw_InvalidateDeviceObjects()
+{
+ if (g_FontTexture)
+ {
+ glDeleteTextures(1, &g_FontTexture);
+ ImGui::GetIO().Fonts->TexID = 0;
+ g_FontTexture = 0;
+ }
+}
+
+bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks)
+{
+ g_Window = window;
+
+ ImGuiIO& io = ImGui::GetIO();
+ io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array.
+ 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_Home] = GLFW_KEY_HOME;
+ io.KeyMap[ImGuiKey_End] = GLFW_KEY_END;
+ io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE;
+ io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE;
+ io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER;
+ io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE;
+ io.KeyMap[ImGuiKey_A] = GLFW_KEY_A;
+ io.KeyMap[ImGuiKey_C] = GLFW_KEY_C;
+ io.KeyMap[ImGuiKey_V] = GLFW_KEY_V;
+ io.KeyMap[ImGuiKey_X] = GLFW_KEY_X;
+ io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y;
+ io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z;
+
+ io.RenderDrawListsFn = ImGui_ImplGlfw_RenderDrawLists;
+ io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText;
+ io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText;
+#ifdef _MSC_VER
+ io.ImeWindowHandle = glfwGetWin32Window(g_Window);
+#endif
+
+ if (install_callbacks)
+ {
+ glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback);
+ glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback);
+ glfwSetKeyCallback(window, ImGui_ImplGlFw_KeyCallback);
+ glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback);
+ }
+
+ return true;
+}
+
+void ImGui_ImplGlfw_Shutdown()
+{
+ ImGui_ImplGlfw_InvalidateDeviceObjects();
+ ImGui::Shutdown();
+}
+
+void ImGui_ImplGlfw_NewFrame()
+{
+ if (!g_FontTexture)
+ ImGui_ImplGlfw_CreateDeviceObjects();
+
+ ImGuiIO& io = ImGui::GetIO();
+
+ // Setup display size (every frame to accommodate for window resizing)
+ int w, h;
+ int display_w, display_h;
+ glfwGetWindowSize(g_Window, &w, &h);
+ glfwGetFramebufferSize(g_Window, &display_w, &display_h);
+ io.DisplaySize = ImVec2((float)display_w, (float)display_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;
+
+ // Setup inputs
+ // (we already got mouse wheel, keyboard keys & characters from glfw callbacks polled in glfwPollEvents())
+ double mouse_x, mouse_y;
+ glfwGetCursorPos(g_Window, &mouse_x, &mouse_y);
+ mouse_x *= (float)display_w / w; // Convert mouse coordinates to pixels
+ mouse_y *= (float)display_h / h;
+ io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.)
+
+ for (int i = 0; i < 3; i++)
+ {
+ io.MouseDown[i] = g_MousePressed[i] || glfwGetMouseButton(g_Window, i) != 0; // 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.
+ g_MousePressed[i] = false;
+ }
+
+ io.MouseWheel = g_MouseWheel;
+ g_MouseWheel = 0.0f;
+
+ // Start the frame
+ ImGui::NewFrame();
+}
diff --git a/examples/opengl_example/imgui_impl_glfw.h b/examples/opengl_example/imgui_impl_glfw.h
new file mode 100644
index 00000000..502d837f
--- /dev/null
+++ b/examples/opengl_example/imgui_impl_glfw.h
@@ -0,0 +1,20 @@
+// ImGui GLFW binding with OpenGL
+// https://github.com/ocornut/imgui
+
+struct GLFWwindow;
+
+bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks);
+void ImGui_ImplGlfw_Shutdown();
+void ImGui_ImplGlfw_NewFrame();
+
+// Use if you want to reset your rendering device without losing ImGui state.
+void ImGui_ImplGlfw_InvalidateDeviceObjects();
+bool ImGui_ImplGlfw_CreateDeviceObjects();
+
+// GLFW callbacks (installed by default if you enable 'install_callbacks' during initialization)
+// Provided here if you want to chain callbacks.
+// You can also handle inputs yourself and use those as a reference.
+void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods);
+void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset);
+void ImGui_ImplGlFw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
+void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c);
diff --git a/examples/opengl_example/main.cpp b/examples/opengl_example/main.cpp
index 4cef9290..c9d303d0 100644
--- a/examples/opengl_example/main.cpp
+++ b/examples/opengl_example/main.cpp
@@ -1,256 +1,42 @@
-// ImGui - standalone example application for OpenGL 2, using fixed pipeline
+// ImGui - standalone example application for Glfw + OpenGL 2, using fixed pipeline
-#ifdef _MSC_VER
-#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
-#endif
-#ifdef __clang__
-#pragma clang diagnostic ignored "-Wunused-function" // warning: unused function
-#endif
-
-#include "../../imgui.h"
+#include
+#include "imgui_impl_glfw.h"
#include
-
-// GLFW
#include
-#ifdef _MSC_VER
-#undef APIENTRY
-#define GLFW_EXPOSE_NATIVE_WIN32
-#define GLFW_EXPOSE_NATIVE_WGL
-#include
-#endif
-
-static GLFWwindow* window;
-static bool mousePressed[2] = { false, false };
-
-#define OFFSETOF(TYPE, ELEMENT) ((size_t)&(((TYPE *)0)->ELEMENT))
-// This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure)
-// If text or lines are blurry when integrating ImGui in your engine:
-// - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f)
-static void ImImpl_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count)
+static void error_callback(int error, const char* description)
{
- if (cmd_lists_count == 0)
- return;
-
- // We are using the OpenGL fixed pipeline to make the example code simpler to read!
- // A probable faster way to render would be to collate all vertices from all cmd_lists into a single vertex buffer.
- // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers.
- glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glDisable(GL_CULL_FACE);
- glDisable(GL_DEPTH_TEST);
- glEnable(GL_SCISSOR_TEST);
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glEnableClientState(GL_COLOR_ARRAY);
- glEnable(GL_TEXTURE_2D);
-
- // Setup orthographic projection matrix
- const float width = ImGui::GetIO().DisplaySize.x;
- const float height = ImGui::GetIO().DisplaySize.y;
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
- glOrtho(0.0f, width, height, 0.0f, -1.0f, +1.0f);
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glLoadIdentity();
-
- // Render command lists
- for (int n = 0; n < cmd_lists_count; n++)
- {
- const ImDrawList* cmd_list = cmd_lists[n];
- const unsigned char* vtx_buffer = (const unsigned char*)&cmd_list->vtx_buffer.front();
- glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)(vtx_buffer + OFFSETOF(ImDrawVert, pos)));
- glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)(vtx_buffer + OFFSETOF(ImDrawVert, uv)));
- glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (void*)(vtx_buffer + OFFSETOF(ImDrawVert, col)));
-
- int vtx_offset = 0;
- for (size_t cmd_i = 0; cmd_i < cmd_list->commands.size(); cmd_i++)
- {
- const ImDrawCmd* pcmd = &cmd_list->commands[cmd_i];
- glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->texture_id);
- glScissor((int)pcmd->clip_rect.x, (int)(height - pcmd->clip_rect.w), (int)(pcmd->clip_rect.z - pcmd->clip_rect.x), (int)(pcmd->clip_rect.w - pcmd->clip_rect.y));
- glDrawArrays(GL_TRIANGLES, vtx_offset, pcmd->vtx_count);
- vtx_offset += pcmd->vtx_count;
- }
- }
-
- // Restore modified state
- glDisableClientState(GL_COLOR_ARRAY);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- glDisableClientState(GL_VERTEX_ARRAY);
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glPopAttrib();
+ fprintf(stderr, "Error: %s\n", description);
}
-// NB: ImGui already provide OS clipboard support for Windows so this isn't needed if you are using Windows only.
-static const char* ImImpl_GetClipboardTextFn()
-{
- return glfwGetClipboardString(window);
-}
-
-static void ImImpl_SetClipboardTextFn(const char* text)
-{
- glfwSetClipboardString(window, text);
-}
-
-// GLFW callbacks
-static void glfw_error_callback(int error, const char* description)
-{
- fputs(description, stderr);
-}
-
-static void glfw_mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
-{
- if (action == GLFW_PRESS && button >= 0 && button < 2)
- mousePressed[button] = true;
-}
-
-static void glfw_scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
-{
- ImGuiIO& io = ImGui::GetIO();
- io.MouseWheel += (float)yoffset; // Use fractional mouse wheel, 1.0 unit 5 lines.
-}
-
-static void glfw_key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
-{
- ImGuiIO& io = ImGui::GetIO();
- if (action == GLFW_PRESS)
- io.KeysDown[key] = true;
- if (action == GLFW_RELEASE)
- io.KeysDown[key] = false;
- io.KeyCtrl = (mods & GLFW_MOD_CONTROL) != 0;
- io.KeyShift = (mods & GLFW_MOD_SHIFT) != 0;
-}
-
-static void glfw_char_callback(GLFWwindow* window, unsigned int c)
-{
- if (c > 0 && c < 0x10000)
- ImGui::GetIO().AddInputCharacter((unsigned short)c);
-}
-
-void InitGL()
+int main(int argc, char** argv)
{
- glfwSetErrorCallback(glfw_error_callback);
+ // Setup window
+ glfwSetErrorCallback(error_callback);
if (!glfwInit())
exit(1);
-
- window = glfwCreateWindow(1280, 720, "ImGui OpenGL2 example", NULL, NULL);
+ GLFWwindow* window = glfwCreateWindow(1280, 720, "ImGui OpenGL2 example", NULL, NULL);
glfwMakeContextCurrent(window);
- glfwSetKeyCallback(window, glfw_key_callback);
- glfwSetMouseButtonCallback(window, glfw_mouse_button_callback);
- glfwSetScrollCallback(window, glfw_scroll_callback);
- glfwSetCharCallback(window, glfw_char_callback);
-}
-void LoadFontsTexture()
-{
- ImGuiIO& io = ImGui::GetIO();
+ // Setup ImGui binding
+ ImGui_ImplGlfw_Init(window, true);
+ //ImGuiIO& io = ImGui::GetIO();
//ImFont* my_font1 = io.Fonts->AddFontDefault();
//ImFont* my_font2 = io.Fonts->AddFontFromFileTTF("extra_fonts/Karla-Regular.ttf", 15.0f);
//ImFont* my_font3 = io.Fonts->AddFontFromFileTTF("extra_fonts/ProggyClean.ttf", 13.0f); my_font3->DisplayOffset.y += 1;
//ImFont* my_font4 = io.Fonts->AddFontFromFileTTF("extra_fonts/ProggyTiny.ttf", 10.0f); my_font4->DisplayOffset.y += 1;
//ImFont* my_font5 = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, io.Fonts->GetGlyphRangesJapanese());
- unsigned char* pixels;
- int width, height;
- io.Fonts->GetTexDataAsAlpha8(&pixels, &width, &height);
-
- GLuint tex_id;
- glGenTextures(1, &tex_id);
- glBindTexture(GL_TEXTURE_2D, tex_id);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, pixels);
-
- // Store our identifier
- io.Fonts->TexID = (void *)(intptr_t)tex_id;
-}
-
-void InitImGui()
-{
- ImGuiIO& io = ImGui::GetIO();
- io.DeltaTime = 1.0f/60.0f; // Time elapsed since last frame, in seconds (in this sample app we'll override this every frame because our time step is variable)
- io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array.
- 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_Home] = GLFW_KEY_HOME;
- io.KeyMap[ImGuiKey_End] = GLFW_KEY_END;
- io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE;
- io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE;
- io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER;
- io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE;
- io.KeyMap[ImGuiKey_A] = GLFW_KEY_A;
- io.KeyMap[ImGuiKey_C] = GLFW_KEY_C;
- io.KeyMap[ImGuiKey_V] = GLFW_KEY_V;
- io.KeyMap[ImGuiKey_X] = GLFW_KEY_X;
- io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y;
- io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z;
-
- io.RenderDrawListsFn = ImImpl_RenderDrawLists;
- io.SetClipboardTextFn = ImImpl_SetClipboardTextFn;
- io.GetClipboardTextFn = ImImpl_GetClipboardTextFn;
-#ifdef _MSC_VER
- io.ImeWindowHandle = glfwGetWin32Window(window);
-#endif
-
- LoadFontsTexture();
-}
-
-void UpdateImGui()
-{
- ImGuiIO& io = ImGui::GetIO();
-
- // Setup resolution (every frame to accommodate for window resizing)
- int w, h;
- int display_w, display_h;
- glfwGetWindowSize(window, &w, &h);
- glfwGetFramebufferSize(window, &display_w, &display_h);
- io.DisplaySize = ImVec2((float)display_w, (float)display_h); // Display size, in pixels. For clamping windows positions.
-
- // Setup time step
- static double time = 0.0f;
- const double current_time = glfwGetTime();
- io.DeltaTime = (float)(current_time - time);
- time = current_time;
-
- // Setup inputs
- // (we already got mouse wheel, keyboard keys & characters from glfw callbacks polled in glfwPollEvents())
- double mouse_x, mouse_y;
- glfwGetCursorPos(window, &mouse_x, &mouse_y);
- mouse_x *= (float)display_w / w; // Convert mouse coordinates to pixels
- mouse_y *= (float)display_h / h;
- io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.)
- io.MouseDown[0] = mousePressed[0] || glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) != 0; // 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[1] = mousePressed[1] || glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) != 0;
-
- // Start the frame
- ImGui::NewFrame();
-}
-
-// Application code
-int main(int argc, char** argv)
-{
- InitGL();
- InitImGui();
-
bool show_test_window = true;
bool show_another_window = false;
- ImVec4 clear_col = ImColor(114, 144, 154);
+ ImVec4 clear_color = ImColor(114, 144, 154);
+ // Main loop
while (!glfwWindowShouldClose(window))
{
- ImGuiIO& io = ImGui::GetIO();
- mousePressed[0] = mousePressed[1] = false;
glfwPollEvents();
- UpdateImGui();
+ ImGui_ImplGlfw_NewFrame();
// 1. Show a simple window
// Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets appears in a window automatically called "Debug"
@@ -258,7 +44,7 @@ int main(int argc, char** argv)
static float f;
ImGui::Text("Hello, world!");
ImGui::SliderFloat("float", &f, 0.0f, 1.0f);
- ImGui::ColorEdit3("clear color", (float*)&clear_col);
+ ImGui::ColorEdit3("clear color", (float*)&clear_color);
if (ImGui::Button("Test Window")) show_test_window ^= 1;
if (ImGui::Button("Another Window")) show_another_window ^= 1;
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
@@ -280,15 +66,15 @@ int main(int argc, char** argv)
}
// Rendering
- glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y);
- glClearColor(clear_col.x, clear_col.y, clear_col.z, clear_col.w);
+ glViewport(0, 0, (int)ImGui::GetIO().DisplaySize.x, (int)ImGui::GetIO().DisplaySize.y);
+ glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w);
glClear(GL_COLOR_BUFFER_BIT);
ImGui::Render();
glfwSwapBuffers(window);
}
// Cleanup
- ImGui::Shutdown();
+ ImGui_ImplGlfw_Shutdown();
glfwTerminate();
return 0;
diff --git a/examples/opengl_example/opengl_example.vcxproj b/examples/opengl_example/opengl_example.vcxproj
index 557f0dc9..6dc90454 100644
--- a/examples/opengl_example/opengl_example.vcxproj
+++ b/examples/opengl_example/opengl_example.vcxproj
@@ -39,16 +39,18 @@
$(ProjectDir)$(Configuration)\
$(ProjectDir)$(Configuration)\
+ $(IncludePath)
$(ProjectDir)$(Configuration)\
$(ProjectDir)$(Configuration)\
+ $(IncludePath)
Level3
Disabled
- $(ProjectDir)\glfw\include;$(ProjectDir)\glew\include;%(AdditionalIncludeDirectories)
+ $(ProjectDir)\glfw\include;..\..;%(AdditionalIncludeDirectories)
true
@@ -64,7 +66,7 @@
MaxSpeed
true
true
- $(ProjectDir)\glfw\include;$(ProjectDir)\glew\include;%(AdditionalIncludeDirectories)
+ $(ProjectDir)\glfw\include;..\..;%(AdditionalIncludeDirectories)
true
@@ -79,11 +81,13 @@
+
+
diff --git a/examples/opengl_example/opengl_example.vcxproj.filters b/examples/opengl_example/opengl_example.vcxproj.filters
index cf1ba241..1365a7da 100644
--- a/examples/opengl_example/opengl_example.vcxproj.filters
+++ b/examples/opengl_example/opengl_example.vcxproj.filters
@@ -16,6 +16,9 @@
imgui
+
+ sources
+
@@ -24,5 +27,8 @@
imgui
+
+ sources
+
\ No newline at end of file
diff --git a/imgui.cpp b/imgui.cpp
index 8c788893..40a8f5c9 100644
--- a/imgui.cpp
+++ b/imgui.cpp
@@ -1,4 +1,4 @@
-// ImGui library v1.35 wip
+// ImGui library v1.35
// See ImGui::ShowTestWindow() for sample code.
// Read 'Programmer guide' below for notes on how to setup ImGui in your codebase.
// Get latest version at https://github.com/ocornut/imgui
@@ -9,9 +9,9 @@
Index
- MISSION STATEMENT
- END-USER GUIDE
- - PROGRAMMER GUIDE
- - API BREAKING CHANGES
- - TROUBLESHOOTING & FREQUENTLY ASKED QUESTIONS
+ - PROGRAMMER GUIDE (read me!)
+ - API BREAKING CHANGES (read me when you update!)
+ - FREQUENTLY ASKED QUESTIONS (FAQ) & TROUBLESHOOTING (read me!)
- ISSUES & TODO-LIST
- CODE
- SAMPLE CODE
@@ -27,15 +27,15 @@
- minimize screen real-estate usage
- minimize setup and maintenance
- minimize state storage on user side
- - portable, minimize dependencies, run on target (consoles, etc.)
+ - portable, minimize dependencies, run on target (consoles, phones, etc.)
- efficient runtime (NB- we do allocate when "growing" content - creating a window / opening a tree node for the first time, etc. - but a typical frame won't allocate anything)
- - read about immediate-mode GUI principles @ http://mollyrocket.com/861, http://mollyrocket.com/forums/index.html
+ - read about immediate-mode gui principles @ http://mollyrocket.com/861, http://mollyrocket.com/forums/index.html
Designed for developers and content-creators, not the typical end-user! Some of the weaknesses includes:
- doesn't look fancy, doesn't animate
- limited layout features, intricate layouts are typically crafted in code
- - occasionally use statically sized buffers for string manipulations - won't crash, but some long text may be clipped
-
+ - occasionally uses statically sized buffers for string manipulations - won't crash, but some long text may be clipped. functions like ImGui::TextUnformatted() don't have such restriction.
+
END-USER GUIDE
==============
@@ -63,12 +63,12 @@
PROGRAMMER GUIDE
================
- - your code creates the UI, if your code doesn't run the UI is gone! == dynamic UI, no construction step, less data retention on your side, no state duplication, less sync, less errors.
- - call and read ImGui::ShowTestWindow() for user-side sample code
+ - read the FAQ below this section!
+ - your code creates the UI, if your code doesn't run the UI is gone! == very dynamic UI, no construction/destructions steps, less data retention on your side, no state duplication, less sync, less bugs.
+ - call and read ImGui::ShowTestWindow() for sample code demonstrating most features.
- see examples/ folder for standalone sample applications.
- customization: use the style editor or PushStyleColor/PushStyleVar to tweak the look of the interface (e.g. if you want a more compact UI or a different color scheme).
-
- getting started:
- initialisation: call ImGui::GetIO() and fill the 'Settings' data.
- every frame:
@@ -129,6 +129,7 @@
Occasionally introducing changes that are breaking the API. The breakage are generally minor and easy to fix.
Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code.
+ - 2015/03/08 (1.35) - renamed style.ScrollBarWidth to style.ScrollbarWidth
- 2015/02/27 (1.34) - renamed OpenNextNode(bool) to SetNextTreeNodeOpened(bool, ImGuiSetCond), kept inline redirection function.
- 2015/02/27 (1.34) - renamed ImGuiSetCondition_*** to ImGuiSetCond_***, and _FirstUseThisSession becomes _Once.
- 2015/02/11 (1.32) - changed text input callback ImGuiTextEditCallback return type from void-->int. reserved for future use, return 0 for now.
@@ -167,29 +168,57 @@
- 2014/08/28 (1.09) - changed the behavior of IO.PixelCenterOffset following various rendering fixes
- TROUBLESHOOTING & FREQUENTLY ASKED QUESTIONS
- ============================================
+ FREQUENTLY ASKED QUESTIONS (FAQ) & TROUBLESHOOTING
+ ==================================================
If text or lines are blurry when integrating ImGui in your engine:
+
- in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f)
- If you are confused about the meaning or use of ID in ImGui:
- - many widgets requires state to be carried over multiple frames (most typically ImGui often wants remember what is the "active" widget).
- to do so they need an unique ID. unique ID are typically derived from a string label, an indice or a pointer.
- when you call Button("OK") the button shows "OK" and also use "OK" as an ID.
+ A primer on the meaning and use of ID in ImGui:
+
+ - widgets require state to be carried over multiple frames (most typically ImGui often needs to remember what is the "active" widget).
+ to do so they need an unique ID. unique ID are typically derived from a string label, an integer index or a pointer.
+
+ Button("OK"); // Label = "OK", ID = hash of "OK"
+ Button("Cancel"); // Label = "Cancel", ID = hash of "Cancel"
+
- ID are uniquely scoped within Windows so no conflict can happen if you have two buttons called "OK" in two different Windows.
- within a same Window, use PushID() / PopID() to easily create scopes and avoid ID conflicts.
- so if you have a loop creating "multiple" items, you can use PushID() / PopID() with the index of each item, or their pointer, etc.
- some functions like TreeNode() implicitly creates a scope for you by calling PushID()
- - when dealing with trees, ID are important because you want to preserve the opened/closed state of tree nodes.
- depending on your use cases you may want to use strings, indices or pointers as ID. experiment and see what makes more sense!
- e.g. When displaying a single object that may change over time, using a static string as ID will preserve your node open/closed state when the targeted object change
- e.g. When displaying a list of objects, using indices or pointers as ID will preserve the node open/closed state per object
- - when passing a label you can optionally specify extra unique ID information within the same string using "##". This helps solving the simpler collision cases.
- e.g. "Label" display "Label" and uses "Label" as ID
- e.g. "Label##Foobar" display "Label" and uses "Label##Foobar" as ID
- e.g. "##Foobar" display an empty label and uses "##Foobar" as ID
- - read articles about immediate-mode ui principles (see web links) to understand the requirement and use of ID.
+
+ - when passing a label you can optionally specify extra unique ID information within string itself. This helps solving the simpler collision cases.
+ use "##" to pass a complement to the ID that won't be visible to the end-user:
+
+ Button("Play##0"); // Label = "Play", ID = hash of "Play##0"
+ Button("Play##1"); // Label = "Play", ID = hash of "Play##1" (different from above)
+
+ use "###" to pass a label that isn't part of ID. You can use that to change labels while preserving a constant ID.
+
+ Button("Hello###ID"; // Label = "Hello", ID = hash of "ID"
+ Button("World###ID"; // Label = "World", ID = hash of "ID" (same as above)
+
+ - use PushID() / PopID() to create scopes and avoid ID conflicts within the same Window:
+
+ Button("Click"); // Label = "Click", ID = hash of "Click"
+ PushID("node");
+ Button("Click"); // Label = "Click", ID = hash of "node" and "Click"
+ for (int i = 0; i < 100; i++)
+ {
+ PushID(i);
+ Button("Click"); // Label = "Click", ID = hash of "node" and i and "label"
+ PopID();
+ }
+ PopID();
+ PushID(my_ptr);
+ Button("Click"); // Label = "Click", ID = hash of ptr and "Click"
+ PopID();
+
+ so if you have a loop creating multiple items, you can use PushID() / PopID() with the index of each item, or their pointer, etc.
+ some functions like TreeNode() implicitly creates a scope for you by calling PushID().
+
+ - when working with trees, ID are used to preserve the opened/closed state of tree nodes.
+ depending on your use cases you may want to use strings, indices or pointers as ID.
+ e.g. when displaying a single object that may change over time (1-1 relationship), using a static string as ID will preserve your node open/closed state when the targeted object change.
+ e.g. when displaying a list of objects, using indices or pointers as ID will preserve the node open/closed state differently. experiment and see what makes more sense!
If you want to load a different font than the default (ProggyClean.ttf, size 13)
@@ -233,8 +262,6 @@
- main: IsItemHovered() returns true even if mouse is active on another widget (e.g. dragging outside of sliders). Maybe not a sensible default? Add parameter or alternate function?
- main: IsItemHovered() make it more consistent for various type of widgets, widgets with multiple components, etc. also effectively IsHovered() region sometimes differs from hot region, e.g tree nodes
- main: IsItemHovered() info stored in a stack? so that 'if TreeNode() { Text; TreePop; } if IsHovered' return the hover state of the TreeNode?
- - scrollbar: use relative mouse movement when first-clicking inside of scroll grab box.
- - scrollbar: make the grab visible and a minimum size for long scroll regions
!- input number: very large int not reliably supported because of int<>float conversions.
- input number: optional range min/max for Input*() functions
- input number: holding [-]/[+] buttons could increase the step speed non-linearly (or user-controlled)
@@ -261,7 +288,7 @@
- plot: add a helper e.g. Plot(char* label, float value, float time_span=2.0f) that stores values and Plot them for you - probably another function name. and/or automatically allow to plot ANY displayed value (more reliance on stable ID)
- file selection widget -> build the tool in our codebase to improve model-dialog idioms
- slider: allow using the [-]/[+] buttons used by InputFloat()/InputInt()
- - slider: initial absolute click is imprecise. change to relative movement slider? hide mouse cursor, allow more precise input using less screen-space.
+ - slider: initial absolute click is imprecise. change to relative movement slider? hide mouse cursor, allow more precise input using less screen-space. same as scrollbar.
- text edit: clean up the mess caused by converting UTF-8 <> wchar. the code is rather inefficient right now.
- text edit: centered text for slider as input text so it matches typical positioning.
- text edit: flag to disable live update of the user buffer.
@@ -364,8 +391,8 @@ namespace IMGUI_STB_NAMESPACE
#endif
#include "stb_truetype.h"
-#define STB_TEXTEDIT_STRING ImGuiTextEditState
-#define STB_TEXTEDIT_CHARTYPE ImWchar
+#define STB_TEXTEDIT_STRING ImGuiTextEditState
+#define STB_TEXTEDIT_CHARTYPE ImWchar
#include "stb_textedit.h"
#ifdef __clang__
@@ -381,7 +408,14 @@ using namespace IMGUI_STB_NAMESPACE;
// Forward Declarations
//-------------------------------------------------------------------------
+struct ImGuiColMod;
+struct ImGuiStyleMod;
struct ImGuiAabb;
+struct ImGuiDrawContext;
+struct ImGuiTextEditState;
+struct ImGuiIniData;
+struct ImGuiState;
+struct ImGuiWindow;
static bool ButtonBehaviour(const ImGuiAabb& bb, const ImGuiID& id, bool* out_hovered, bool* out_held, bool allow_key_modifiers, bool repeat = false, bool pressed_on_click = false);
static void LogText(const ImVec2& ref_pos, const char* text, const char* text_end = NULL);
@@ -402,6 +436,7 @@ static bool IsClipped(const ImGuiAabb& bb);
static bool IsMouseHoveringBox(const ImGuiAabb& bb);
static bool IsKeyPressedMap(ImGuiKey key, bool repeat = true);
+static void Scrollbar(ImGuiWindow* window);
static bool CloseWindowButton(bool* p_opened = NULL);
static void FocusWindow(ImGuiWindow* window);
static ImGuiWindow* FindHoveredWindow(ImVec2 pos, bool excluding_childs);
@@ -416,7 +451,7 @@ static size_t ImFormatString(char* buf, size_t buf_size, const char* fmt,
static size_t ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args);
// Helpers: Misc
-static ImU32 ImCrc32(const void* data, size_t data_size, ImU32 seed);
+static ImU32 ImHash(const void* data, size_t data_size, ImU32 seed);
static bool ImLoadFileToMemory(const char* filename, const char* file_open_mode, void** out_file_data, size_t* out_file_size, size_t padding_bytes = 0);
static inline int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; }
static inline bool ImCharIsSpace(int c) { return c == ' ' || c == '\t' || c == 0x3000; }
@@ -425,9 +460,9 @@ static inline bool ImCharIsSpace(int c) { return c == ' ' || c == '\t' || c ==
static int ImTextCharToUtf8(char* buf, size_t buf_size, unsigned int in_char); // return output UTF-8 bytes count
static ptrdiff_t ImTextStrToUtf8(char* buf, size_t buf_size, const ImWchar* in_text, const ImWchar* in_text_end); // return output UTF-8 bytes count
static int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end); // return input UTF-8 bytes count
-static ptrdiff_t ImTextStrFromUtf8(ImWchar* buf, size_t buf_size, const char* in_text, const char* in_text_end); // return input UTF-8 bytes count
+static ptrdiff_t ImTextStrFromUtf8(ImWchar* buf, size_t buf_size, const char* in_text, const char* in_text_end, const char** in_remaining = NULL); // return input UTF-8 bytes count
static int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end); // return number of UTF-8 code-points (NOT bytes count)
-static int ImTextCountUtf8BytesFromWchar(const ImWchar* in_text, const ImWchar* in_text_end); // return number of bytes to express string as UTF-8 code-points
+static int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end); // return number of bytes to express string as UTF-8 code-points
//-----------------------------------------------------------------------------
// Platform dependent default implementations
@@ -468,7 +503,8 @@ ImGuiStyle::ImGuiStyle()
WindowFillAlphaDefault = 0.70f; // Default alpha of window background, if not specified in ImGui::Begin()
TreeNodeSpacing = 22.0f; // Horizontal spacing when entering a tree node
ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns
- ScrollBarWidth = 16.0f; // Width of the vertical scroll bar
+ ScrollbarWidth = 16.0f; // Width of the vertical scrollbar
+ GrabMinSize = 10.0f; // Minimum width/height of a slider or scrollbar grab
Colors[ImGuiCol_Text] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
Colors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f);
@@ -656,7 +692,8 @@ static const char* ImStristr(const char* haystack, const char* needle, const cha
}
// Pass data_size==0 for zero-terminated string
-static ImU32 ImCrc32(const void* data, size_t data_size, ImU32 seed = 0)
+// Try to replace with FNV1a hash?
+static ImU32 ImHash(const void* data, size_t data_size, ImU32 seed = 0)
{
static ImU32 crc32_lut[256] = { 0 };
if (!crc32_lut[1])
@@ -670,7 +707,9 @@ static ImU32 ImCrc32(const void* data, size_t data_size, ImU32 seed = 0)
crc32_lut[i] = crc;
}
}
- ImU32 crc = ~seed;
+
+ seed = ~seed;
+ ImU32 crc = seed;
const unsigned char* current = (const unsigned char*)data;
if (data_size > 0)
@@ -683,7 +722,16 @@ static ImU32 ImCrc32(const void* data, size_t data_size, ImU32 seed = 0)
{
// Zero-terminated string
while (unsigned char c = *current++)
- crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c];
+ {
+ // We support a syntax of "label###id" where only "###id" is included in the hash, and only "label" gets displayed.
+ // Because this syntax is rarely used we are optimizing for the common case.
+ // - If we reach ### in the string we discard the hash so far and reset to the seed.
+ // - We don't do 'current += 2; continue;' after handling ### to keep the code smaller.
+ if (c == '#' && current[0] == '#' && current[1] == '#')
+ crc = seed;
+
+ crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c];
+ }
}
return ~crc;
}
@@ -907,8 +955,9 @@ struct ImGuiTextEditState
{
ImGuiID Id; // widget id owning the text state
ImWchar Text[1024]; // edit buffer, we need to persist but can't guarantee the persistence of the user-provided buffer. so we copy into own buffer.
- char InitialText[1024*3+1]; // backup of end-user buffer at the time of focus (in UTF-8, unconverted)
- size_t BufSize; // end-user buffer size, <= 1024 (or increase above)
+ char InitialText[1024*4+1]; // backup of end-user buffer at the time of focus (in UTF-8, unaltered)
+ size_t CurLenA, CurLenW; // we need to maintain our buffer length in both UTF-8 and wchar format.
+ size_t BufSizeA; // end-user buffer size, <= 1024 (or increase above)
float Width; // widget width
float ScrollX;
STB_TexteditState StbState;
@@ -939,6 +988,7 @@ struct ImGuiTextEditState
struct ImGuiIniData
{
char* Name;
+ ImGuiID ID;
ImVec2 Pos;
ImVec2 Size;
bool Collapsed;
@@ -997,6 +1047,7 @@ struct ImGuiState
ImGuiID SliderAsInputTextId;
ImGuiStorage ColorEditModeStorage; // for user selection
ImGuiID ActiveComboID;
+ float ScrollbarClickDeltaToGrabCenter; // distance between mouse and center of grab box, normalized in parent space
char Tooltip[1024];
char* PrivateClipboard; // if no custom clipboard handler is defined
@@ -1046,6 +1097,7 @@ struct ImGuiState
SliderAsInputTextId = 0;
ActiveComboID = 0;
+ ScrollbarClickDeltaToGrabCenter = 0.0f;
memset(Tooltip, 0, sizeof(Tooltip));
PrivateClipboard = NULL;
@@ -1073,7 +1125,8 @@ struct ImGuiWindow
ImVec2 Pos; // Position rounded-up to nearest pixel
ImVec2 Size; // Current size (==SizeFull or collapsed title bar size)
ImVec2 SizeFull; // Size when non collapsed
- ImVec2 SizeContentsFit; // Size of contents (extents reach by the drawing cursor) - may not fit within Size.
+ ImVec2 SizeContents; // Size of contents (== extents reach of the drawing cursor) from previous frame
+ ImVec2 SizeContentsCurrent; // Size of contents, currently extending
float ScrollY;
float NextScrollY;
bool ScrollbarY;
@@ -1409,11 +1462,13 @@ void ImGuiTextBuffer::append(const char* fmt, ...)
ImGuiWindow::ImGuiWindow(const char* name)
{
Name = ImStrdup(name);
- ID = GetID(name);
+ ID = ImHash(name, 0);
+ IDStack.push_back(ID);
+
Flags = 0;
PosFloat = Pos = ImVec2(0.0f, 0.0f);
Size = SizeFull = ImVec2(0.0f, 0.0f);
- SizeContentsFit = ImVec2(0.0f, 0.0f);
+ SizeContents = SizeContentsCurrent = ImVec2(0.0f, 0.0f);
ScrollY = 0.0f;
NextScrollY = 0.0f;
ScrollbarY = false;
@@ -1425,7 +1480,6 @@ ImGuiWindow::ImGuiWindow(const char* name)
AutoFitOnlyGrows = false;
SetWindowPosAllowFlags = SetWindowSizeAllowFlags = SetWindowCollapsedAllowFlags = ImGuiSetCond_Always | ImGuiSetCond_Once | ImGuiSetCond_FirstUseEver;
- IDStack.push_back(ID);
LastFrameDrawn = -1;
ItemWidthDefault = 0.0f;
FontWindowScale = 1.0f;
@@ -1456,16 +1510,16 @@ ImGuiWindow::~ImGuiWindow()
ImGuiID ImGuiWindow::GetID(const char* str)
{
- const ImGuiID seed = IDStack.empty() ? 0 : IDStack.back();
- const ImGuiID id = ImCrc32(str, 0, seed);
+ ImGuiID seed = IDStack.back();
+ const ImGuiID id = ImHash(str, 0, seed);
RegisterAliveId(id);
return id;
}
ImGuiID ImGuiWindow::GetID(const void* ptr)
{
- const ImGuiID seed = IDStack.empty() ? 0 : IDStack.back();
- const ImGuiID id = ImCrc32(&ptr, sizeof(void*), seed);
+ ImGuiID seed = IDStack.back();
+ const ImGuiID id = ImHash(&ptr, sizeof(void*), seed);
RegisterAliveId(id);
return id;
}
@@ -1537,10 +1591,11 @@ void ImGui::MemFree(void* ptr)
static ImGuiIniData* FindWindowSettings(const char* name)
{
ImGuiState& g = *GImGui;
+ ImGuiID id = ImHash(name, 0);
for (size_t i = 0; i != g.Settings.size(); i++)
{
ImGuiIniData* ini = g.Settings[i];
- if (ImStricmp(ini->Name, name) == 0)
+ if (ini->ID == id)
return ini;
}
return NULL;
@@ -1551,6 +1606,7 @@ static ImGuiIniData* AddWindowSettings(const char* name)
ImGuiIniData* ini = (ImGuiIniData*)ImGui::MemAlloc(sizeof(ImGuiIniData));
new(ini) ImGuiIniData();
ini->Name = ImStrdup(name);
+ ini->ID = ImHash(name, 0);
ini->Collapsed = false;
ini->Pos = ImVec2(FLT_MAX,FLT_MAX);
ini->Size = ImVec2(0,0);
@@ -1635,7 +1691,10 @@ static void SaveSettings()
const ImGuiIniData* settings = g.Settings[i];
if (settings->Pos.x == FLT_MAX)
continue;
- fprintf(f, "[%s]\n", settings->Name);
+ const char* name = settings->Name;
+ if (const char* p = strstr(name, "###")) // Skip to the "###" marker if any. We don't skip past to match the behavior of GetID()
+ name = p;
+ fprintf(f, "[%s]\n", name);
fprintf(f, "Pos=%d,%d\n", (int)settings->Pos.x, (int)settings->Pos.y);
fprintf(f, "Size=%d,%d\n", (int)settings->Size.x, (int)settings->Size.y);
fprintf(f, "Collapsed=%d\n", settings->Collapsed);
@@ -2047,7 +2106,9 @@ void ImGui::Render()
static const char* FindTextDisplayEnd(const char* text, const char* text_end = NULL)
{
const char* text_display_end = text;
- while ((!text_end || text_display_end < text_end) && *text_display_end != '\0' && (text_display_end[0] != '#' || text_display_end[1] != '#'))
+ if (!text_end)
+ text_end = (const char*)-1;
+ while (text_display_end < text_end && *text_display_end != '\0' && (text_display_end[0] != '#' || text_display_end[1] != '#'))
text_display_end++;
return text_display_end;
}
@@ -2253,7 +2314,7 @@ static void RenderCollapseTriangle(ImVec2 p_min, bool opened, float scale, bool
if (shadow && (window->Flags & ImGuiWindowFlags_ShowBorders) != 0)
window->DrawList->AddTriangleFilled(a+ImVec2(2,2), b+ImVec2(2,2), c+ImVec2(2,2), window->Color(ImGuiCol_BorderShadow));
- window->DrawList->AddTriangleFilled(a, b, c, window->Color(ImGuiCol_Border));
+ window->DrawList->AddTriangleFilled(a, b, c, window->Color(ImGuiCol_Text));
}
// Calculate text size. Text can be multi-line. Optionally ignore text after a ## marker.
@@ -2604,8 +2665,8 @@ void ImGui::EndChildFrame()
static ImGuiWindow* FindWindowByName(const char* name)
{
// FIXME-OPT: Store sorted hashes -> pointers.
- ImGuiID id = ImCrc32(name, 0, 0);
ImGuiState& g = *GImGui;
+ ImGuiID id = ImHash(name, 0);
for (size_t i = 0; i < g.Windows.size(); i++)
if (g.Windows[i]->ID == id)
return g.Windows[i];
@@ -2664,7 +2725,8 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFl
// - 'size' for a regular window denote the initial size for first-time creation (no saved data) and isn't that useful. Use SetNextWindowSize() prior to calling Begin() for more flexible window manipulation.
// - A default window called "Debug" is automatically stacked at the beginning of every frame so you can use widgets without explicitly calling a Begin/End pair.
// - Begin/End can be called multiple times during the frame with the same window name to append content.
-// - The window name is used as a unique identifier to preserve window information across frames (and save rudimentary information to the .ini file). Note that you can use ## to append unique data that isn't displayed, e.g. "My window##1" will use "My window##1" as unique window ID but display "My window" to the user.
+// - The window name is used as a unique identifier to preserve window information across frames (and save rudimentary information to the .ini file).
+// You can use the "##" or "###" markers to use the same label with different id, or same id with different label. See documentation at the top of this file.
// - Return false when window is collapsed, so you can early out in your code. You always need to call ImGui::End() even if false is returned.
// - Passing 'bool* p_opened' displays a Close button on the upper-right corner of the window, the pointed value will be set to false when the button is pressed.
// - Passing non-zero 'size' is roughly equivalent to calling SetNextWindowSize(size, ImGuiSetCond_FirstUseEver) prior to calling Begin().
@@ -2743,6 +2805,10 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg
window->LastFrameDrawn = current_frame;
window->ClipRectStack.resize(0);
+ // Reset contents size for auto-fitting
+ window->SizeContents = window->SizeContentsCurrent;
+ window->SizeContentsCurrent = ImVec2(0.0f, 0.0f);
+
if (flags & ImGuiWindowFlags_ChildWindow)
{
parent_window->DC.ChildWindows.push_back(window);
@@ -2765,9 +2831,8 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg
// Setup and draw window
if (first_begin_of_the_frame)
{
- // Seed ID stack with our window pointer
- window->IDStack.resize(0);
- ImGui::PushID(window);
+ // Reset ID stack
+ window->IDStack.resize(1);
// Move window (at the beginning of the frame to avoid input lag or sheering). Only valid for root windows.
const ImGuiID move_id = window->GetID("#MOVE");
@@ -2838,7 +2903,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg
window->ScrollY = window->NextScrollY;
window->ScrollY = ImMax(window->ScrollY, 0.0f);
if (!window->Collapsed && !window->SkipItems)
- window->ScrollY = ImMin(window->ScrollY, ImMax(0.0f, (float)window->SizeContentsFit.y - window->SizeFull.y));
+ window->ScrollY = ImMin(window->ScrollY, ImMax(0.0f, window->SizeContents.y - window->SizeFull.y));
window->NextScrollY = window->ScrollY;
// At this point we don't have a clipping rectangle setup yet, so we can test and draw in title bar
@@ -2878,12 +2943,12 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg
if ((window->Flags & ImGuiWindowFlags_Tooltip) != 0)
{
// Tooltip always resize. We keep the spacing symmetric on both axises for aesthetic purpose.
- const ImVec2 size_auto_fit = window->SizeContentsFit + style.WindowPadding - ImVec2(0.0f, style.ItemSpacing.y);
+ const ImVec2 size_auto_fit = window->SizeContents + style.WindowPadding - ImVec2(0.0f, style.ItemSpacing.y);
window->SizeFull = size_auto_fit;
}
else
{
- const ImVec2 size_auto_fit = ImClamp(window->SizeContentsFit + style.AutoFitPadding, style.WindowMinSize, ImMax(style.WindowMinSize, g.IO.DisplaySize - style.AutoFitPadding));
+ const ImVec2 size_auto_fit = ImClamp(window->SizeContents + style.AutoFitPadding, style.WindowMinSize, ImMax(style.WindowMinSize, g.IO.DisplaySize - style.AutoFitPadding));
if ((window->Flags & ImGuiWindowFlags_AlwaysAutoResize) != 0)
{
// Don't continuously mark settings as dirty, the size of the window doesn't need to be stored.
@@ -2903,7 +2968,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg
{
// Manual resize grip
const ImGuiAabb resize_aabb(window->Aabb().GetBR()-ImVec2(18,18), window->Aabb().GetBR());
- const ImGuiID resize_id = window->GetID("##RESIZE");
+ const ImGuiID resize_id = window->GetID("#RESIZE");
bool hovered, held;
ButtonBehaviour(resize_aabb, resize_id, &hovered, &held, true);
resize_col = window->Color(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip);
@@ -2931,7 +2996,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg
}
// Scrollbar
- window->ScrollbarY = (window->SizeContentsFit.y > window->Size.y) && !(window->Flags & ImGuiWindowFlags_NoScrollbar);
+ window->ScrollbarY = (window->SizeContents.y > window->Size.y) && !(window->Flags & ImGuiWindowFlags_NoScrollbar);
// Window background
if (bg_alpha > 0.0f)
@@ -2941,7 +3006,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg
else if ((window->Flags & ImGuiWindowFlags_Tooltip) != 0)
window->DrawList->AddRectFilled(window->Pos, window->Pos+window->Size, window->Color(ImGuiCol_TooltipBg, bg_alpha), window_rounding);
else if ((window->Flags & ImGuiWindowFlags_ChildWindow) != 0)
- window->DrawList->AddRectFilled(window->Pos, window->Pos+window->Size-ImVec2(window->ScrollbarY?style.ScrollBarWidth:0.0f,0.0f), window->Color(ImGuiCol_ChildWindowBg, bg_alpha), window_rounding, window->ScrollbarY ? (1|8) : (0xF));
+ window->DrawList->AddRectFilled(window->Pos, window->Pos+window->Size-ImVec2(window->ScrollbarY?style.ScrollbarWidth:0.0f,0.0f), window->Color(ImGuiCol_ChildWindowBg, bg_alpha), window_rounding, window->ScrollbarY ? (1|8) : (0xF));
else
window->DrawList->AddRectFilled(window->Pos, window->Pos+window->Size, window->Color(ImGuiCol_WindowBg, bg_alpha), window_rounding);
}
@@ -2961,38 +3026,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg
// Scrollbar
if (window->ScrollbarY)
- {
- ImGuiAabb scrollbar_bb(window->Aabb().Max.x - style.ScrollBarWidth, title_bar_aabb.Max.y+1, window->Aabb().Max.x, window->Aabb().Max.y-1);
- //window->DrawList->AddLine(scrollbar_bb.GetTL(), scrollbar_bb.GetBL(), g.Colors[ImGuiCol_Border]);
- window->DrawList->AddRectFilled(scrollbar_bb.Min, scrollbar_bb.Max, window->Color(ImGuiCol_ScrollbarBg));
- scrollbar_bb.Expand(ImVec2(-3,-3));
-
- const float grab_size_y_norm = ImSaturate(window->Size.y / ImMax(window->SizeContentsFit.y, window->Size.y));
- const float grab_size_y = scrollbar_bb.GetHeight() * grab_size_y_norm;
-
- // Handle input right away (none of the code above is relying on scrolling position)
- bool held = false;
- bool hovered = false;
- if (grab_size_y_norm < 1.0f)
- {
- const ImGuiID scrollbar_id = window->GetID("#SCROLLY");
- ButtonBehaviour(scrollbar_bb, scrollbar_id, &hovered, &held, true);
- if (held)
- {
- g.HoveredId = scrollbar_id;
- const float pos_y_norm = ImSaturate((g.IO.MousePos.y - (scrollbar_bb.Min.y + grab_size_y*0.5f)) / (scrollbar_bb.GetHeight() - grab_size_y)) * (1.0f - grab_size_y_norm);
- window->ScrollY = (float)(int)(pos_y_norm * window->SizeContentsFit.y);
- window->NextScrollY = window->ScrollY;
- }
- }
-
- // Normalized height of the grab
- const float pos_y_norm = ImSaturate(window->ScrollY / ImMax(0.0f, window->SizeContentsFit.y));
- const ImU32 grab_col = window->Color(held ? ImGuiCol_ScrollbarGrabActive : hovered ? ImGuiCol_ScrollbarGrabHovered : ImGuiCol_ScrollbarGrab);
- window->DrawList->AddRectFilled(
- ImVec2(scrollbar_bb.Min.x, ImLerp(scrollbar_bb.Min.y, scrollbar_bb.Max.y, pos_y_norm)),
- ImVec2(scrollbar_bb.Max.x, ImLerp(scrollbar_bb.Min.y, scrollbar_bb.Max.y, pos_y_norm + grab_size_y_norm)), grab_col);
- }
+ Scrollbar(window);
// Render resize grip
// (after the input handling so we don't have a frame of latency)
@@ -3032,8 +3066,6 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg
window->DC.TreeDepth = 0;
window->DC.StateStorage = &window->StateStorage;
- // Reset contents size for auto-fitting
- window->SizeContentsFit = ImVec2(0.0f, 0.0f);
if (window->AutoFitFrames > 0)
window->AutoFitFrames--;
@@ -3065,7 +3097,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg
const ImGuiAabb title_bar_aabb = window->TitleBarAabb();
ImVec4 clip_rect(title_bar_aabb.Min.x+0.5f+window->WindowPadding().x*0.5f, title_bar_aabb.Max.y+0.5f, window->Aabb().Max.x+0.5f-window->WindowPadding().x*0.5f, window->Aabb().Max.y-1.5f);
if (window->ScrollbarY)
- clip_rect.z -= style.ScrollBarWidth;
+ clip_rect.z -= style.ScrollbarWidth;
PushClipRect(clip_rect);
// Clear 'accessed' flag last thing
@@ -3115,6 +3147,75 @@ void ImGui::End()
g.CurrentWindow = g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back();
}
+// Vertical scrollbar
+// The entire piece of code below is rather confusing because:
+// - We handle absolute seeking (when first clicking outside the grab) and relative manipulation (afterward or when clicking inside the grab)
+// - We store values as ratio and in a form that allows the window content to change while we are holding on a scrollbar
+static void Scrollbar(ImGuiWindow* window)
+{
+ ImGuiState& g = *GImGui;
+ const ImGuiStyle& style = g.Style;
+ const ImGuiID id = window->GetID("#SCROLLY");
+
+ // Render background
+ ImGuiAabb bb(window->Aabb().Max.x - style.ScrollbarWidth, window->Pos.y + window->TitleBarHeight()+1, window->Aabb().Max.x, window->Aabb().Max.y-1);
+ window->DrawList->AddRectFilled(bb.Min, bb.Max, window->Color(ImGuiCol_ScrollbarBg));
+ bb.Expand(ImVec2(-3,-3));
+ const float scrollbar_height = bb.GetHeight();
+
+ // The grabable box size generally represent the amount visible (vs the total scrollable amount)
+ // But we maintain a minimum size in pixel to allow for the user to still aim inside.
+ const float grab_h_pixels = ImMax(style.GrabMinSize, scrollbar_height * ImSaturate(window->Size.y / ImMax(window->SizeContents.y, window->Size.y)));
+ const float grab_h_norm = grab_h_pixels / scrollbar_height;
+
+ // Handle input right away. None of the code of Begin() is relying on scrolling position before calling Scrollbar().
+ bool held = false;
+ bool hovered = false;
+ const bool previously_held = (g.ActiveId == id);
+ ButtonBehaviour(bb, id, &hovered, &held, true);
+
+ const float scroll_max = ImMax(1.0f, window->SizeContents.y - window->Size.y);
+ float scroll_ratio = ImSaturate(window->ScrollY / scroll_max);
+ float grab_y_norm = scroll_ratio * (scrollbar_height - grab_h_pixels) / scrollbar_height;
+ if (held)
+ {
+ const float clicked_y_norm = ImSaturate((g.IO.MousePos.y - bb.Min.y) / scrollbar_height); // Click position in scrollbar space (0.0f->1.0f)
+ g.HoveredId = id;
+
+ bool seek_absolute = false;
+ if (!previously_held)
+ {
+ // On initial click calculate the distance between mouse and the center of the grab
+ if (clicked_y_norm >= grab_y_norm && clicked_y_norm <= grab_y_norm + grab_h_norm)
+ {
+ g.ScrollbarClickDeltaToGrabCenter = clicked_y_norm - grab_y_norm - grab_h_norm*0.5f;
+ }
+ else
+ {
+ seek_absolute = true;
+ g.ScrollbarClickDeltaToGrabCenter = 0;
+ }
+ }
+
+ // Apply scroll
+ const float scroll_y_norm = ImSaturate((clicked_y_norm - g.ScrollbarClickDeltaToGrabCenter - grab_h_norm*0.5f) / (1.0f - grab_h_norm));
+ window->ScrollY = (float)(int)(0.5f + scroll_y_norm * (window->SizeContents.y - window->Size.y));
+ window->NextScrollY = window->ScrollY;
+
+ // Update values for rendering
+ scroll_ratio = ImSaturate(window->ScrollY / scroll_max);
+ grab_y_norm = scroll_ratio * (scrollbar_height - grab_h_pixels) / scrollbar_height;
+
+ // Update distance to grab now that we have seeked and saturated
+ if (seek_absolute)
+ g.ScrollbarClickDeltaToGrabCenter = clicked_y_norm - grab_y_norm - grab_h_norm*0.5f;
+ }
+
+ // Render
+ const ImU32 grab_col = window->Color(held ? ImGuiCol_ScrollbarGrabActive : hovered ? ImGuiCol_ScrollbarGrabHovered : ImGuiCol_ScrollbarGrab);
+ window->DrawList->AddRectFilled(ImVec2(bb.Min.x, ImLerp(bb.Min.y, bb.Max.y, grab_y_norm)), ImVec2(bb.Max.x, ImLerp(bb.Min.y, bb.Max.y, grab_y_norm) + grab_h_pixels), grab_col);
+}
+
// Moving window to front of display (which happens to be back of our sorted list)
static void FocusWindow(ImGuiWindow* window)
{
@@ -3535,7 +3636,7 @@ ImVec2 ImGui::GetContentRegionMax()
else
{
if (window->ScrollbarY)
- mx.x -= GImGui->Style.ScrollBarWidth;
+ mx.x -= GImGui->Style.ScrollbarWidth;
}
return mx;
}
@@ -3551,7 +3652,7 @@ ImVec2 ImGui::GetWindowContentRegionMax()
ImGuiWindow* window = GetCurrentWindow();
ImVec2 m = window->Size - window->WindowPadding();
if (window->ScrollbarY)
- m.x -= GImGui->Style.ScrollBarWidth;
+ m.x -= GImGui->Style.ScrollbarWidth;
return m;
}
@@ -3614,21 +3715,21 @@ void ImGui::SetCursorPos(const ImVec2& pos)
{
ImGuiWindow* window = GetCurrentWindow();
window->DC.CursorPos = window->Pos + pos;
- window->SizeContentsFit = ImMax(window->SizeContentsFit, pos + ImVec2(0.0f, window->ScrollY));
+ window->SizeContentsCurrent = ImMax(window->SizeContentsCurrent, pos + ImVec2(0.0f, window->ScrollY));
}
void ImGui::SetCursorPosX(float x)
{
ImGuiWindow* window = GetCurrentWindow();
window->DC.CursorPos.x = window->Pos.x + x;
- window->SizeContentsFit.x = ImMax(window->SizeContentsFit.x, x);
+ window->SizeContentsCurrent.x = ImMax(window->SizeContentsCurrent.x, x);
}
void ImGui::SetCursorPosY(float y)
{
ImGuiWindow* window = GetCurrentWindow();
window->DC.CursorPos.y = window->Pos.y + y;
- window->SizeContentsFit.y = ImMax(window->SizeContentsFit.y, y + window->ScrollY);
+ window->SizeContentsCurrent.y = ImMax(window->SizeContentsCurrent.y, y + window->ScrollY);
}
ImVec2 ImGui::GetCursorScreenPos()
@@ -3643,6 +3744,18 @@ void ImGui::SetCursorScreenPos(const ImVec2& screen_pos)
window->DC.CursorPos = screen_pos;
}
+float ImGui::GetScrollPosY()
+{
+ ImGuiWindow* window = GetCurrentWindow();
+ return window->ScrollY;
+}
+
+float ImGui::GetScrollMaxY()
+{
+ ImGuiWindow* window = GetCurrentWindow();
+ return window->SizeContents.y - window->SizeFull.y;
+}
+
void ImGui::SetScrollPosHere()
{
ImGuiWindow* window = GetCurrentWindow();
@@ -4015,7 +4128,7 @@ static bool CloseWindowButton(bool* p_opened)
{
ImGuiWindow* window = GetCurrentWindow();
- const ImGuiID id = window->GetID("##CLOSE");
+ const ImGuiID id = window->GetID("#CLOSE");
const float size = window->TitleBarHeight() - 4.0f;
const ImGuiAabb bb(window->Aabb().GetTR() + ImVec2(-3.0f-size,2.0f), window->Aabb().GetTR() + ImVec2(-3.0f,2.0f+size));
@@ -4274,9 +4387,8 @@ bool ImGui::CollapsingHeader(const char* label, const char* str_id, bool display
// When logging is enabled, if automatically expand tree nodes (but *NOT* collapsing headers.. seems like sensible behaviour).
// NB- If we are above max depth we still allow manually opened nodes to be logged.
- if (!display_frame)
- if (g.LogEnabled && window->DC.TreeDepth < g.LogAutoExpandMaxDepth)
- opened = true;
+ if (g.LogEnabled && !display_frame && window->DC.TreeDepth < g.LogAutoExpandMaxDepth)
+ opened = true;
if (!ItemAdd(bb, &id))
return opened;
@@ -4580,9 +4692,9 @@ bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, c
const float grab_size_in_units = 1.0f; // In 'v' units. Probably needs to be parametrized, based on a 'v_step' value? decimal precision?
float grab_size_in_pixels;
if (decimal_precision > 0 || is_unbound)
- grab_size_in_pixels = 10.0f;
+ grab_size_in_pixels = style.GrabMinSize;
else
- grab_size_in_pixels = ImMax(grab_size_in_units * (w / (v_max-v_min+1.0f)), 8.0f); // Integer sliders
+ grab_size_in_pixels = ImMax(grab_size_in_units * (w / (v_max-v_min+1.0f)), style.GrabMinSize); // Integer sliders
const float slider_effective_w = slider_bb.GetWidth() - grab_size_in_pixels;
const float slider_effective_x1 = slider_bb.Min.x + grab_size_in_pixels*0.5f;
const float slider_effective_x2 = slider_bb.Max.x - grab_size_in_pixels*0.5f;
@@ -5150,17 +5262,38 @@ static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, STB_TEXTEDIT_STRING* ob
static bool is_separator(unsigned int c) { return c==',' || c==';' || c=='(' || c==')' || c=='{' || c=='}' || c=='[' || c==']' || c=='|'; }
#define STB_TEXTEDIT_IS_SPACE(CH) ( ImCharIsSpace((unsigned int)CH) || is_separator((unsigned int)CH) )
-static void STB_TEXTEDIT_DELETECHARS(STB_TEXTEDIT_STRING* obj, int pos, int n) { ImWchar* dst = obj->Text+pos; const ImWchar* src = obj->Text+pos+n; while (ImWchar c = *src++) *dst++ = c; *dst = '\0'; }
+static void STB_TEXTEDIT_DELETECHARS(STB_TEXTEDIT_STRING* obj, int pos, int n)
+{
+ ImWchar* dst = obj->Text + pos;
+
+ // We maintain our buffer length in both UTF-8 and wchar formats
+ obj->CurLenA -= ImTextCountUtf8BytesFromStr(dst, dst + n);
+ obj->CurLenW -= n;
+
+ // Offset remaining text
+ const ImWchar* src = obj->Text + pos + n;
+ while (ImWchar c = *src++)
+ *dst++ = c;
+ *dst = '\0';
+}
+
static bool STB_TEXTEDIT_INSERTCHARS(STB_TEXTEDIT_STRING* obj, int pos, const ImWchar* new_text, int new_text_len)
{
- const size_t text_len = ImStrlenW(obj->Text);
- if ((size_t)new_text_len + text_len + 1 > obj->BufSize)
+ const size_t text_len = obj->CurLenW;
+ if ((size_t)new_text_len + text_len + 1 > IM_ARRAYSIZE(obj->Text))
+ return false;
+
+ const int new_text_len_utf8 = ImTextCountUtf8BytesFromStr(new_text, new_text + new_text_len);
+ if ((size_t)new_text_len_utf8 + obj->CurLenA + 1 > obj->BufSizeA)
return false;
if (pos != (int)text_len)
memmove(obj->Text + (size_t)pos + new_text_len, obj->Text + (size_t)pos, (text_len - (size_t)pos) * sizeof(ImWchar));
memcpy(obj->Text + (size_t)pos, new_text, (size_t)new_text_len * sizeof(ImWchar));
- obj->Text[text_len + (size_t)new_text_len] = '\0';
+
+ obj->CurLenW += new_text_len;
+ obj->CurLenA += new_text_len_utf8;
+ obj->Text[obj->CurLenW] = '\0';
return true;
}
@@ -5255,11 +5388,15 @@ void ImGuiTextEditState::RenderTextScrolledClipped(ImFont* font, float font_size
const char* text_start = GetTextPointerClippedA(font, font_size, buf, scroll_x, NULL);
const char* text_end = GetTextPointerClippedA(font, font_size, text_start, width, &text_size);
+ // We need to test for the possibility of malformed UTF-8 (instead of just text_end[0] != 0)
+ unsigned int text_end_char = 0;
+ ImTextCharFromUtf8(&text_end_char, text_end, NULL);
+
// Draw a little clip symbol if we've got text on either left or right of the box
const char symbol_c = '~';
const float symbol_w = font_size*0.40f; // FIXME: compute correct width
const float clip_begin = (text_start > buf && text_start < text_end) ? symbol_w : 0.0f;
- const float clip_end = (text_end[0] != '\0' && text_end > text_start) ? symbol_w : 0.0f;
+ const float clip_end = (text_end_char != 0 && text_end > text_start) ? symbol_w : 0.0f;
// Draw text
RenderText(pos+ImVec2(clip_begin,0), text_start+(clip_begin>0.0f?1:0), text_end-(clip_end>0.0f?1:0), false);
@@ -5471,8 +5608,11 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT
{
// Start edition
// Take a copy of the initial buffer value (both in original UTF-8 format and converted to wchar)
+ // From the moment we focused we are ignoring the content of 'buf'
ImFormatString(edit_state.InitialText, IM_ARRAYSIZE(edit_state.InitialText), "%s", buf);
- size_t buf_len = ImTextStrFromUtf8(edit_state.Text, IM_ARRAYSIZE(edit_state.Text), buf, NULL);
+ const char* buf_end = NULL;
+ edit_state.CurLenW = ImTextStrFromUtf8(edit_state.Text, IM_ARRAYSIZE(edit_state.Text), buf, NULL, &buf_end);
+ edit_state.CurLenA = buf_end - buf; // We can't get the result from ImFormatString() above because it is not UTF-8 aware. Here we'll cut off malformed UTF-8.
edit_state.Width = w;
edit_state.InputCursorScreenPos = ImVec2(-1.f,-1.f);
edit_state.CursorAnimReset();
@@ -5489,9 +5629,9 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT
{
// Recycle existing cursor/selection/undo stack but clamp position
// Note a single mouse click will override the cursor/position immediately by calling stb_textedit_click handler.
- edit_state.StbState.cursor = ImMin(edit_state.StbState.cursor, buf_len);
- edit_state.StbState.select_start = ImMin(edit_state.StbState.select_start, buf_len);
- edit_state.StbState.select_end = ImMin(edit_state.StbState.select_end, buf_len);
+ edit_state.StbState.cursor = ImMin(edit_state.StbState.cursor, edit_state.CurLenW);
+ edit_state.StbState.select_start = ImMin(edit_state.StbState.select_start, edit_state.CurLenW);
+ edit_state.StbState.select_end = ImMin(edit_state.StbState.select_end, edit_state.CurLenW);
}
if (focus_requested_by_tab || (user_clicked && is_ctrl_down))
select_all = true;
@@ -5520,10 +5660,10 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT
if (g.ActiveId == id)
{
// Edit in progress
- edit_state.BufSize = buf_size < IM_ARRAYSIZE(edit_state.Text) ? buf_size : IM_ARRAYSIZE(edit_state.Text);
+ edit_state.BufSizeA = buf_size;
edit_state.Font = window->Font();
edit_state.FontSize = window->FontSize();
-
+
const float mx = g.IO.MousePos.x - frame_bb.Min.x - style.FramePadding.x;
const float my = window->FontSize()*0.5f; // Flatten mouse because we are doing a single-line edit
@@ -5588,7 +5728,7 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT
if (g.IO.SetClipboardTextFn)
{
const int ib = edit_state.HasSelection() ? ImMin(edit_state.StbState.select_start, edit_state.StbState.select_end) : 0;
- const int ie = edit_state.HasSelection() ? ImMax(edit_state.StbState.select_start, edit_state.StbState.select_end) : (int)ImStrlenW(edit_state.Text);
+ const int ie = edit_state.HasSelection() ? ImMax(edit_state.StbState.select_start, edit_state.StbState.select_end) : edit_state.CurLenW;
ImTextStrToUtf8(text_tmp_utf8, IM_ARRAYSIZE(text_tmp_utf8), edit_state.Text+ib, edit_state.Text+ie);
g.IO.SetClipboardTextFn(text_tmp_utf8);
}
@@ -5604,7 +5744,7 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT
if (const char* clipboard = g.IO.GetClipboardTextFn())
{
// Remove new-line from pasted buffer
- size_t clipboard_len = strlen(clipboard);
+ const size_t clipboard_len = strlen(clipboard);
ImWchar* clipboard_filtered = (ImWchar*)ImGui::MemAlloc((clipboard_len+1) * sizeof(ImWchar));
int clipboard_filtered_len = 0;
for (const char* s = clipboard; *s; )
@@ -5674,22 +5814,22 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT
callback_data.EventFlag = event_flag;
callback_data.EventKey = event_key;
callback_data.Buf = text_tmp_utf8;
- callback_data.BufSize = edit_state.BufSize;
+ callback_data.BufSize = edit_state.BufSizeA;
callback_data.BufDirty = false;
callback_data.Flags = flags;
callback_data.UserData = user_data;
// We have to convert from position from wchar to UTF-8 positions
- const int utf8_cursor_pos = callback_data.CursorPos = ImTextCountUtf8BytesFromWchar(edit_state.Text, edit_state.Text + edit_state.StbState.cursor);
- const int utf8_selection_start = callback_data.SelectionStart = ImTextCountUtf8BytesFromWchar(edit_state.Text, edit_state.Text + edit_state.StbState.select_start);
- const int utf8_selection_end = callback_data.SelectionEnd = ImTextCountUtf8BytesFromWchar(edit_state.Text, edit_state.Text + edit_state.StbState.select_end);
+ const int utf8_cursor_pos = callback_data.CursorPos = ImTextCountUtf8BytesFromStr(edit_state.Text, edit_state.Text + edit_state.StbState.cursor);
+ const int utf8_selection_start = callback_data.SelectionStart = ImTextCountUtf8BytesFromStr(edit_state.Text, edit_state.Text + edit_state.StbState.select_start);
+ const int utf8_selection_end = callback_data.SelectionEnd = ImTextCountUtf8BytesFromStr(edit_state.Text, edit_state.Text + edit_state.StbState.select_end);
// Call user code
callback(&callback_data);
// Read back what user may have modified
IM_ASSERT(callback_data.Buf == text_tmp_utf8); // Invalid to modify those fields
- IM_ASSERT(callback_data.BufSize == edit_state.BufSize);
+ IM_ASSERT(callback_data.BufSize == edit_state.BufSizeA);
IM_ASSERT(callback_data.Flags == flags);
if (callback_data.CursorPos != utf8_cursor_pos) edit_state.StbState.cursor = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.CursorPos);
if (callback_data.SelectionStart != utf8_selection_start) edit_state.StbState.select_start = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionStart);
@@ -6111,7 +6251,7 @@ bool ImGui::ColorButton(const ImVec4& col, bool small_height, bool outline_borde
return false;
const ImGuiStyle& style = g.Style;
- const ImGuiID id = window->GetID("##colorbutton");
+ const ImGuiID id = window->GetID("#colorbutton");
const float square_size = window->FontSize();
const ImGuiAabb bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(square_size + style.FramePadding.x*2, square_size + (small_height ? 0 : style.FramePadding.y*2)));
ItemSize(bb);
@@ -6351,7 +6491,7 @@ static void ItemSize(ImVec2 size, ImVec2* adjust_vertical_offset)
window->DC.CursorPosPrevLine = ImVec2(window->DC.CursorPos.x + size.x, window->DC.CursorPos.y);
window->DC.CursorPos = ImVec2((float)(int)(window->Pos.x + window->DC.ColumnsStartX + window->DC.ColumnsOffsetX), (float)(int)(window->DC.CursorPos.y + line_height + g.Style.ItemSpacing.y));
- window->SizeContentsFit = ImMax(window->SizeContentsFit, ImVec2(window->DC.CursorPosPrevLine.x - window->Pos.x, window->DC.CursorPos.y + window->ScrollY - window->Pos.y));
+ window->SizeContentsCurrent = ImMax(window->SizeContentsCurrent, ImVec2(window->DC.CursorPosPrevLine.x - window->Pos.x, window->DC.CursorPos.y + window->ScrollY - window->Pos.y));
window->DC.PrevLineHeight = line_height;
window->DC.CurrentLineHeight = 0.0f;
@@ -6380,7 +6520,6 @@ bool ImGui::IsClipped(const ImVec2& item_size)
static bool ItemAdd(const ImGuiAabb& bb, const ImGuiID* id)
{
- //ImGuiState& g = *GImGui;
ImGuiWindow* window = GetCurrentWindow();
window->DC.LastItemID = id ? *id : 0;
window->DC.LastItemAabb = bb;
@@ -6458,6 +6597,18 @@ void ImGui::NextColumn()
}
}
+int ImGui::GetColumnIndex()
+{
+ ImGuiWindow* window = GetCurrentWindow();
+ return window->DC.ColumnsCurrent;
+}
+
+int ImGui::GetColumnsCount()
+{
+ ImGuiWindow* window = GetCurrentWindow();
+ return window->DC.ColumnsCount;
+}
+
float ImGui::GetColumnOffset(int column_index)
{
ImGuiState& g = *GImGui;
@@ -6470,7 +6621,7 @@ float ImGui::GetColumnOffset(int column_index)
const float t = window->DC.ColumnsOffsetsT[column_index];
const float min_x = window->DC.ColumnsStartX;
- const float max_x = window->Size.x - (g.Style.ScrollBarWidth);// - window->WindowPadding().x;
+ const float max_x = window->Size.x - (g.Style.ScrollbarWidth);// - window->WindowPadding().x;
const float offset = min_x + t * (max_x - min_x);
return offset;
}
@@ -6486,7 +6637,7 @@ void ImGui::SetColumnOffset(int column_index, float offset)
const ImGuiID column_id = window->DC.ColumnsSetID + ImGuiID(column_index);
const float min_x = window->DC.ColumnsStartX;
- const float max_x = window->Size.x - (g.Style.ScrollBarWidth);// - window->WindowPadding().x;
+ const float max_x = window->Size.x - (g.Style.ScrollbarWidth);// - window->WindowPadding().x;
const float t = (offset - min_x) / (max_x - min_x);
window->DC.StateStorage->SetFloat(column_id, t);
window->DC.ColumnsOffsetsT[column_index] = t;
@@ -7502,7 +7653,7 @@ void ImFontAtlas::RenderCustomTexData()
TexUvWhitePixel = ImVec2((TexExtraDataPos.x + 0.5f) / TexWidth, (TexExtraDataPos.y + 0.5f) / TexHeight);
// Draw a mouse cursor into texture
- // Because our font uses an alpha texture, we have to spread the cursor in 2 parts (black/white) which will be rendered separately.
+ // Because our font uses a single color channel, we have to spread the cursor in 2 layers (black/white) which will be rendered separately.
const char cursor_pixels[] =
{
"X "
@@ -7573,8 +7724,7 @@ const ImWchar* ImFontAtlas::GetGlyphRangesChinese()
static const ImWchar ranges[] =
{
0x0020, 0x00FF, // Basic Latin + Latin Supplement
- 0x3000, 0x3000, // Ideographic Space
- 0x3040, 0x30FF, // Hiragana, Katakana
+ 0x3000, 0x30FF, // Punctuations, Hiragana, Katakana
0x31F0, 0x31FF, // Katakana Phonetic Extensions
0xFF00, 0xFFEF, // Half-width characters
0x4e00, 0x9FAF, // CJK Ideograms
@@ -7623,11 +7773,10 @@ const ImWchar* ImFontAtlas::GetGlyphRangesJapanese()
109,2,18,23,0,0,9,61,3,0,28,41,77,27,19,17,81,5,2,14,5,83,57,252,14,154,263,14,20,8,13,6,57,39,38,
};
static int ranges_unpacked = false;
- static ImWchar ranges[10 + IM_ARRAYSIZE(offsets_from_0x4E00)*2 + 1] =
+ static ImWchar ranges[8 + IM_ARRAYSIZE(offsets_from_0x4E00)*2 + 1] =
{
0x0020, 0x00FF, // Basic Latin + Latin Supplement
- 0x3000, 0x3000, // Ideographic Space
- 0x3040, 0x30FF, // Hiragana, Katakana
+ 0x3000, 0x30FF, // Punctuations, Hiragana, Katakana
0x31F0, 0x31FF, // Katakana Phonetic Extensions
0xFF00, 0xFFEF, // Half-width characters
};
@@ -7635,7 +7784,7 @@ const ImWchar* ImFontAtlas::GetGlyphRangesJapanese()
{
// Unpack
int codepoint = 0x4e00;
- ImWchar* dst = &ranges[10];
+ ImWchar* dst = &ranges[8];
for (int n = 0; n < IM_ARRAYSIZE(offsets_from_0x4E00); n++, dst += 2)
dst[0] = dst[1] = (ImWchar)(codepoint += (offsets_from_0x4E00[n] + 1));
dst[0] = 0;
@@ -7707,6 +7856,7 @@ const ImFont::Glyph* ImFont::FindGlyph(unsigned short c) const
// Convert UTF-8 to 32-bits character, process single character input.
// Based on stb_from_utf8() from github.com/nothings/stb/
+// We handle UTF-8 decoding error by skipping forward.
static int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end)
{
unsigned int c = (unsigned int)-1;
@@ -7719,42 +7869,45 @@ static int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const
}
if ((*str & 0xe0) == 0xc0)
{
- if (in_text_end && in_text_end - (const char*)str < 2) return -1;
- if (*str < 0xc2) return -1;
+ *out_char = 0;
+ if (in_text_end && in_text_end - (const char*)str < 2) return 0;
+ if (*str < 0xc2) return 0;
c = (unsigned int)((*str++ & 0x1f) << 6);
- if ((*str & 0xc0) != 0x80) return -1;
+ if ((*str & 0xc0) != 0x80) return 0;
c += (*str++ & 0x3f);
*out_char = c;
return 2;
}
if ((*str & 0xf0) == 0xe0)
{
- if (in_text_end && in_text_end - (const char*)str < 3) return -1;
- if (*str == 0xe0 && (str[1] < 0xa0 || str[1] > 0xbf)) return -1;
- if (*str == 0xed && str[1] > 0x9f) return -1; // str[1] < 0x80 is checked below
+ *out_char = 0;
+ if (in_text_end && in_text_end - (const char*)str < 3) return 0;
+ if (*str == 0xe0 && (str[1] < 0xa0 || str[1] > 0xbf)) return 0;
+ if (*str == 0xed && str[1] > 0x9f) return 0; // str[1] < 0x80 is checked below
c = (unsigned int)((*str++ & 0x0f) << 12);
- if ((*str & 0xc0) != 0x80) return -1;
+ if ((*str & 0xc0) != 0x80) return 0;
c += (unsigned int)((*str++ & 0x3f) << 6);
- if ((*str & 0xc0) != 0x80) return -1;
+ if ((*str & 0xc0) != 0x80) return 0;
c += (*str++ & 0x3f);
*out_char = c;
return 3;
}
if ((*str & 0xf8) == 0xf0)
{
- if (in_text_end && in_text_end - (const char*)str < 4) return -1;
- if (*str > 0xf4) return -1;
- if (*str == 0xf0 && (str[1] < 0x90 || str[1] > 0xbf)) return -1;
- if (*str == 0xf4 && str[1] > 0x8f) return -1; // str[1] < 0x80 is checked below
+ *out_char = 0;
+ if (in_text_end && in_text_end - (const char*)str < 4) return 0;
+ if (*str > 0xf4) return 0;
+ if (*str == 0xf0 && (str[1] < 0x90 || str[1] > 0xbf)) return 0;
+ if (*str == 0xf4 && str[1] > 0x8f) return 0; // str[1] < 0x80 is checked below
c = (unsigned int)((*str++ & 0x07) << 18);
- if ((*str & 0xc0) != 0x80) return -1;
+ if ((*str & 0xc0) != 0x80) return 0;
c += (unsigned int)((*str++ & 0x3f) << 12);
- if ((*str & 0xc0) != 0x80) return -1;
+ if ((*str & 0xc0) != 0x80) return 0;
c += (unsigned int)((*str++ & 0x3f) << 6);
- if ((*str & 0xc0) != 0x80) return -1;
+ if ((*str & 0xc0) != 0x80) return 0;
c += (*str++ & 0x3f);
// utf-8 encodings of values used in surrogate pairs are invalid
- if ((c & 0xFFFFF800) == 0xD800) return -1;
+ if ((c & 0xFFFFF800) == 0xD800) return 0;
*out_char = c;
return 4;
}
@@ -7762,7 +7915,7 @@ static int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const
return 0;
}
-static ptrdiff_t ImTextStrFromUtf8(ImWchar* buf, size_t buf_size, const char* in_text, const char* in_text_end)
+static ptrdiff_t ImTextStrFromUtf8(ImWchar* buf, size_t buf_size, const char* in_text, const char* in_text_end, const char** in_text_remaining)
{
ImWchar* buf_out = buf;
ImWchar* buf_end = buf + buf_size;
@@ -7770,10 +7923,14 @@ static ptrdiff_t ImTextStrFromUtf8(ImWchar* buf, size_t buf_size, const char* in
{
unsigned int c;
in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
+ if (c == 0)
+ break;
if (c < 0x10000) // FIXME: Losing characters that don't fit in 2 bytes
*buf_out++ = (ImWchar)c;
}
*buf_out = 0;
+ if (in_text_remaining)
+ *in_text_remaining = in_text;
return buf_out - buf;
}
@@ -7784,6 +7941,8 @@ static int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end
{
unsigned int c;
in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
+ if (c == 0)
+ break;
if (c < 0x10000)
char_count++;
}
@@ -7848,7 +8007,7 @@ static ptrdiff_t ImTextStrToUtf8(char* buf, size_t buf_size, const ImWchar* in_t
return buf_out - buf;
}
-static int ImTextCountUtf8BytesFromWchar(const ImWchar* in_text, const ImWchar* in_text_end)
+static int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end)
{
int bytes_count = 0;
while ((!in_text_end || in_text < in_text_end) && *in_text)
@@ -7894,6 +8053,8 @@ const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const c
next_s = s + 1;
else
next_s = s + ImTextCharFromUtf8(&c, s, text_end);
+ if (c == 0)
+ break;
if (c == '\n')
{
@@ -7995,9 +8156,15 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons
// Decode and advance source (handle unlikely UTF-8 decoding failure by skipping to the next byte)
unsigned int c = (unsigned int)*s;
if (c < 0x80)
+ {
s += 1;
+ }
else
+ {
s += ImTextCharFromUtf8(&c, s, text_end);
+ if (c == 0)
+ break;
+ }
if (c == '\n')
{
@@ -8127,9 +8294,15 @@ void ImFont::RenderText(float size, ImVec2 pos, ImU32 col, const ImVec4& clip_re
// Decode and advance source (handle unlikely UTF-8 decoding failure by skipping to the next byte)
unsigned int c = (unsigned int)*s;
if (c < 0x80)
+ {
s += 1;
+ }
else
+ {
s += ImTextCharFromUtf8(&c, s, text_end);
+ if (c == 0)
+ break;
+ }
if (c == '\n')
{
@@ -8227,12 +8400,16 @@ static const char* GetClipboardTextFn_DefaultImpl()
}
if (!OpenClipboard(NULL))
return NULL;
- HANDLE buf_handle = GetClipboardData(CF_TEXT);
- if (buf_handle == NULL)
+ HANDLE wbuf_handle = GetClipboardData(CF_UNICODETEXT);
+ if (wbuf_handle == NULL)
return NULL;
- if (char* buf_global = (char*)GlobalLock(buf_handle))
- buf_local = ImStrdup(buf_global);
- GlobalUnlock(buf_handle);
+ if (ImWchar* wbuf_global = (ImWchar*)GlobalLock(wbuf_handle))
+ {
+ int buf_len = ImTextCountUtf8BytesFromStr(wbuf_global, NULL) + 1;
+ buf_local = (char*)ImGui::MemAlloc(buf_len * sizeof(char));
+ ImTextStrToUtf8(buf_local, buf_len, wbuf_global, NULL);
+ }
+ GlobalUnlock(wbuf_handle);
CloseClipboard();
return buf_local;
}
@@ -8242,17 +8419,16 @@ static void SetClipboardTextFn_DefaultImpl(const char* text)
{
if (!OpenClipboard(NULL))
return;
- const char* text_end = text + strlen(text);
- const int buf_length = (int)(text_end - text) + 1;
- HGLOBAL buf_handle = GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)buf_length * sizeof(char));
- if (buf_handle == NULL)
+
+ const int wbuf_length = ImTextCountCharsFromUtf8(text, NULL) + 1;
+ HGLOBAL wbuf_handle = GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(ImWchar));
+ if (wbuf_handle == NULL)
return;
- char* buf_global = (char *)GlobalLock(buf_handle);
- memcpy(buf_global, text, (size_t)(text_end - text));
- buf_global[text_end - text] = 0;
- GlobalUnlock(buf_handle);
+ ImWchar* wbuf_global = (ImWchar*)GlobalLock(wbuf_handle);
+ ImTextStrFromUtf8(wbuf_global, wbuf_length, text, NULL);
+ GlobalUnlock(wbuf_handle);
EmptyClipboard();
- SetClipboardData(CF_TEXT, buf_handle);
+ SetClipboardData(CF_UNICODETEXT, wbuf_handle);
CloseClipboard();
}
@@ -8370,7 +8546,8 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f");
ImGui::SliderFloat2("TouchExtraPadding", (float*)&style.TouchExtraPadding, 0.0f, 10.0f, "%.0f");
ImGui::SliderFloat("TreeNodeSpacing", &style.TreeNodeSpacing, 0.0f, 20.0f, "%.0f");
- ImGui::SliderFloat("ScrollBarWidth", &style.ScrollBarWidth, 0.0f, 20.0f, "%.0f");
+ ImGui::SliderFloat("ScrollBarWidth", &style.ScrollbarWidth, 1.0f, 20.0f, "%.0f");
+ ImGui::SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f");
ImGui::TreePop();
}
@@ -8441,11 +8618,32 @@ static void ShowExampleAppConsole(bool* opened);
static void ShowExampleAppLongText(bool* opened);
static void ShowExampleAppAutoResize(bool* opened);
static void ShowExampleAppFixedOverlay(bool* opened);
+static void ShowExampleAppManipulatingWindowTitle(bool* opened);
static void ShowExampleAppCustomRendering(bool* opened);
// Demonstrate ImGui features (unfortunately this makes this function a little bloated!)
void ImGui::ShowTestWindow(bool* opened)
{
+ // Examples apps
+ static bool show_app_console = false;
+ static bool show_app_long_text = false;
+ static bool show_app_auto_resize = false;
+ static bool show_app_fixed_overlay = false;
+ static bool show_app_custom_rendering = false;
+ static bool show_app_manipulating_window_title = false;
+ if (show_app_console)
+ ShowExampleAppConsole(&show_app_console);
+ if (show_app_long_text)
+ ShowExampleAppLongText(&show_app_long_text);
+ if (show_app_auto_resize)
+ ShowExampleAppAutoResize(&show_app_auto_resize);
+ if (show_app_fixed_overlay)
+ ShowExampleAppFixedOverlay(&show_app_fixed_overlay);
+ if (show_app_manipulating_window_title)
+ ShowExampleAppManipulatingWindowTitle(&show_app_manipulating_window_title);
+ if (show_app_custom_rendering)
+ ShowExampleAppCustomRendering(&show_app_custom_rendering);
+
static bool no_titlebar = false;
static bool no_border = true;
static bool no_resize = false;
@@ -9150,29 +9348,15 @@ void ImGui::ShowTestWindow(bool* opened)
}
}
- static bool show_app_console = false;
- static bool show_app_long_text = false;
- static bool show_app_auto_resize = false;
- static bool show_app_fixed_overlay = false;
- static bool show_app_custom_rendering = false;
if (ImGui::CollapsingHeader("App Examples"))
{
ImGui::Checkbox("Console", &show_app_console);
ImGui::Checkbox("Long text display", &show_app_long_text);
ImGui::Checkbox("Auto-resizing window", &show_app_auto_resize);
ImGui::Checkbox("Simple overlay", &show_app_fixed_overlay);
+ ImGui::Checkbox("Manipulating window title", &show_app_manipulating_window_title);
ImGui::Checkbox("Custom rendering", &show_app_custom_rendering);
}
- if (show_app_console)
- ShowExampleAppConsole(&show_app_console);
- if (show_app_long_text)
- ShowExampleAppLongText(&show_app_long_text);
- if (show_app_auto_resize)
- ShowExampleAppAutoResize(&show_app_auto_resize);
- if (show_app_fixed_overlay)
- ShowExampleAppFixedOverlay(&show_app_fixed_overlay);
- if (show_app_custom_rendering)
- ShowExampleAppCustomRendering(&show_app_custom_rendering);
ImGui::End();
}
@@ -9210,8 +9394,34 @@ static void ShowExampleAppFixedOverlay(bool* opened)
ImGui::End();
}
+static void ShowExampleAppManipulatingWindowTitle(bool* opened)
+{
+ // By default, Windows are uniquely identified by their title.
+ // You can use the "##" and "###" markers to manipulate the display/ID. Read FAQ at the top of this file!
+
+ // Using "##" to display same title but have unique identifier.
+ ImGui::SetNextWindowPos(ImVec2(100,100), ImGuiSetCond_FirstUseEver);
+ ImGui::Begin("Same title as another window##1");
+ ImGui::Text("This is window 1.\nMy title is the same as window 2, but my identifier is unique.");
+ ImGui::End();
+
+ ImGui::SetNextWindowPos(ImVec2(100,200), ImGuiSetCond_FirstUseEver);
+ ImGui::Begin("Same title as another window##2");
+ ImGui::Text("This is window 2.\nMy title is the same as window 1, but my identifier is unique.");
+ ImGui::End();
+
+ // Using "###" to display a changing title but keep a static identifier "MyWindow"
+ char buf[128];
+ ImFormatString(buf, IM_ARRAYSIZE(buf), "Animated title %c %d###MyWindow", "|/-\\"[(int)(ImGui::GetTime()/0.25f)&3], rand());
+ ImGui::SetNextWindowPos(ImVec2(100,300), ImGuiSetCond_FirstUseEver);
+ ImGui::Begin(buf);
+ ImGui::Text("This window has a changing title.");
+ ImGui::End();
+}
+
static void ShowExampleAppCustomRendering(bool* opened)
{
+ ImGui::SetNextWindowSize(ImVec2(300,350), ImGuiSetCond_FirstUseEver);
if (!ImGui::Begin("Example: Custom Rendering", opened))
{
ImGui::End();
@@ -9226,7 +9436,7 @@ static void ShowExampleAppCustomRendering(bool* opened)
static ImVector points;
static bool adding_line = false;
if (ImGui::Button("Clear")) points.clear();
- if (points.size() > 2) { ImGui::SameLine(); if (ImGui::Button("Undo")) points.pop_back(); }
+ if (points.size() >= 2) { ImGui::SameLine(); if (ImGui::Button("Undo")) { points.pop_back(); points.pop_back(); } }
ImGui::Text("Left-click and drag to add lines");
ImGui::Text("Right-click to undo");
@@ -9332,6 +9542,8 @@ struct ExampleAppConsole
if (ImGui::SmallButton("Add Dummy Text")) { AddLog("%d some text", Items.size()); AddLog("some more text"); AddLog("display very important message here!"); } ImGui::SameLine();
if (ImGui::SmallButton("Add Dummy Error")) AddLog("[error] something went wrong"); ImGui::SameLine();
if (ImGui::SmallButton("Clear")) ClearLog();
+ //static float t = 0.0f; if (ImGui::GetTime() - t > 0.02f) { t = ImGui::GetTime(); AddLog("Spam %f", t); }
+
ImGui::Separator();
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0,0));
diff --git a/imgui.h b/imgui.h
index dfa5233f..6a009758 100644
--- a/imgui.h
+++ b/imgui.h
@@ -1,4 +1,4 @@
-// ImGui library v1.35 wip
+// ImGui library v1.35
// See .cpp file for documentation.
// See ImGui::ShowTestWindow() for sample code.
// Read 'Programmer guide' in .cpp for notes on how to setup ImGui in your codebase.
@@ -6,17 +6,7 @@
#pragma once
-struct ImDrawCmd;
-struct ImDrawList;
-struct ImFont;
-struct ImFontAtlas;
-struct ImGuiAabb;
-struct ImGuiIO;
-struct ImGuiStorage;
-struct ImGuiStyle;
-struct ImGuiWindow;
-
-#include "imconfig.h"
+#include "imconfig.h" // User-editable configuration file
#include // FLT_MAX
#include // va_list
#include // ptrdiff_t
@@ -34,6 +24,15 @@ struct ImGuiWindow;
#define IMGUI_API
#endif
+// Forward declarations
+struct ImDrawCmd;
+struct ImDrawList;
+struct ImFont;
+struct ImFontAtlas;
+struct ImGuiIO;
+struct ImGuiStorage;
+struct ImGuiStyle;
+
typedef unsigned int ImU32;
typedef unsigned short ImWchar; // character for display
typedef void* ImTextureID; // user data to refer to a texture (e.g. store your texture handle/id)
@@ -191,6 +190,8 @@ namespace ImGui
IMGUI_API void SetWindowCollapsed(const char* name, bool collapsed, ImGuiSetCond cond = 0); // set named window collapsed state.
IMGUI_API void SetWindowFocus(const char* name); // set named window to be focused / front-most
+ IMGUI_API float GetScrollPosY(); // get scrolling position (0..GetScrollMaxY())
+ IMGUI_API float GetScrollMaxY(); // get maximum scrolling position == ContentSize.Y - WindowSize.Y
IMGUI_API void SetScrollPosHere(); // adjust scrolling position to center into the current cursor position.
IMGUI_API void SetKeyboardFocusHere(int offset = 0); // focus keyboard on the next widget. Use positive 'offset' to access sub components of a multiple component widget.
IMGUI_API void SetStateStorage(ImGuiStorage* tree); // replace tree state storage with our own (if you want to manipulate it yourself, typically clear subsection of it).
@@ -226,9 +227,11 @@ namespace ImGui
IMGUI_API void Spacing();
IMGUI_API void Columns(int count = 1, const char* id = NULL, bool border=true); // setup number of columns
IMGUI_API void NextColumn(); // next column
- IMGUI_API float GetColumnOffset(int column_index = -1);
- IMGUI_API void SetColumnOffset(int column_index, float offset);
- IMGUI_API float GetColumnWidth(int column_index = -1);
+ IMGUI_API int GetColumnIndex(); // get current column index
+ IMGUI_API float GetColumnOffset(int column_index = -1); // get position of column line (in pixels, from the left side of the contents region). pass -1 to use current column, otherwise 0..GetcolumnsCount() inclusive. column 0 is usually 0.0f and not resizable unless you call this.
+ IMGUI_API void SetColumnOffset(int column_index, float offset_x); // set position of column line (in pixels, from the left side of the contents region). pass -1 to use current column.
+ IMGUI_API float GetColumnWidth(int column_index = -1); // column width (== GetColumnOffset(GetColumnIndex()+1) - GetColumnOffset(GetColumnOffset())
+ IMGUI_API int GetColumnsCount(); // number of columns (what was passed to Columns())
IMGUI_API ImVec2 GetCursorPos(); // cursor position is relative to window position
IMGUI_API float GetCursorPosX(); // "
IMGUI_API float GetCursorPosY(); // "
@@ -383,7 +386,7 @@ enum ImGuiWindowFlags_
ImGuiWindowFlags_NoTitleBar = 1 << 0, // Disable title-bar
ImGuiWindowFlags_NoResize = 1 << 1, // Disable user resizing with the lower-right grip
ImGuiWindowFlags_NoMove = 1 << 2, // Disable user moving the window
- ImGuiWindowFlags_NoScrollbar = 1 << 3, // Disable scroll bar (window can still scroll with mouse or programatically)
+ ImGuiWindowFlags_NoScrollbar = 1 << 3, // Disable scrollbar (window can still scroll with mouse or programatically)
ImGuiWindowFlags_NoScrollWithMouse = 1 << 4, // Disable user scrolling with mouse wheel
ImGuiWindowFlags_NoCollapse = 1 << 5, // Disable user collapsing window by double-clicking on it
ImGuiWindowFlags_AlwaysAutoResize = 1 << 6, // Resize every window to its content every frame
@@ -531,7 +534,8 @@ struct ImGuiStyle
float WindowFillAlphaDefault; // Default alpha of window background, if not specified in ImGui::Begin()
float TreeNodeSpacing; // Horizontal spacing when entering a tree node
float ColumnsMinSpacing; // Minimum horizontal spacing between two columns
- float ScrollBarWidth; // Width of the vertical scroll bar
+ float ScrollbarWidth; // Width of the vertical scrollbar
+ float GrabMinSize; // Minimum width/height of a slider or scrollbar grab
ImVec4 Colors[ImGuiCol_COUNT];
IMGUI_API ImGuiStyle();