diff --git a/backends/imgui_impl_win32.cpp b/backends/imgui_impl_win32.cpp
index 70c29f268..363e016d8 100644
--- a/backends/imgui_impl_win32.cpp
+++ b/backends/imgui_impl_win32.cpp
@@ -35,6 +35,7 @@ typedef DWORD (WINAPI *PFN_XInputGetState)(DWORD, XINPUT_STATE*);
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
+// 2023-04-19: Added ImGui_ImplWin32_InitForOpenGL() to facilitate combining raw Win32/Winapi with OpenGL. (#3218)
// 2023-04-04: Inputs: Added support for io.AddMouseSourceEvent() to discriminate ImGuiMouseSource_Mouse/ImGuiMouseSource_TouchScreen/ImGuiMouseSource_Pen. (#2702)
// 2023-02-15: Inputs: Use WM_NCMOUSEMOVE / WM_NCMOUSELEAVE to track mouse position over non-client area (e.g. OS decorations) when app is not focused. (#6045, #6162)
// 2023-02-02: Inputs: Flipping WM_MOUSEHWHEEL (horizontal mouse-wheel) value to match other backends and offer consistent horizontal scrolling direction. (#4019, #6096, #1463)
@@ -114,7 +115,7 @@ static ImGui_ImplWin32_Data* ImGui_ImplWin32_GetBackendData()
}
// Functions
-static bool ImGui_ImplWin32_Init(void* hwnd, bool platformHasOwnDC)
+static bool ImGui_ImplWin32_InitEx(void* hwnd, bool platform_has_own_dc)
{
ImGuiIO& io = ImGui::GetIO();
IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!");
@@ -139,7 +140,7 @@ static bool ImGui_ImplWin32_Init(void* hwnd, bool platformHasOwnDC)
// Set platform dependent data in viewport
ImGui::GetMainViewport()->PlatformHandleRaw = (void*)hwnd;
- IM_UNUSED(platformHasOwnDC); // Used in 'docking' branch
+ IM_UNUSED(platform_has_own_dc); // Used in 'docking' branch
// Dynamically load XInput library
#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
@@ -167,13 +168,13 @@ static bool ImGui_ImplWin32_Init(void* hwnd, bool platformHasOwnDC)
IMGUI_IMPL_API bool ImGui_ImplWin32_Init(void* hwnd)
{
- return ImGui_ImplWin32_Init(hwnd, false);
+ return ImGui_ImplWin32_InitEx(hwnd, false);
}
IMGUI_IMPL_API bool ImGui_ImplWin32_InitForOpenGL(void* hwnd)
{
// OpenGL needs CS_OWNDC
- return ImGui_ImplWin32_Init(hwnd, true);
+ return ImGui_ImplWin32_InitEx(hwnd, true);
}
void ImGui_ImplWin32_Shutdown()
diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt
index d8d85e674..a887cb5a0 100644
--- a/docs/CHANGELOG.txt
+++ b/docs/CHANGELOG.txt
@@ -48,8 +48,12 @@ Other changes:
(#6341) [@lukaasm]
- Backends: Clear bits sets io.BackendFlags on backend Shutdown(). (#6334, #6335] [@GereonV]
Potentially this would facilitate switching runtime backend mid-session.
+- Backends: Win32: Added ImGui_ImplWin32_InitForOpenGL() to facilitate combining raw
+ Win32/Winapi with OpenGL. (#3218)
- Backends: OpenGL3: Restore front and back polygon mode separately when supported
by context (Desktop 3.0, 3.1, or 3.2+ with compat bit). (#6333) [@GereonV]
+- Examples: Added native Win32+OpenGL3 example. We don't recommend using this setup but we
+ provide it for completeness. (#3218, #5170, #6086, #2772, #2600, #2359, #2022, #1553) [@learn-more]
diff --git a/docs/EXAMPLES.md b/docs/EXAMPLES.md
index d6d1bb650..42ff47850 100644
--- a/docs/EXAMPLES.md
+++ b/docs/EXAMPLES.md
@@ -200,6 +200,10 @@ DirectX12 example, Windows only.
= main.cpp + imgui_impl_win32.cpp + imgui_impl_dx12.cpp
This is quite long and tedious, because: DirectX12.
+[example_win32_opengl3/](https://github.com/ocornut/imgui/blob/master/examples/example_win32_opengl3/)
+Raw Windows + OpenGL3 + example (modern, programmable pipeline)
+= main.cpp + imgui_impl_win32.cpp + imgui_impl_opengl3.cpp
+
### Miscellaneous
diff --git a/examples/example_win32_opengl3/main.cpp b/examples/example_win32_opengl3/main.cpp
index d35160748..7b89a0a12 100644
--- a/examples/example_win32_opengl3/main.cpp
+++ b/examples/example_win32_opengl3/main.cpp
@@ -1,28 +1,32 @@
-// dear imgui: standalone example application for OpenGL3 with Winapi
-// If you are new to dear imgui, see examples/README.txt and documentation at the top of imgui.cpp.
+// Dear ImGui: standalone example application for Win32 + OpenGL 3
+// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
+// Read online: https://github.com/ocornut/imgui/tree/master/docs
+
+// This is provided for completeness, however it is strogly recommended you use OpenGL with SDL or GLFW.
#include "imgui.h"
#include "imgui_impl_opengl3.h"
#include "imgui_impl_win32.h"
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
#include
#include
#include
// Data stored per platform window
-struct RendererData
-{
- HDC hDC;
-};
+struct WGL_WindowData { HDC hDC; };
// Data
-HGLRC g_hRC;
-RendererData g_MainWindow;
-static int g_Width;
-static int g_Height;
+static HGLRC g_hRC;
+static WGL_WindowData g_MainWindow;
+static int g_Width;
+static int g_Height;
// Forward declarations of helper functions
-static bool CreateDeviceOpenGL3(HWND hWnd, RendererData* data);
-static void CleanupDeviceOpenGL3(HWND hWnd, RendererData* data);
+bool CreateDeviceWGL(HWND hWnd, WGL_WindowData* data);
+void CleanupDeviceWGL(HWND hWnd, WGL_WindowData* data);
+void ResetDeviceWGL();
LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
// Main code
@@ -30,19 +34,18 @@ int main(int, char**)
{
// Create application window
//ImGui_ImplWin32_EnableDpiAwareness();
- WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_OWNDC, WndProc, 0L, 0L, GetModuleHandle(NULL), NULL, NULL, NULL, NULL, _T("ImGui Example"), NULL };
- ::RegisterClassEx(&wc);
- HWND hwnd = ::CreateWindow(wc.lpszClassName, _T("Dear ImGui Winapi+OpenGL3 Example"), WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL);
+ WNDCLASSEXW wc = { sizeof(wc), CS_OWNDC, WndProc, 0L, 0L, GetModuleHandle(NULL), NULL, NULL, NULL, NULL, L"ImGui Example", NULL };
+ ::RegisterClassExW(&wc);
+ HWND hwnd = ::CreateWindowW(wc.lpszClassName, L"Dear ImGui Win32+OpenGL3 Example", WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL);
- // Initialize OpenGL3
- if (!CreateDeviceOpenGL3(hwnd, &g_MainWindow))
+ // Initialize OpenGL
+ if (!CreateDeviceWGL(hwnd, &g_MainWindow))
{
- CleanupDeviceOpenGL3(hwnd, &g_MainWindow);
+ CleanupDeviceWGL(hwnd, &g_MainWindow);
::DestroyWindow(hwnd);
- ::UnregisterClass(wc.lpszClassName, wc.hInstance);
+ ::UnregisterClassW(wc.lpszClassName, wc.hInstance);
return 1;
}
-
wglMakeCurrent(g_MainWindow.hDC, g_hRC);
// Show the window
@@ -60,7 +63,7 @@ int main(int, char**)
ImGui::StyleColorsDark();
//ImGui::StyleColorsClassic();
- // Setup Platform/Renderer bindings
+ // Setup Platform/Renderer backends
ImGui_ImplWin32_InitForOpenGL(hwnd);
ImGui_ImplOpenGL3_Init();
@@ -69,13 +72,14 @@ int main(int, char**)
// - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
// - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit).
// - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call.
+ // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering.
// - Read 'docs/FONTS.md' for more instructions and details.
// - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ !
//io.Fonts->AddFontDefault();
+ //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f);
+ //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f);
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f);
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f);
- //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f);
- //io.Fonts->AddFontFromFileTTF("../../misc/fonts/ProggyTiny.ttf", 10.0f);
//ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, NULL, io.Fonts->GetGlyphRangesJapanese());
//IM_ASSERT(font != NULL);
@@ -85,21 +89,21 @@ int main(int, char**)
ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
// Main loop
- MSG msg;
- ZeroMemory(&msg, sizeof(msg));
- while (msg.message != WM_QUIT)
+ bool done = false;
+ while (!done)
{
// Poll and handle messages (inputs, window resize, etc.)
- // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
- // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application.
- // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
- // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
- if (::PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
+ // See the WndProc() function below for our to dispatch events to the Win32 backend.
+ MSG msg;
+ while (::PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
- continue;
+ if (msg.message == WM_QUIT)
+ done = true;
}
+ if (done)
+ break;
// Start the Dear ImGui frame
ImGui_ImplOpenGL3_NewFrame();
@@ -110,7 +114,7 @@ int main(int, char**)
if (show_demo_window)
ImGui::ShowDemoWindow(&show_demo_window);
- // 2. Show a simple window that we create ourselves. We use a Begin/End pair to created a named window.
+ // 2. Show a simple window that we create ourselves. We use a Begin/End pair to create a named window.
{
static float f = 0.0f;
static int counter = 0;
@@ -129,7 +133,7 @@ int main(int, char**)
ImGui::SameLine();
ImGui::Text("counter = %d", counter);
- ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
+ ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
ImGui::End();
}
@@ -148,84 +152,62 @@ int main(int, char**)
glViewport(0, 0, g_Width, g_Height);
glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w);
glClear(GL_COLOR_BUFFER_BIT);
-
- // If you are using this code with non-legacy OpenGL header/contexts (which you should not, prefer using imgui_impl_opengl3.cpp!!),
- // you may need to backup/reset/restore current shader using the commented lines below.
- //GLint last_program;
- //glGetIntegerv(GL_CURRENT_PROGRAM, &last_program);
- //glUseProgram(0);
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
- //glUseProgram(last_program);
- SwapBuffers(g_MainWindow.hDC);
+ // Present
+ ::SwapBuffers(g_MainWindow.hDC);
}
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplWin32_Shutdown();
ImGui::DestroyContext();
- CleanupDeviceOpenGL3(hwnd, &g_MainWindow);
+ CleanupDeviceWGL(hwnd, &g_MainWindow);
wglDeleteContext(g_hRC);
::DestroyWindow(hwnd);
- ::UnregisterClass(wc.lpszClassName, wc.hInstance);
+ ::UnregisterClassW(wc.lpszClassName, wc.hInstance);
return 0;
}
-static bool ActivateOpenGL3(HWND hWnd)
+// Helper functions
+bool CreateDeviceWGL(HWND hWnd, WGL_WindowData* data)
{
- HDC hDc = GetDC(hWnd);
-
+ HDC hDc = ::GetDC(hWnd);
PIXELFORMATDESCRIPTOR pfd = { 0 };
-
pfd.nSize = sizeof(pfd);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32;
- int pf = ChoosePixelFormat(hDc, &pfd);
+ const int pf = ::ChoosePixelFormat(hDc, &pfd);
if (pf == 0)
- {
return false;
- }
-
- if (SetPixelFormat(hDc, pf, &pfd) == FALSE)
- {
+ if (::SetPixelFormat(hDc, pf, &pfd) == FALSE)
return false;
- }
-
- ReleaseDC(hWnd, hDc);
- return true;
-}
-
-// Helper functions
-
-static bool CreateDeviceOpenGL3(HWND hWnd, RendererData* data)
-{
- if (!ActivateOpenGL3(hWnd))
- return false;
-
- data->hDC = GetDC(hWnd);
+ ::ReleaseDC(hWnd, hDc);
+ data->hDC = ::GetDC(hWnd);
if (!g_hRC)
- {
g_hRC = wglCreateContext(data->hDC);
- }
-
return true;
}
-static void CleanupDeviceOpenGL3(HWND hWnd, RendererData* data)
+void CleanupDeviceWGL(HWND hWnd, WGL_WindowData* data)
{
wglMakeCurrent(NULL, NULL);
- ReleaseDC(hWnd, data->hDC);
+ ::ReleaseDC(hWnd, data->hDC);
}
// Forward declare message handler from imgui_impl_win32.cpp
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
// Win32 message handler
+// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
+// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data.
+// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data.
+// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam))