Examples: Amend Win32/Winapi + OpenGL example. (#3218, #5170 and #6086, #2772, #2600, #2359, #2022, #1553)

This commit is contained in:
ocornut 2023-04-19 15:57:38 +02:00
parent a566ecc58f
commit 9308cfdcfb
4 changed files with 68 additions and 77 deletions

View File

@ -35,6 +35,7 @@ typedef DWORD (WINAPI *PFN_XInputGetState)(DWORD, XINPUT_STATE*);
// CHANGELOG // CHANGELOG
// (minor and older changes stripped away, please see git history for details) // (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-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-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) // 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 // 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(); ImGuiIO& io = ImGui::GetIO();
IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!"); 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 // Set platform dependent data in viewport
ImGui::GetMainViewport()->PlatformHandleRaw = (void*)hwnd; 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 // Dynamically load XInput library
#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD #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) 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) IMGUI_IMPL_API bool ImGui_ImplWin32_InitForOpenGL(void* hwnd)
{ {
// OpenGL needs CS_OWNDC // OpenGL needs CS_OWNDC
return ImGui_ImplWin32_Init(hwnd, true); return ImGui_ImplWin32_InitEx(hwnd, true);
} }
void ImGui_ImplWin32_Shutdown() void ImGui_ImplWin32_Shutdown()

View File

@ -48,8 +48,12 @@ Other changes:
(#6341) [@lukaasm] (#6341) [@lukaasm]
- Backends: Clear bits sets io.BackendFlags on backend Shutdown(). (#6334, #6335] [@GereonV] - Backends: Clear bits sets io.BackendFlags on backend Shutdown(). (#6334, #6335] [@GereonV]
Potentially this would facilitate switching runtime backend mid-session. 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 - 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] 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]

View File

@ -200,6 +200,10 @@ DirectX12 example, Windows only. <BR>
= main.cpp + imgui_impl_win32.cpp + imgui_impl_dx12.cpp <BR> = main.cpp + imgui_impl_win32.cpp + imgui_impl_dx12.cpp <BR>
This is quite long and tedious, because: DirectX12. This is quite long and tedious, because: DirectX12.
[example_win32_opengl3/](https://github.com/ocornut/imgui/blob/master/examples/example_win32_opengl3/) <BR>
Raw Windows + OpenGL3 + example (modern, programmable pipeline) <BR>
= main.cpp + imgui_impl_win32.cpp + imgui_impl_opengl3.cpp <BR>
### Miscellaneous ### Miscellaneous

View File

@ -1,28 +1,32 @@
// dear imgui: standalone example application for OpenGL3 with Winapi // Dear ImGui: standalone example application for Win32 + OpenGL 3
// If you are new to dear imgui, see examples/README.txt and documentation at the top of imgui.cpp. // 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.h"
#include "imgui_impl_opengl3.h" #include "imgui_impl_opengl3.h"
#include "imgui_impl_win32.h" #include "imgui_impl_win32.h"
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h> #include <windows.h>
#include <GL/GL.h> #include <GL/GL.h>
#include <tchar.h> #include <tchar.h>
// Data stored per platform window // Data stored per platform window
struct RendererData struct WGL_WindowData { HDC hDC; };
{
HDC hDC;
};
// Data // Data
HGLRC g_hRC; static HGLRC g_hRC;
RendererData g_MainWindow; static WGL_WindowData g_MainWindow;
static int g_Width; static int g_Width;
static int g_Height; static int g_Height;
// Forward declarations of helper functions // Forward declarations of helper functions
static bool CreateDeviceOpenGL3(HWND hWnd, RendererData* data); bool CreateDeviceWGL(HWND hWnd, WGL_WindowData* data);
static void CleanupDeviceOpenGL3(HWND hWnd, RendererData* data); void CleanupDeviceWGL(HWND hWnd, WGL_WindowData* data);
void ResetDeviceWGL();
LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
// Main code // Main code
@ -30,19 +34,18 @@ int main(int, char**)
{ {
// Create application window // Create application window
//ImGui_ImplWin32_EnableDpiAwareness(); //ImGui_ImplWin32_EnableDpiAwareness();
WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_OWNDC, WndProc, 0L, 0L, GetModuleHandle(NULL), NULL, NULL, NULL, NULL, _T("ImGui Example"), NULL }; WNDCLASSEXW wc = { sizeof(wc), CS_OWNDC, WndProc, 0L, 0L, GetModuleHandle(NULL), NULL, NULL, NULL, NULL, L"ImGui Example", NULL };
::RegisterClassEx(&wc); ::RegisterClassExW(&wc);
HWND hwnd = ::CreateWindow(wc.lpszClassName, _T("Dear ImGui Winapi+OpenGL3 Example"), WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL); HWND hwnd = ::CreateWindowW(wc.lpszClassName, L"Dear ImGui Win32+OpenGL3 Example", WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL);
// Initialize OpenGL3 // Initialize OpenGL
if (!CreateDeviceOpenGL3(hwnd, &g_MainWindow)) if (!CreateDeviceWGL(hwnd, &g_MainWindow))
{ {
CleanupDeviceOpenGL3(hwnd, &g_MainWindow); CleanupDeviceWGL(hwnd, &g_MainWindow);
::DestroyWindow(hwnd); ::DestroyWindow(hwnd);
::UnregisterClass(wc.lpszClassName, wc.hInstance); ::UnregisterClassW(wc.lpszClassName, wc.hInstance);
return 1; return 1;
} }
wglMakeCurrent(g_MainWindow.hDC, g_hRC); wglMakeCurrent(g_MainWindow.hDC, g_hRC);
// Show the window // Show the window
@ -60,7 +63,7 @@ int main(int, char**)
ImGui::StyleColorsDark(); ImGui::StyleColorsDark();
//ImGui::StyleColorsClassic(); //ImGui::StyleColorsClassic();
// Setup Platform/Renderer bindings // Setup Platform/Renderer backends
ImGui_ImplWin32_InitForOpenGL(hwnd); ImGui_ImplWin32_InitForOpenGL(hwnd);
ImGui_ImplOpenGL3_Init(); 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. // - 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). // - 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. // - 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. // - 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 \\ ! // - 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->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/Roboto-Medium.ttf", 16.0f);
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.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()); //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, NULL, io.Fonts->GetGlyphRangesJapanese());
//IM_ASSERT(font != NULL); //IM_ASSERT(font != NULL);
@ -85,21 +89,21 @@ int main(int, char**)
ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
// Main loop // Main loop
MSG msg; bool done = false;
ZeroMemory(&msg, sizeof(msg)); while (!done)
while (msg.message != WM_QUIT)
{ {
// Poll and handle messages (inputs, window resize, etc.) // 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. // See the WndProc() function below for our to dispatch events to the Win32 backend.
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application. MSG msg;
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application. while (::PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
// 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))
{ {
::TranslateMessage(&msg); ::TranslateMessage(&msg);
::DispatchMessage(&msg); ::DispatchMessage(&msg);
continue; if (msg.message == WM_QUIT)
done = true;
} }
if (done)
break;
// Start the Dear ImGui frame // Start the Dear ImGui frame
ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplOpenGL3_NewFrame();
@ -110,7 +114,7 @@ int main(int, char**)
if (show_demo_window) if (show_demo_window)
ImGui::ShowDemoWindow(&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 float f = 0.0f;
static int counter = 0; static int counter = 0;
@ -129,7 +133,7 @@ int main(int, char**)
ImGui::SameLine(); ImGui::SameLine();
ImGui::Text("counter = %d", counter); 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(); ImGui::End();
} }
@ -148,84 +152,62 @@ int main(int, char**)
glViewport(0, 0, g_Width, g_Height); glViewport(0, 0, g_Width, g_Height);
glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w); glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w);
glClear(GL_COLOR_BUFFER_BIT); 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()); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
//glUseProgram(last_program);
SwapBuffers(g_MainWindow.hDC); // Present
::SwapBuffers(g_MainWindow.hDC);
} }
ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplWin32_Shutdown(); ImGui_ImplWin32_Shutdown();
ImGui::DestroyContext(); ImGui::DestroyContext();
CleanupDeviceOpenGL3(hwnd, &g_MainWindow); CleanupDeviceWGL(hwnd, &g_MainWindow);
wglDeleteContext(g_hRC); wglDeleteContext(g_hRC);
::DestroyWindow(hwnd); ::DestroyWindow(hwnd);
::UnregisterClass(wc.lpszClassName, wc.hInstance); ::UnregisterClassW(wc.lpszClassName, wc.hInstance);
return 0; 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 }; PIXELFORMATDESCRIPTOR pfd = { 0 };
pfd.nSize = sizeof(pfd); pfd.nSize = sizeof(pfd);
pfd.nVersion = 1; pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA; pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32; pfd.cColorBits = 32;
int pf = ChoosePixelFormat(hDc, &pfd); const int pf = ::ChoosePixelFormat(hDc, &pfd);
if (pf == 0) if (pf == 0)
{
return false; return false;
} if (::SetPixelFormat(hDc, pf, &pfd) == FALSE)
if (SetPixelFormat(hDc, pf, &pfd) == FALSE)
{
return false; return false;
} ::ReleaseDC(hWnd, hDc);
ReleaseDC(hWnd, hDc);
return true;
}
// Helper functions
static bool CreateDeviceOpenGL3(HWND hWnd, RendererData* data)
{
if (!ActivateOpenGL3(hWnd))
return false;
data->hDC = GetDC(hWnd);
data->hDC = ::GetDC(hWnd);
if (!g_hRC) if (!g_hRC)
{
g_hRC = wglCreateContext(data->hDC); g_hRC = wglCreateContext(data->hDC);
}
return true; return true;
} }
static void CleanupDeviceOpenGL3(HWND hWnd, RendererData* data) void CleanupDeviceWGL(HWND hWnd, WGL_WindowData* data)
{ {
wglMakeCurrent(NULL, NULL); wglMakeCurrent(NULL, NULL);
ReleaseDC(hWnd, data->hDC); ::ReleaseDC(hWnd, data->hDC);
} }
// Forward declare message handler from imgui_impl_win32.cpp // 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); extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
// Win32 message handler // 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) LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{ {
if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam)) if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam))