-
-
Notifications
You must be signed in to change notification settings - Fork 10.3k
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
How to handle window and surface with different dimensions? #6955
Comments
Easiest way would be to copy If scissor rects are a problem as well (they most likely are), you can iterate through the draw data before rendering (take a look at Or you can indeed write your custom backend. It's not as hard as it may sound. In this case it would be a copy of the DX9 backend with adjustments in the mentioned functions. |
Seconding Daniel. My wording is maybe a bit off in that old comment, I think what I actually meant was customizing an existing backends rather than writing one from scratch. (In your case it also appears that your inputs are fine it's just the visuals that are too small, which is much simpler to tweak.) |
I thought I'd post here once I figured everything out, but since you mentioned inputs, they're not fine, actually. Dear ImGui behaves as if the window that I'm trying to interact with was still at its original position, even though it's now displayed at a different one. Here's another video where I tried to show it off better: input.mp4I also showed the dimensions of the display size and render target this time. You can see the render target's changing to 4k right once the game goes into a loading screen. Here's how I queried it: IDirect3DSurface9 *render_target = nullptr;
HRESULT result = render_manager->d3d_device->GetRenderTarget(0, &render_target);
if (!result) {
D3DSURFACE_DESC desc = {};
result = render_target->GetDesc(&desc);
if (!result) {
ImGui::Text("Current io.DisplaySize.x is %f", io.DisplaySize.x);
ImGui::Text("Current io.DisplaySize.y is %f", io.DisplaySize.y);
ImGui::Text("Current width of render target 0 in D3DSURFACE_DESC is %d", desc.Width);
ImGui::Text("Current height of render target 0 in D3DSURFACE_DESC is %d", desc.Height);
}
} An idea I got is simply doubling the mouse cursor position: LPARAM newpos = lParam;
if (message == WM_MOUSEMOVE) {
newpos = ((GET_Y_LPARAM(lParam) << 16) * 2) | (GET_X_LPARAM(lParam) * 2);
}
ImGui_ImplWin32_WndProcHandler(hwnd, message, wParam, newpos); Surprisingly, it works, but this could potentially cause some problems, like if Dear ImGui tries to set the cursor's position based on this value, for example if ImGuiConfigFlags_NavEnableSetMousePos is used. I was thinking that maybe I could divide all the window's positions and dimensions by 2 somehow before inputs are handled? Or maybe there already is a way to make the library do exactly that, that I haven't found? In the meantime I managed to solve the issues with the scissor rects thanks to pointers from Daniel. Once I knew where to look, I even found out that there's specifically a function for this very case, |
OK, I figured it all out. Essentially, what happens under the win32 backend when you have a surface and window with different dimensions is that the backend ignores that (to be fair, it's not like it can be aware of that without calling into dx9) and tells Dear ImGui to work in the context of the window. So, when I see two possible solutions to this:
ImDrawData *draw_data = ImGui::GetDrawData();
if (draw_data) {
for (auto &list : draw_data->CmdLists) {
for (auto &vert : list->VtxBuffer) {
vert.pos.x *= 2;
vert.pos.y *= 2;
}
}
draw_data->DisplaySize.x = 3840;
draw_data->DisplaySize.y = 2160;
draw_data->ScaleClipRects(ImVec2(2, 2));
}
ImGui_ImplDX9_RenderDrawData(draw_data); And while this approach is likely worse in terms of performance, I think I prefer it anyway. While searching through some more issues I found the following comment by ocornut #6714 (comment):
Meaning the first approach could potentially become supported at some point. Exciting! |
Inputs only don't look fine as long as the display is scaled incorrectly. Once you fix your render scaling, the inputs should match up again after modification. Inputs should behave as if the window was still at its original position, you just need to scale rendering so that it is displayed at its original position as well. If you do it the other way around and adjust your inputs to your non-scaled rendering, they will match up as well. But you will have changing sizes all over and in high resolution rendering your ImGui windows and widgets will be very small and hard to read. |
I (eventually) arrived at the same conclusion. The only downside to upscaling the rendering is that it looks less crisp: upscale.mp4In this video the render target's dimensions change at around the 2 second mark, and you can notice how the UI quality degrades slightly. I think the problem could be dealt with by using
Although I think the size and reading experience can be improved by setting the font scale like |
You could do an extra step. Create your own render target texture in the original window resolution and render into that one (after a clear). Then you won't need to scale anything. But you would need to adjust your blending setup with separate blending for the alpha channel. Then you could render the resulting texture as a fullscreen quad with point sampling and a fitting blending setup, that should preserve the crispness. |
Version/Branch of Dear ImGui:
Version: 313676d
Branch: master
Back-end/Renderer/Compiler/OS
Back-ends: imgui_impl_win32.cpp + imgui_impl_dx9.cpp
Compiler: i686-w64-mingw32-g++
Operating System: Windows and Linux (Wine)
My Issue/Question:
I'm using Dear ImGui to make a UI with which to control discovered leftover/debug functionality in a proprietary video game that I have no source code for. It's compiled to a DLL, which the game then loads. From DllMain I hook the game's EndScene, which is then used to render everything.
It's working well, but the game can dynamically change the dimensions of the surface it's rendering to (the window resolution never changes). If the graphics quality are set to highest, the game renders everything after the intro at 2x width and height of the resolution selected in the settings. Since this depends on the graphics quality, my guess is that this is done for anti-aliasing. Unfortunately it also screws with the rendering and input of the UI. I attached a video showing what the problem looks like.
I found a few issues discussing similar problems:
There I didn't see a definitive answer for how to handle such situations. PathogenDavid suggested writing a custom backend, but I'm wondering if there is a simpler way.
Thank you in advance!
Screenshots/Video
2x.mp4
The text was updated successfully, but these errors were encountered: