NASAWorldWind / WorldWindJava

The NASA WorldWind Java SDK (WWJ) is for building cross-platform 3D geospatial desktop applications in Java.
717 stars 326 forks source link

Rendering issue: black borders around map when using scaling in 2.2.0 #195

Open nicolas-van opened 4 years ago

nicolas-van commented 4 years ago

Description

Using the version 2.2.0, when using Windows with the scaling graphical parameter activated we can see borders on the top and the right of the WorldWind map:

Annotation 2020-03-31 104113

Steps to Reproduce

On Windows 10, with openjdk 13 or 14 installed, right click your Windows background and choose "Display Settings". Then change the "Scale and Layout" parameter to "125%":

Annotation 2020-03-31 104036

Then launch the WorldWindJava demo application.

You can even switch the "Scale and Layout" display parameter without closing the demo application. The borders will always be present when the setting has a different value than "100%".

Expected behavior: The map displays without the black borders regardless of the "Scale and Layout" display setting.

Actual behavior: There are black borders when the "Scale and Layout" display setting has a value other than "100%".

Reproduces how often: 100% of the time, tested on 3 different computers with different graphic cards (AMD, Nvidia, Intel), all of them with same software configuration (Windows 10, openjdk13, latest commit on develop branch)

Operating System and Version

Additional Information

It's problematic for us because a lot of laptops nowadays have a default scaling parameter set to a value other than 100%. It means that a lot of our user report bugs and we have to explain them how to change their windows configuration as a workaround.

nicolas-van commented 4 years ago

Update: I also tested with openjdk 11 and this bug reproduces exactly the same way. I wasn't able to test with jdk 8 as it seems the project doesn't compile easily anymore with that older jdk version.

markpet49 commented 4 years ago

@nicolas-van Thanks for the detailed report. We'll review this issue in our final release testing.

thwe74 commented 4 years ago

we have the same problem but we fixed it with a small workaround. Not the best solution but it works as long as WWJ will be restarted after changing the window scale factor. Then it was running on 4K screens with 125% scaling.

In file WorldWindowGLAutoDrawable.java change:

public void reshape(GLAutoDrawable glAutoDrawable, int x, int y, int w, int h) {
        GL2 gl = this.drawable.getGL().getGL2(); // change this as needed
        double dpiScalingFactor = getScaleFactor();
        w = (int) (w * dpiScalingFactor);
        h = (int) (h * dpiScalingFactor);
        gl.glViewport(0, 0, w, h);
        ((Component) glAutoDrawable).setMinimumSize(new Dimension(0, 0));
}

but then the mouse point doesn't fit anymore and we needed to change WorldWindowGLCanvas.java and added the following:

@Override
protected void processMouseEvent(MouseEvent e) {
        double dpiScalingFactor = (double) (Toolkit.getDefaultToolkit().getScreenResolution() / 96.0);
        int x = (int) (e.getPoint().x * dpiScalingFactor);
        int y = (int) (e.getPoint().y * dpiScalingFactor);
        MouseEvent scaledEvent = new MouseEvent((Component)e.getSource(), e.getID(), e.getWhen(), e.getModifiersEx(), x, y, e.getXOnScreen(), e.getYOnScreen(), e.getClickCount(), false,e.getButton());
        super.processMouseEvent(scaledEvent);
}
protected void processMouseMotionEvent(MouseEvent e) {
        double dpiScalingFactor = (double) (Toolkit.getDefaultToolkit().getScreenResolution() / 96.0);
        int x = (int) (e.getPoint().x * dpiScalingFactor);
        int y = (int) (e.getPoint().y * dpiScalingFactor);
        MouseEvent scaledEvent = new MouseEvent((Component) e.getSource(), e.getID(), e.getWhen(), e.getModifiersEx(),
                x, y, e.getXOnScreen(), e.getYOnScreen(), e.getClickCount(), false, e.getButton());
        super.processMouseMotionEvent(scaledEvent);
}
protected void processMouseWheelEvent(MouseWheelEvent e) {
        double dpiScalingFactor = (double) (Toolkit.getDefaultToolkit().getScreenResolution() / 96.0);;
        int x = (int) (e.getPoint().x * dpiScalingFactor);
        int y = (int) (e.getPoint().y * dpiScalingFactor);
        MouseWheelEvent scaledEvent = new MouseWheelEvent((Component) e.getSource(), e.getID(), e.getWhen(), e.getModifiersEx(), x, y, e.getXOnScreen(), e.getYOnScreen(), e.getClickCount(), false, e.getScrollType(),e.getScrollAmount(),e.getWheelRotation());
        super.processMouseWheelEvent(scaledEvent);
}

I hope it will be fixed in a correct way...

nicolas-van commented 4 years ago

