LWJGL3 Window Utilities

LWJGL3’s “window manipulation interface” is a bit more convoluted compared to LWJGL2. I’ve always thought it would be nice if JME had some utility methods to make using 3 a bit easier.

But I’m on the fence about whether this should even be a JME responsibility.

To illustrate what I mean by “convoluted”, relatively speaking:

LWJGL2:

Display.setLocation(windowX, windowY);

Simple interface:

public static void setLocation(int new_x, int new_y);

LWJGL3:
‘context’ is a JmeContext. I know this could be written more concisely, but it would still be a nuisance.

LwjglWindow lwjglContext = (LwjglWindow) context;
long winHandle = lwjglContext.getWindowHandle();
GLFW.glfwSetWindowPos(winHandle, windowX, windowY);

Interface:

public static void glfwSetWindowPos(long window, int xpos, int ypos);

This is one of the less annoying differences. Getting window position or size is worse. You need to pass two IntBuffers to capture the window width/height values, for example:

public static void glfwGetWindowSize(long window, IntBuffer width, IntBuffer height);

(And if you’re calling this frequently, now you’re either creating extra garbage with those buffers, or you have to keep them around to re-use.)

None of this is a problem; it’s just a slight annoyance and inconvenience–another reason I’m not sure it’s worth putting in JME.

Another idea, apart from a simple LWJGL3 utility class, is to have JME provide a standard interface which LWJGL2, LWJGL3, and JOGL could all implement. I imagine it would look similar to parts of LWJGL2’s Display class (static methods with minimal parameters).

It was suggested that I ask here to solicit some additional opinions on whether this is worth adding.
…Any thoughts?

Well, I mean, in JME it 100% would not be static methods. That much I can say for sure.

I think the reason they aren’t static in lwjgl3 is because there can be more than one window? (not familiar with 3 but that’s what the API implies).

I think LWJGL3 just exposes the GLFW-binding

https://www.glfw.org/docs/latest/window_guide.html

I don’t think LWJGL3 even have their own window/context-creation anymore, it’s all GLFW I believe.

Multi-window might have been a factor, but at least some of these methods work fine as statics even with multiple windows due to that window handle parameter. I haven’t looked at the entire API they’re exposing yet, just things I’ve wanted to use before.

Some of these could definitely be static. Are you opposed to statics for design reasons for because there’s some technical limitation that prevents it? For 2, these were all static.

When I get a chance I’ll post a list of ‘candidate api’ that would be the goal, if this enhancement is judged useful, I realize it’s a little fuzzy right now.

@jmaasing Yes these are all GLFW calls.

Yes THEIR methods are static because they pass a window handle to support multiple windows. That’s because they are essentially a C API rendered in Java.

JME is not a C API. It’s an OOP API. So should not have static methods for this… else JME would be forever forced into a single window design.

lwjgl2 has static methods because I guess they only ever support one display at a time.

2 Likes

I wanted to get a clearer understanding of the high level design, so I found an app to reverse-engineer this diagram below. Note, there may be some JmeContext implementors missing; I think VR has its own implementation too.

Anyway, JmeContext is the clear nexus. This seems like a logical place to add window-manipulation or other similar methods, unless there’s some concern over bloating that class, or a better suggestion. (I have additional thoughts on this but will keep it simple, unless objections are noted.)

This is a big improvement over my original proposal using statics, requiring a JmeContext to be passed in, which I wasn’t happy with anyway. (In my defense, I was trying to be minimally intrusive to core classes to keep it simple, but this deserves more forethought and better integration than that.)

Imgur

These are the methods I suggest adding to start with. If there are other useful methods they can be added later, or maybe I could throw some additional API in if someone really wants.

    public static int getWindowX();
    public static int getWindowY();
    public static void setWindowPosition(int xPos, int yPos);

    public static int getWindowWidth();
    public static int getWindowHeight();
    public static void setWindowSize(int width, int height);

    public static int getPrimaryMonitorWidth();
    public static int getPrimaryMonitorHeight();

Thoughts/flames/suggestions?

(Side note: The lwjgl projects use the same package and in some cases class names, so I find myself wondering if jme3-lwjgl3 could have used a different package than jme3-lwjgl. Then we wouldn’t have to swap these dependencies at build time to switch from 2 to 3, and instead the desired context implementation could be injected at runtime. But, different topic…)

1 Like

Stupid question since this is a part of jME that I’m not very familiar with: is there only ever one JmeContext per application, and if not, how will this change handle contexts that are not associated with a window (this is also an issue with headless contexts)?

Multiple contexts & displays per app, I guess is what pspeed was alluding to above. I don’t believe any possible configuration of JME supports that kind of thing now (I could be wrong). In future, who knows.

I’ve thought about this kind of thing some, for example with the VR classes - these methods probably aren’t useful or maybe not even applicable in that case. I’m not sure there’s a perfect solution for contexts like that. The obvious/easy option is to just throw a runtime exception informing the developer that the method isn’t implemented or isn’t supported. Generally I frown upon that kind of solution, but if the alternatives are nastier…

