Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Viewports for win32+opengl backend (fix #2600) #5170

Closed
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 97 additions & 3 deletions backends/imgui_impl_win32.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@
#include <tchar.h>
#include <dwmapi.h>

// Stuff for loading WGL functions explicitly
#include <cstdlib> // atexit()
static HMODULE libgl;
theOtherMichael marked this conversation as resolved.
Show resolved Hide resolved
HGLRC (WINAPI* _wglCreateContext)(HDC);
theOtherMichael marked this conversation as resolved.
Show resolved Hide resolved
BOOL (WINAPI* _wglDeleteContext)(HGLRC);
BOOL (WINAPI* _wglMakeCurrent)(HDC, HGLRC);
BOOL (WINAPI* _wglShareLists)(HGLRC, HGLRC);

// Configuration flags to add in your imconfig.h file:
//#define IMGUI_IMPL_WIN32_DISABLE_GAMEPAD // Disable gamepad support. This was meaningful before <1.81 but we now load XInput dynamically so the option is now less relevant.

Expand Down Expand Up @@ -82,10 +90,14 @@ typedef DWORD (WINAPI *PFN_XInputGetState)(DWORD, XINPUT_STATE*);
static void ImGui_ImplWin32_InitPlatformInterface();
static void ImGui_ImplWin32_ShutdownPlatformInterface();
static void ImGui_ImplWin32_UpdateMonitors();
static void ImGui_ImplWin32_SetWindowFocus(ImGuiViewport* viewport);
static void ImGui_ImplWin32_ShowWindow(ImGuiViewport* viewport);

struct ImGui_ImplWin32_Data
{
HWND hWnd;
HDC Hdc;
HGLRC HgLrc;
theOtherMichael marked this conversation as resolved.
Show resolved Hide resolved
HWND MouseHwnd;
bool MouseTracked;
int MouseButtonsDown;
Expand Down Expand Up @@ -115,7 +127,7 @@ static ImGui_ImplWin32_Data* ImGui_ImplWin32_GetBackendData()
}

// Functions
bool ImGui_ImplWin32_Init(void* hwnd)
bool ImGui_ImplWin32_Init(void* hwnd, void* hglrc)
{
ImGuiIO& io = ImGui::GetIO();
IM_ASSERT(io.BackendPlatformUserData == NULL && "Already initialized a platform backend!");
Expand All @@ -126,6 +138,25 @@ bool ImGui_ImplWin32_Init(void* hwnd)
if (!::QueryPerformanceCounter((LARGE_INTEGER*)&perf_counter))
return false;

// Load WGL symbols explicitly
// This is needed to allow compilation if and when non-OpenGL APIs are used with Win32.
// The function pointer names are preceded with an underscore ("_") to prevent duplicate
// symbols in projects where OpenGL32.dll is linked implicitly.
if (hglrc)
theOtherMichael marked this conversation as resolved.
Show resolved Hide resolved
{
libgl = LoadLibraryA("opengl32.dll");
theOtherMichael marked this conversation as resolved.
Show resolved Hide resolved
IM_ASSERT(libgl);
_wglCreateContext = (HGLRC(WINAPI*)(HDC))GetProcAddress(libgl, "wglCreateContext");
_wglDeleteContext = (BOOL(WINAPI*)(HGLRC))GetProcAddress(libgl, "wglDeleteContext");
_wglMakeCurrent = (BOOL(WINAPI*)(HDC, HGLRC))GetProcAddress(libgl, "wglMakeCurrent");
_wglShareLists = (BOOL(WINAPI*)(HGLRC, HGLRC))GetProcAddress(libgl, "wglShareLists");
IM_ASSERT(_wglCreateContext);
IM_ASSERT(_wglDeleteContext);
IM_ASSERT(_wglMakeCurrent);
IM_ASSERT(_wglShareLists);
atexit([](){ FreeLibrary(libgl); });
theOtherMichael marked this conversation as resolved.
Show resolved Hide resolved
}

// Setup backend capabilities flags
ImGui_ImplWin32_Data* bd = IM_NEW(ImGui_ImplWin32_Data)();
io.BackendPlatformUserData = (void*)bd;
Expand All @@ -136,6 +167,8 @@ bool ImGui_ImplWin32_Init(void* hwnd)
io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; // We can call io.AddMouseViewportEvent() with correct data (optional)

bd->hWnd = (HWND)hwnd;
bd->Hdc = GetDC(bd->hWnd);
theOtherMichael marked this conversation as resolved.
Show resolved Hide resolved
bd->HgLrc = (HGLRC)hglrc; // OpenGL
bd->WantUpdateHasGamepad = true;
bd->WantUpdateMonitors = true;
bd->TicksPerSecond = perf_frequency;
Expand Down Expand Up @@ -843,10 +876,20 @@ struct ImGui_ImplWin32_ViewportData
{
HWND Hwnd;
bool HwndOwned;
HDC Hdc;
HGLRC HgLrc;
DWORD DwStyle;
DWORD DwExStyle;

ImGui_ImplWin32_ViewportData() { Hwnd = NULL; HwndOwned = false; DwStyle = DwExStyle = 0; }
ImGui_ImplWin32_ViewportData()
{
Hwnd = NULL;
HwndOwned = false;
Hdc = NULL;
HgLrc = NULL;
DwStyle = 0;
DwExStyle = 0;
}
~ImGui_ImplWin32_ViewportData() { IM_ASSERT(Hwnd == NULL); }
};

Expand Down Expand Up @@ -886,8 +929,28 @@ static void ImGui_ImplWin32_CreateWindow(ImGuiViewport* viewport)
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, // Window area
parent_window, NULL, ::GetModuleHandle(NULL), NULL); // Parent window, Menu, Instance, Param
vd->HwndOwned = true;
vd->Hdc = GetDC(vd->Hwnd);
viewport->PlatformRequestResize = false;
viewport->PlatformHandle = viewport->PlatformHandleRaw = vd->Hwnd;

ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
if (bd->HgLrc) // OpenGL
{
// Use the main window's pixel format
int pf = GetPixelFormat(bd->Hdc);
PIXELFORMATDESCRIPTOR pfd;
DescribePixelFormat(bd->Hdc, pf, sizeof(pfd), &pfd);
SetPixelFormat(vd->Hdc, pf, &pfd);

// Create OpenGL context and share main context's lists with it
vd->HgLrc = _wglCreateContext(vd->Hdc);
_wglMakeCurrent(vd->Hdc, vd->HgLrc);
_wglShareLists(bd->HgLrc, vd->HgLrc);

// Present window
theOtherMichael marked this conversation as resolved.
Show resolved Hide resolved
ImGui_ImplWin32_SetWindowFocus(viewport);
ImGui_ImplWin32_ShowWindow(viewport);
}
}