@thwe74 : Did you reproduced it with version 2.2.0 or using a random commit on the develop branch like I did ?

thwe74 commented 4 years ago

@nicolas-van: Yes, I tested it with version 2.2.0 and the current develop branch from today. Always the same problem. It looks like the scale factor from the screen is not considered in the JOGL implementation. With the workaround it works

nicolas-van commented 3 years ago

I changed the description and title to clearly explain this bug is present in 2.2.0.

nicolas-van commented 3 years ago

@thwe74 : I tested your solution, which seems fine, and made a pull request: #218

yaroslavkulinich commented 2 years ago

The problem with @thwe74 solution is that it breaks the behavior on MacOS giving wrong scaling factor when has to be 1.0 (actually it's not).

To make it work, you just need to check the OS and do changes with scale factor only on Windows.

Here is some code. We need to know what OS is running on:

src/gov/nasa/worldwind/util/WWUtil.java

public static OS getOS() {
        String osName = System.getProperty("os.name").toLowerCase(Locale.getDefault());
        if (osName.contains("win")) return OS.WINDOWS;
        else if (osName.contains("nix") || osName.contains("nux") || osName.contains("aix")) return OS.LINUX;
        if (osName.contains("mac")) return OS.MAC;
        else return null;
    }

public enum OS {
        WINDOWS,
        LINUX,
        MAC
}

Then use it in our event functions (I showed only one of them):

src/gov/nasa/worldwind/awt/WorldWindowGLCanvas.java

@Override
protected void processMouseEvent(MouseEvent e) {
     if (WWUtil.getOS() == WWUtil.OS.WINDOWS) {
         double dpiScalingFactor = (double) (Toolkit.getDefaultToolkit().getScreenResolution() / 96.0);
         int x = (int) (e.getPoint().x * dpiScalingFactor);
         int y = (int) (e.getPoint().y * dpiScalingFactor);
         MouseEvent scaledEvent = new MouseEvent((Component) e.getSource(), e.getID(),
                 e.getWhen(), e.getModifiersEx(), x, y, e.getXOnScreen(), e.getYOnScreen(), e.getClickCount(), false, e.getButton());
         super.processMouseEvent(scaledEvent);
     } else super.processMouseEvent(e);
}
PJHogan commented 2 years ago

Elegantly beautiful, like so much from this extraordinary international crew of virtual globe aficionados!

gknorman commented 2 years ago

Not as elegant as yaroslavkulinich's code above, but I usually pass an argument to the VM when running WWD on Windows:

-Dsun.java2d.uiScale.enabled=true; -Dide.ui.scale=1.5

This can also be added to a .bat file if folks need to distribute WWD with a launcher:

@echo off
REM Copyright (C) 2012 United States Government as represented by the Administrator of the
REM National Aeronautics and Space Administration.
REM All Rights Reserved.

@echo Running gov.nasa.worldwindx.examples.ApplicationTemplate
java -Dsun.java2d.uiScale.enabled=true -Dide.ui.scale=1.5 -jar "YourWorldWindBuild.jar"

Or you can turn off the scaling factor with VM options, like in this shell script:

# Copyright (C) 2012 United States Government as represented by the Administrator of the
# National Aeronautics and Space Administration.
# All Rights Reserved.

java -Dsun.java2d.uiScale.enabled=false -Xmx1024m -Dsun.java2d.noddraw=true -jar "YourWorldWindBuild.jar"
PJHogan commented 2 years ago

Can you fix it and then we can fold that in!

gknorman commented 2 years ago

@PJHogan Do you see any reason to support DPI scaling on windows when it's not really supported by Java 8?

If not, this System property can be set in the ApplicationTemplate's start() method instead of calculating the DPI scaling of mouse events ourselves:

if (Configuration.isWindowsOS() && appName != null)
    {
           System.setProperty("sun.java2d.uiScale.enabled", "false");
    }
PJHogan commented 2 years ago

NASA, please do your best to HELP make this work! Seems like some basic stuff that dearly needs attention!

grammesm commented 1 year ago

@thwe74 @yaroslavkulinich @nicolas-van Thanks for the solutions. I've tried implementing these, and everything seems to work great except dragging the map with the mouse. The modified mouse event doesn't seem to be scaling properly for me and I'm still limited to the "small" map portion when I click and drag the map. Anyone else seeing these issues? I'm using Adoptium JDK 11 if that would matter.

I can't see how the processMouseMotionEvent would be any different than the others.

Edit: Also testing at 200% scaling at 4K resolution

RaimundBarbeln commented 6 months ago

Is there any chance to solve the remainig issue when changing the scale whith the application running. It is quite annoying, since we sometimes need to change the scaling during presentations of our application. Customers don't like suddenly seeing black borders.