One thing we could probably do is introduce an intermediate interface in between JmeContext and the implementing classes that it makes sense for, and put these type of methods in there. That may be some overkill (I haven’t developed a strong opinion on the matter), but it would eliminate the need for classes which shouldn’t implement these methods to provide stub no-op methods. I’ve no idea what we’d name such an intermediate interface, yet.

I’ve still got a bit of analysis to do in this area, the interface/API design is one part, but I need to look at which classes should implement these methods. In addition to VR, a quick check seemed to show iOS and Android references to JmeContext, which maybe are problematic?

You can already get and set these with app settings and a restart… which is really the only way it makes sense to resize the display, I guess. Else it’s just going to be stretching.

These seem like something that you can already ask Java if you are on desktop… and only make sense on desktop, anyway. Though I guess that requires making an AWT call but I think it’s separate from the lwjgl3 bug.

I’m a little less on the fence. I’d probably need to see some strong game-related use-cases for such a thing.

…and while listing those use-cases explain why positioning the window is necessary but things like min/maxing a window isn’t.

And if you think all/some of those should be supported then to me it’s a completely separate interface we can ask of the JmeContext. getWindowContext() or some such that can simply return null in the cases where it doesn’t make sense… like headless, android, vr, maybe even fullscreen.

1 Like

Oh these methods aren’t a complete list, it’s just what I’ve needed so far. For example another might be setting a custom mouse cursor - GLFW call. (AWT can maybe, if we trust it to work.) Window min/max is a candidate for inclusion here I guess. I’ve only skimmed the GLFW stuff available, so there could be lots more useful stuff, or not.

My particular case is limited only to development convenience. I sometimes go between a tiny laptop to a big ultrawide monitor, so I use very different window sizes/positions, and would rather not change code constantly to do so. I’ve used AppSettings for window size. The settings dialog forces it to be specifically one of the resolutions available in the screen resolution combobox, but a window can be any size.

Original goal was to make the GLFW API more convenient; eliminate the need to obtain and pass window handles, buffers to store returned values, use of inconvenient types where a simple one will do, etc. Like I said on GitHub originally, if the interest isn’t there, I won’t be upset if we drop the idea. I’ve plenty of other stuff lined up to work on. :slight_smile:

So back to the original question - do we even want a convenience API for GLFW? It doesn’t make sense for me to offer a contribution otherwise.

So in your case, wouldn’t it be easier just to have command line arguments on your game that feed the app settings… and skip the dialog?

I do skip the dialog for my own stuff, but long story short, that’s not a very appealing option. It’s easier to use the GLFW calls for me, even with the uglier-than-lwjgl2 API. But I don’t want to make this about my “problem” (not really a problem). It’s just what got my attention on that slightly cumbersome GLFW API.

So, you might look forward to a thread like this in your future:

“I have this weird problem that no one else seems to see.”

20 replies later.

“Oh, yeah, I set the window size directly without letting JME know the proper framebuffer size…”

Not if I only used GLFW for the window positioning part, but point taken… maybe we shouldn’t even be calling some of these GLFW methods directly anyway. Hmm…

These seem like something that you can already ask Java if you are on desktop… and only make sense on desktop, anyway. Though I guess that requires making an AWT call but I think it’s separate from the lwjgl3 bug.

I want to mention one thing.

We have one computer with Linux Centos with 3 Monitor(Displays).

In fullscreen mode seems like in start settings there is like 7000x1000 resolution(for fullscreen mode only) alike, so looks like width is calculated by adding width of all displays. So i think something is wrong there. It was for LWJGL3. Well selecting proper resolution for fullscreen (not auto choosed) fix it, but there is problem in JME auto fullscreen resolution picker for many displays.

Ok, last attempt to wrap this up and decide one way or the other I guess. These are documented methods I found that may have some utility. I left out the window size call since it can be done via settings and may be problematic.

AFAIK JME doesn’t expose any API to access these, but I’m just going off memory so I could be wrong.

void glfwSetWindowPos (GLFWwindow *window, int xpos, int ypos)
 	Sets the position of the content area of the specified window. 

void glfwRestoreWindow (GLFWwindow *window)
 	Restores the specified window.

void glfwMaximizeWindow (GLFWwindow *window)
 	Maximizes the specified window.

void glfwShowWindow (GLFWwindow *window)
 	Makes the specified window visible.

void glfwHideWindow (GLFWwindow *window)
 	Hides the specified window.

void glfwFocusWindow (GLFWwindow *window)
 	Brings the specified window to front and sets input focus.

void glfwSetWindowUserPointer (GLFWwindow *window, void *pointer)
 	Sets the user pointer of the specified window.

Picking the monitor to use for full screen appears to be something that can only done at window-creation time, oh well.

Maybe some of these would be useful if you’re running a background server with an admin interface that you want to make visible or whatever. Window positioning and maybe setting a mouse pointer are probably the main things. So not enough here to warrant big changes. Can those be done without accessing GLFW directly?

1 Like