imgui icon indicating copy to clipboard operation
imgui copied to clipboard

Rotating display is fine, but clipping is an issue (SDL2+OpenGL ES - No X server)

Open hippyau opened this issue 3 years ago • 6 comments

Version/Branch of Dear ImGui:

Version: 1.82 Branch: master

Back-end/Renderer/Compiler/OS

Back-ends: imgui_impl_SDL.cpp + Open GL ES on Raspberry Pi4 (SDL2 kmsdrm driver, without X11) Compiler: gcc Operating System: Linux / Raspbian

My Issue/Question:

Is there a way to have Dear ImGui globally swap X and Y coordinates, that is, to draw the whole UI in a rotated orientation?

I have a "1920x480 LCD Panel" letterbox HDMI display, however it is really a 480x1920 LCD Panel, and I cannot find driver support or a method of using SDL to rotate the display for me. I am not using X11.

I believe swapping X and Y would do the trick, is this achievable?

hippyau avatar Mar 26 '21 06:03 hippyau

You will need to rotate the projection matrix in the renderer. This will need modifying the renderer. You may need to rotate the mouse position as well.

ocornut avatar Mar 26 '21 07:03 ocornut

Great success...

image

I modified the ortho_projection[4][4] to...

        { 0.0f,         2.0f/(R-L),   0.0f,   0.0f },
        { 2.0f/(T-B),   0.0f,         0.0f,   0.0f },
        { 0.0f,         0.0f,         1.0f,   0.0f },
        { (T+B)/(B-T),  (R+L)/(L-R),  0.0f,   1.0f },

I had to comment out because of some weird clipping issues.

//                    glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y));

And in SDL2_NewFrame(), I hardcoded my screen dimensions...

    display_w = 480; display_h = 1920;  // real screen
    w = 1920; h = 480; // we want

and swapped X & Y in the mouse input :)

hippyau avatar Mar 26 '21 13:03 hippyau

As @ocornut explained, I needed to rotate the projection matrix so modified ortho_projection[4][4] as previous comment,

  { 0.0f,         2.0f/(R-L),   0.0f,   0.0f },
  { 2.0f/(T-B),   0.0f,         0.0f,   0.0f },
  { 0.0f,         0.0f,         1.0f,   0.0f },
  { (T+B)/(B-T),  (R+L)/(L-R),  0.0f,   1.0f },

I then have display in correct orientation working nicely, except.... I had to comment out glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y)); because it was messing it all up.

Now I need to get glScissor working with the rotated projection matrix because the mess is terrible.

I am not very smart when it comes to OpenGL and projection matrices etc... I have tried a few permutations, I thought swapping x and y would be sufficient, but I am doing something very wrong and not really understanding.

Should I be changing the clip_rect, or the order of the input arguments to glScissor ?

In normal orientation, I think clip_rect.x and .y are top-left x,y of a rectangle, .z and .w are bottom-right x,y so why is swapping them not rotating the rectangle properly?

[original from impl_opengl3.cpp]

[...]
                clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x;
                clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y;
                clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x;
                clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y; 

                if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f)
                {
                    // Apply scissor/clipping rectangle
                    glScissor(
                      (int)clip_rect.x, 
                      (int)(fb_height - clip_rect.w), 
                      (int)(clip_rect.z - clip_rect.x), 
                      (int)(clip_rect.w - clip_rect.y)
                    ); 
[...]                   

hippyau avatar May 03 '21 04:05 hippyau

I have tried several permutations of swapping and offsetting x, y, z, w to get clipping to work, but I can't translate the rectangle that glScissor needs to account for the rotated projection matrix, there is clipping present but in the wrong places.

hippyau avatar Mar 06 '23 12:03 hippyau

I have tried several permutations of swapping and offsetting x, y, z, w to get clipping to work, but I can't translate the rectangle that glScissor needs to account for the rotated projection matrix, there is clipping present but in the wrong places.

Did you get a work around for this? I have a waveshare display that is 1080x1920, but I need my fullscreen Imgui app to display as 1920x1080 I need everything rotated 90 degrees, I'm trying to avoid the overhead of X11 or Wayland with my Raspberry Pi 5 / Debian Bookworm setup.

schoolpost avatar Nov 29 '23 19:11 schoolpost

I have found a solution for the clipping when rotating the screen 180 degrees. This is the correct way:

// Apply scissor/clipping rectangle (Y is inverted in OpenGL)
GL_CALL(glScissor((int)clip_max.x, (int)((float)fb_height - clip_min.y), (int)(clip_min.x - clip_max.x), (int)(clip_min.y - clip_max.y)));

So basically you just replace min with max and vice versa. For 90 degrees I think you also have to swap and/or negate x/y. But this will hopefully make finding the right permutation easier.

jgeskens avatar Feb 06 '24 10:02 jgeskens