static void ImGui_ImplWin32_DestroyWindow(ImGuiViewport* viewport)
Expand All @@ -902,7 +965,12 @@ static void ImGui_ImplWin32_DestroyWindow(ImGuiViewport* viewport)
::SetCapture(bd->hWnd);
}
if (vd->Hwnd && vd->HwndOwned)
{
if (vd->HgLrc)
_wglDeleteContext(vd->HgLrc);
theOtherMichael marked this conversation as resolved.
Show resolved Hide resolved

::DestroyWindow(vd->Hwnd);
}
vd->Hwnd = NULL;
IM_DELETE(vd);
}
Expand Down Expand Up @@ -1062,6 +1130,21 @@ static void ImGui_ImplWin32_OnChangedViewport(ImGuiViewport* viewport)
#endif
}

static void ImGui_ImplWin32_OGL_RenderWindow(ImGuiViewport* viewport, void*)
{
ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
IM_ASSERT(vd->HgLrc); // ImGui_ImplWin32_OGL_RenderWindow() is only registered if API is OpenGL
_wglMakeCurrent(vd->Hdc, vd->HgLrc);
}

static void ImGui_ImplWin32_OGL_SwapBuffers(ImGuiViewport* viewport, void*)
{
ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
IM_ASSERT(vd->HgLrc); // ImGui_ImplWin32_OGL_SwapBuffers() is only registered if API is OpenGL
_wglMakeCurrent(vd->Hdc, vd->HgLrc);
SwapBuffers(vd->Hdc);
}

static LRESULT CALLBACK ImGui_ImplWin32_WndProcHandler_PlatformWindow(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam))
Expand All @@ -1071,6 +1154,9 @@ static LRESULT CALLBACK ImGui_ImplWin32_WndProcHandler_PlatformWindow(HWND hWnd,
{
switch (msg)
{
case WM_ERASEBKGND:
// Prevent flickering on window invalidation
return TRUE;
case WM_CLOSE:
viewport->PlatformRequestClose = true;
return 0;
Expand Down Expand Up @@ -1134,14 +1220,22 @@ static void ImGui_ImplWin32_InitPlatformInterface()
platform_io.Platform_UpdateWindow = ImGui_ImplWin32_UpdateWindow;
platform_io.Platform_GetWindowDpiScale = ImGui_ImplWin32_GetWindowDpiScale; // FIXME-DPI
platform_io.Platform_OnChangedViewport = ImGui_ImplWin32_OnChangedViewport; // FIXME-DPI

ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
if (bd->HgLrc) // OpenGL
{
platform_io.Platform_RenderWindow = ImGui_ImplWin32_OGL_RenderWindow;
platform_io.Platform_SwapBuffers = ImGui_ImplWin32_OGL_SwapBuffers;
}

// Register main window handle (which is owned by the main application, not by us)
// This is mostly for simplicity and consistency, so that our code (e.g. mouse handling etc.) can use same logic for main and secondary viewports.
ImGuiViewport* main_viewport = ImGui::GetMainViewport();
ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
ImGui_ImplWin32_ViewportData* vd = IM_NEW(ImGui_ImplWin32_ViewportData)();
vd->Hwnd = bd->hWnd;
vd->HwndOwned = false;
vd->Hdc = bd->Hdc;
vd->HgLrc = bd->HgLrc; // OpenGL
main_viewport->PlatformUserData = vd;
main_viewport->PlatformHandle = (void*)bd->hWnd;
}
Expand Down
2 changes: 1 addition & 1 deletion backends/imgui_impl_win32.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
#pragma once
#include "imgui.h" // IMGUI_IMPL_API

IMGUI_IMPL_API bool ImGui_ImplWin32_Init(void* hwnd);
IMGUI_IMPL_API bool ImGui_ImplWin32_Init(void* hwnd, void* hglrc = NULL);
theOtherMichael marked this conversation as resolved.
Show resolved Hide resolved
IMGUI_IMPL_API void ImGui_ImplWin32_Shutdown();
IMGUI_IMPL_API void ImGui_ImplWin32_NewFrame();

Expand Down