[SOLVED] Lwjgl3 getWidth, getHeight

I am at a point where I am seeing if lwjgl3 is going to work for me in avoiding reflection warnings thrown out by java 14 with regards to.

Illegal reflective access by com.jme3.util.ReflectionAllocator

After switching to lwjgl3 I found out they no longer provide convenience methods used in the class org.lwjgl.opengl.Display to get the width and height of the screen and the GLFW class that replaces it doesnt have anything like it.

I find it kinda weird to cannibalize code like that but what the hell do I know, I am just the end user, why should they care right?

Anyway, it looks like I am forced to implement my own library just to use their library so before I get stupid, are there any jme GLFW utilities already written somewhere?

I presume you want this information before you can get it from the camera? Just want to make sure you didn’t forget the obvious.

The camera will also get it from somewhere, so you could track the code back to wherever it obtains those values.

You probably can just use the values from jME appsettings?

jME stuff you may want is in:

I’m pretty sure this code is how to get the framebuffer size of the GLFW window via lwjgl3

        try (MemoryStack stack = stackPush()) {
            final IntBuffer bWidth = stack.ints(0);
            final IntBuffer bHeight = stack.ints(0);
            GLFW.glfwGetFramebufferSize(window, width, height);
            int width = bWidth.get(0);
            int height = bHeight.get(0);
        }

I have only minimal knowledge of this so if I write something stupid feel free to point it out to me.

I dont have access without passing a reference. This is a port of MigLayout so that would be awkward.

My intention is to try and avoid writing code like this.

I can access the camera, and it is used already but for the current width/height. For the max width/height, lwgl is used by @zissis.

I found this after some more digging.

glfwGetVideoMode()

so

        @Override
        public int getMaximumWidth(int hHint) {
            //lwjgl2
//            return Display.getWidth();

            //lwjgl3
            GLFWVidMode glfwGetVideoMode = glfwGetVideoMode(glfwGetPrimaryMonitor());
            return glfwGetVideoMode.width();
        }

This seems to work fine.

So your mig layout implementation will be specific to the screen and can’t be used for a viewport based UI? Seems unfortunate.

I think someone did a mig layout implementation for Lemur but I don’t know how they solved this issue.

Edit: oh… hahah. zissis was the one I’m pretty sure so that’s already where you are starting. Is this still for Lemur then?

This is from that implementation.

yes

This is probably something that could/should be available from GuiGlobals, I guess.

Edit: seems like technically you could now by grabbing:
GuiGlobals.getInstance().getPopupState().getApplication().getCamera()

Edit 2: or even the deprecated: public ViewPort getCollisionViewPort( Spatial s )
…which I’m wondering now if should not be deprecated. I left myself no bread crumbs. lol

Heres what we have,

	/** Returns the current width for this component.
	 * @return The current width for this component.
	 */
	public abstract int getWidth();

where component is a lemur node.

        @Override
        public int getWidth() {
            return (int) component.getControl(GuiControl.class).getSize().x;
        }

and for max,

	/** Returns the maximum width of the component.
	 * @param hHint The Size hint for the other dimension. An implementation can use this value or the
	 * current size for the widget in this dimension, or a combination of both, to calculate the correct size.<br>
	 * Use -1 to denote that there is no hint. This corresponds with SWT.DEFAULT.
	 * @return The maximum width of the component.
	 * @since 3.5. Added the hint as a parameter knowing that a correction and recompilation is necessary for
	 * any implementing classes. This change was worth it though.
	 */
	public abstract int getMaximumWidth(int hHint);

with what used to be lwjgl2 Display class.

        @Override
        public int getMaximumWidth(int hHint) {
            //lwjgl2
            return Display.getWidth();
        }

I used what was posted before for lwjgl3.

        @Override
        public int getMaximumWidth(int hHint) {
            //lwjgl3
            GLFWVidMode glfwGetVideoMode = glfwGetVideoMode(glfwGetPrimaryMonitor());

            return glfwGetVideoMode.width();
        }

So this implementation is wrong and should just use camera width for both methods?

Edit: fixed wrong cut and paste for method.

If you want to work in all cases where your UI could be used (viewports) and it’s already attached to the scene then you can use:
GuiGlobals.getInstance().getCollisionViewport(this) and then ask the viewport. getOutputFrameBuffer().getWidth().

If you only care about screen size then:
GuiGlobals.getInstance().getPopupState().getApplication().getCamera().getWidth()

Edit: and either way, your code will then work on any JME platform, not just lwjgl3.

Crap. Thats worth knowing…

Ok I will fix this so it can be used in mini map.

Also the getWidth/getHeight are not probably always true when you ask it from jME/LWJGL, that is just the resolution. Scale differs… HiDPI… etc. so viewport/camera is what you want most of the time anyway.

The problem for this wrapper is that GuiGlobals gets initialized in simpleUpdate(). The AppStates using Lemur are instantiated at startup in main.

These wrapper methods can be called twice during startup. Whenever you position any component and when guiNode.updateLogicalState gets called after all AppStates are initialized.

When positioning, you get a null viewport as GuiGlobals is not yet fully initialized yet. This may be why the lwjgl values were used originally. They are always available.

By the time guiNode.updateLogicalState is called, everything is ok.

To work around positioning, I moved the AppState using lemur to instantiate after GuiGlobals initializes and using the AppStates update loop to position components since that means guiNode.updateLogicalState has already been called, but that limits you to the default camera anyway. May as well just leave it using lwjgl methods like was already doing.

getOutputFrameBuffer() is null by default. I only see the opportunity to setOutputFrameBuffer() per Component.

    @Deprecated
    public ViewPort getCollisionViewPort( Spatial s ) {
        if( mouseState != null ) {
            return mouseState.findViewPort(s);
        }
        if( touchState != null ) {
            return touchState.findViewPort(s);
        } 
        return null;
    }
    @Deprecated
    public ViewPort findViewPort( Spatial s ) {
        return session.findViewPort(s);
    }

Not sure if it even makes sense to do that for every component.

When do you initialize GuiGlobals? The best place is in simpleInit().

Yes, thats where they are.

The problem comes from the MigLayout. Running through debugger shows MouseState and PopupState are not initialized yet nor have ids.

When the MigLayout getPreferredSize() gets called, it calls these getMax methods so they return null.

So you are also setting up a UI in simpleInit()?

Else why is mig layout caring about these so early?

Usual good practice:
initialize GuiGlobals in simpleInit()
create UIs in app state.init

Mm… or are your app states added on the super() constructor? Hmm…

No.

    public Main() {
        super(new StatsAppState(), new DebugKeysAppState(),
              new BasicProfilerState(false),
              new AnimationState(), // from Lemur
              new OptionPanelState(), // from Lemur
              new DebugHudState(), // SiO2 utility class
              new LogoState(),
              new MainMenuState(), // <==== This is the UI here
              //new FlyCamAppState(), // temporary
              new ScreenshotAppState("", System.currentTimeMillis()));
    }

    @Override
    public void simpleInitApp() {

        setPauseOnLostFocus(false);
        setDisplayFps(false);
        setDisplayStatView(false);

        GuiGlobals.initialize(this);

yes, I am.

yes

To me, the easiest answer is to allow external setting of some static fields on MigLayout for where it keeps its screen size… or call it a “default screen size”.

Use the automatic ways when they are available (so that you can support viewport UIs or texture mapped UIs) but otherwise fall back on the static defaults.

…then set your static defaults during simpleInit().

I thought about passing a viewport to the MigLayout constructor. Wasn’t sure if that would be a good idea or not.

Edit: Feels dirty though.