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

Setting background alpha for specific viewports in glfw and win32/dx11 [SOLVED] #6558

Open
dgm3333 opened this issue Jun 28, 2023 · 9 comments

Comments

@dgm3333
Copy link

dgm3333 commented Jun 28, 2023

I want to create a transparent / overlay viewport.
With the following code it is correctly semi-transparent when over the main viewport (ie can see the main viewport through it).
However as soon as it is dragged outside the main viewport and becomes a single-window viewport it immediately becomes opaque.
I've tried these three variations for setting the alpha
I've tried with glfw and win32 dx11,dx12 with identical results
win32/ogl3 is the odd one out as the window appears to entirely disappear if it is in the main viewport (but is still opaque if it's outside the bounds)

ImVec4 overlayColour = ImVec4(1.0f, 0.4f, 0.4f, 0.25f);

ImGui::PushStyleColor(ImGuiCol_WindowBg, overlayColour);  // 1 (outside begin)

ImGui::SetNextWindowBgAlpha(0.25f);  // 2
if (ImGui::Begin("alpha", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse)) {
    ImGui::PushStyleColor(ImGuiCol_WindowBg, overlayColour);  //3 (inside begin)
    ImGui::PopStyleColor();
}
ImGui::End();
ImGui::PopStyleColor();
@PathogenDavid
Copy link
Contributor

Dear ImGui currently does not support secondary viewports with transparent backgrounds. (Alpha is explicitly ignored for viewport-owned windows)

See also #2766

win32/ogl3 is the odd one out as the window appears to entirely disappear if it is in the main viewport (but is still opaque if it's outside the bounds)

This sounds like a bug, but I cannot reproduce it on my machine with example_win32_opengl3 on latest docking (a88e5be).

@dgm3333
Copy link
Author

dgm3333 commented Jun 29, 2023

Oh sorry I think I may have been unclear / still struggling with the window naming terminology - I'm totally happy with the behaviour of the owned viewports
I was referring specifically to the effect after dragging an ImGui Window outside the boundaries of a Host Viewport when it becomes/is a Single-Window Viewport

I want this:
#2766

but it looks like this isn't currently supported as per this:
#5218

Regarding your helpful response (which provided me the path to clarify that issue had already been described)
Correct me if I'm wrong, but the issue is not this section of code explicitly preventing transparency in single-window viewports

If that were the case it should be possible to force everything to be transparent with something like the following at approx L6349. However this doesn't work

bg_col = (ImU32)(255 | 100 << 8 | 100 << 16 | 50 << 24);;
bg_draw_list->AddRectFilled(window->Pos + ImVec2(0, window->TitleBarHeight()), window->Pos + window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? 0 : ImDrawFlags_RoundCornersBottom);

@dgm3333
Copy link
Author

dgm3333 commented Jul 1, 2023

I've made a bit of (maybe) progress - in that I can now make the main viewport transparent - but it doesn't work for single-window viewports
BTW the following requires GLFW 3.3.8 - it doesn't work with the 3.2 shipped with ImGui

Inside the client bounds of the main-viewport it's perfect
image

But if it is moved outside those bounds the transparency fails
The blue is the background of the Visual studio window behind
From the menu bar down (with green semitransparency is the main viewport
The red is the still opaque :-( single window (supposed to be a transparent overlay)

image

Getting this far only requires a small change to core code

// transparency hint goes before glfwCreateWindow
glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE);
window = glfwCreateWindow(1650, 900, "ABCInsights", NULL, NULL);

// alpha is respected
ImVec4 clear_color = ImVec4(0.0f, 1.0f, 0.0f, 0.25f);

incidentally for those not sure it only takes a minute to upgrade - you just download glfw replace the following files and change the linker target to lib-vc2022 (or whatever version you're using). https://www.glfw.org/download.html
image

@dgm3333 dgm3333 changed the title Unable to set viewport background alpha Setting background alpha for specific viewports in glfw [SOLVED] Sep 10, 2023
@dgm3333
Copy link
Author

dgm3333 commented Sep 10, 2023

Finally got a couple of hours to get back to this question.
I can now set and/or change the transparency for any chosen single viewport to an arbitrary value at my whim :-)
Unfortunately I couldn't do it without a (very minor) modification to the core imgui code and a global :-(
If the transparent viewport is created over the main viewport it will inherit the main viewport alpha until it is at least once dragged outside the main viewport bounds - but I don't really care about that so haven't bothered to try and fix it.
Otherwise I'm pretty happy with it :-)
NB I'm using Win10 so this is a platform specific solution.

image

in "imgui_impl_opengl3.h"

in "imgui_impl_opengl3.cpp" remove static from the declaration so it becomes

void ImGui_ImplGlfw_CreateWindow(ImGuiViewport* viewport)
{

//New functions

std::map <ImGuiID, int> windowIDToAlpha;
void addWindowToMap(ImGuiID windowID, int alpha) {
	windowIDToAlpha[windowID] = alpha;
}
void makeWindowTransparent(GLFWwindow* window, int alpha = 255)
{
	HWND hwnd = glfwGetWin32Window(window);
	if (hwnd)
	{
		SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
		SetLayeredWindowAttributes(hwnd, 0, alpha, LWA_ALPHA);
	}
}

// ImGui platform interface allows to set a hook for viewport creation
// This hook is called as each viewport is created
void ImGuiPlatform_CreateWindow_WithTransparency(ImGuiViewport* viewport) {

	ImGui_ImplGlfw_CreateWindow(viewport);			// Create window with default platform_create_window

	// Set transparency for the window if it is in the map
	if (windowIDToAlpha.contains(viewport->ID)) {
		int viewPortAlpha = windowIDToAlpha[viewport->ID];		// 0 = transparent, 255 = opaque
		makeWindowTransparent((GLFWwindow*)viewport->PlatformHandle, viewPortAlpha);		// Make the window transparent as well
	}
}

In the main setup code flow

	// Setup Platform/Renderer backends
	...

        // ImGui platform interface allows to set a hook for viewport creation
	// Overwrite the platform interface function to create a window
	ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
	platform_io.Platform_CreateWindow = ImGuiPlatform_CreateWindow_WithTransparency;

In the rendering loop

        // Create an ImGui window
        if (ImGui::Begin("Transparent Viewport"))
        {
            static bool init = true;
            if (init) {
                init = true;
                addWindowIDToAlphaMap(ImGui::GetCurrentWindow()->Viewport->ID, 25);
            }
            ImGui::Text("This is a special transparent viewport\n(unless it's docked when it inherits parent transparency)");
        }
        ImGui::End();

@DynamicalCreator
Copy link

@dgm3333 I tried your solution on my directx9 win32 app. It gave me IM_ASSERT error and crashed when i dragged the window outside of the main viewport.

@dgm3333
Copy link
Author

dgm3333 commented May 25, 2024

as per the title I was after a glfw specific solution.

However with minor modifications it also works for win32/dx11.
I haven't tested it with dx9 but hopefully it will also work fine - just copy the platform_io lines from setupBackendWin32() to the appropriate point in your dx9 setup.

Then add these functions

I was trying to get some additional effects with the dwm library - but they aren't working in the way I wanted.
I've left them in case you want to play but if not just comment out the define


std::map <ImGuiID, int> windowIDToAlpha;
void addWindowIDToAlphaMap(ImGuiID windowID, int alpha) {
	windowIDToAlpha[windowID] = alpha;
}
void makeWindowTransparent(HWND hwnd, int alpha = 255)
{
	if (hwnd)
	{
		// Set the window to have a layered style
		SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
		// Set the transparency of the window
		SetLayeredWindowAttributes(hwnd, 0, alpha, LWA_ALPHA);
	}
}


#define OPTIONAL_DWM
#ifdef OPTIONAL_DWM
// Ensure you link against Dwmapi.lib for DwmEnableBlurBehindWindow function
#pragma comment(lib, "Dwmapi.lib")
#include <dwmapi.h>
// Function to enable blur behind the window (optional)
void EnableBlurBehindWindow(HWND hwnd) {
	DWM_BLURBEHIND bb = { 0 };
	bb.dwFlags = DWM_BB_ENABLE;
	bb.fEnable = TRUE;
	bb.hRgnBlur = NULL;
	DwmEnableBlurBehindWindow(hwnd, &bb);
}

// Function to extend the frame into the client area to create an Aero Glass effect
void ExtendFrameIntoClientArea(HWND hwnd) {
	MARGINS margins = { -1 };
	DwmExtendFrameIntoClientArea(hwnd, &margins);
}
#endif

// ImGui platform interface allows to set a hook for viewport creation
// This hook is called as each viewport is created
// You need to override the platform interface function to create a window
// platform_io.Platform_CreateWindow = ImGuiPlatform_CreateWindow_WithTransparency;
// you will have to update the ImGui_ImplWin32_CreateWindow function in imgui\backends\imgui_impl_win32.cpp so it is not static
IMGUI_IMPL_API void ImGui_ImplWin32_CreateWindow(ImGuiViewport* viewport);
void ImGuiPlatform_CreateWindow_WithTransparency(ImGuiViewport* viewport) {
	// Create window with default platform_create_window
	ImGui_ImplWin32_CreateWindow(viewport);

	// Set transparency for the window if it is in the map
	if (windowIDToAlpha.contains(viewport->ID)) {
		int viewPortAlpha = windowIDToAlpha[viewport->ID]; // 0 = transparent, 255 = opaque

		makeWindowTransparent((HWND)viewport->PlatformHandle, viewPortAlpha);	// Set the window transparency
#ifdef OPTIONAL_DWM
		EnableBlurBehindWindow((HWND)viewport->PlatformHandle);					// Enable blur behind the window
		ExtendFrameIntoClientArea((HWND)viewport->PlatformHandle);				// Extend frame into client area to create Aero Glass effect
#endif
	}
}

void setupBackendWin32(HWND& hwnd) {
	//ImGuiPlatform_CreateWindow_WithTransparency;
	// Setup Platform/Renderer backends
	ImGui_ImplWin32_Init(hwnd);
	ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext);

	// Override the platform interface function for window creation
	ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
	platform_io.Platform_CreateWindow = ImGuiPlatform_CreateWindow_WithTransparency;

	return;
}

// from inside your render loop
void drawTransparency() {
	ImGui::Begin("Transparency Test");
            static ImGuiWindow* window = ImGui::GetCurrentWindow();
            static ImGuiID viewportID = window->Viewport->ID;
            int alpha = 25;  // max 255
            addWindowIDToAlphaMap(viewportID, alpha );
       ImGui::End();
}


@dgm3333 dgm3333 changed the title Setting background alpha for specific viewports in glfw [SOLVED] Setting background alpha for specific viewports in glfw and win32/dx11 [SOLVED] May 25, 2024
@DynamicalCreator
Copy link

@dgm3333 Thank you!

@DynamicalCreator
Copy link

@dgm3333 After testing, it definitely works for directx9 too. Although i realized that i need to make only the background (WindowBg) transparent, not the entire viewport. Do you know how to do that in dx9? Sorry to bother you more.

@dgm3333
Copy link
Author

dgm3333 commented May 26, 2024

That's pretty easy to do in the initial window creation function with SetLayeredWindowAttributes - you just keep the alpha at 255 and set the colour key to a specific colour you don't want as the transparent colour - then anything in that colour will be transparent.

If you put the function and the change you want into chatGPT (or the free Bing version) then it will probably make a good stab at the code you want.

However I think this should do it:

// if you want to just have a single colour which is transparent then use this function
void makeWindowTransparent(HWND hwnd, COLORREF alphaColorKey, int alpha = 255) {
	if (hwnd) {
		// Set the window to have a layered style
		SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
		// Set the transparency of the window
		SetLayeredWindowAttributes(hwnd, alphaColorKey, alpha, LWA_ALPHA);
	}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants