Full Encapsulation of LWJGL/GLFW Dependencies from Client Applications Possible?

Started by xghost, July 06, 2015, 00:31:14

Previous topic - Next topic

xghost

Hi everyone,

I'm currently evaluating LWJGL3 for a Java-based project. The project is a "simple" game engine that will be used in a computer science course on computer game architecture/implementation.

I've used JOGL before, and it has been good, but there's a particular constraint that's been getting in my way lately (particularly, the fact that you can't make OpenGL calls outside of specific locations, like display(GLAutoDrawable) override.), which is why I'm checking this one out.

However, I think I've found something that's getting in my way with LWJGL when it comes to input handling. For example, the documentation (eg. https://github.com/LWJGL/lwjgl3-wiki/wiki/2.6.3-Input-handling-with-GLFW) seems to imply that the only way to manage inputs is by using the glfw* functions.

The design problem this creates is that it seems difficult to completely encapsulate/hide the fact that the engine depends on LWJGL from the client application itself because for the client/game to be able to handle inputs, it'd have to use the glfw* functions and callbacks directly, exposing to the client that there's in fact a dependency on LWJGL, instead of relying on interfaces like KeyListener, MouseListener, etc.

My goal is for the client to depend on the "simple" engine that's being developed and on the interfaces that the engine itself should/will expose, rather than "leak" the LWJGL/JOGL/Whatever dependency within the engine itself.

I searched the forum for a bit and did not find anything that seemed related to this. Then again, there were lots of hits and it's not realistic/practical to go through all of them, so I apologize if this topic has been discussed in some deep and dark corner of the forum, perhaps by using keywords different to those I used during my search :)

Questions:

  • Is there a nice way around the situation I've described, perhaps something I'm missing?
  • Any suggestions and/or recommendations?
  • Anything you'd like me to clarify?


Thanks in advance,

-x

Cornix

Yes of course there is a simple solution: Write a Facade.
Just wrap the input handling from GLFW inside your own adapter class and expose only this class.

Kai

Yes, like Cornix said, you can beautifully create your own listener callback implementations that interface with GLFWKeyCallback, GLFWMouseButtonCallback, GLFWCursorPosCallback, etc.

But I want to also give a note on my experiences about abstraction, information hiding and encapsulation that I painfully learnt during the last years, especially when it comes to performance-critical applications:
I usually do not abstract away things I don't expect to change in the near future.

What I mean by this is four points:

1. there are basically only JOGL and LWJGL out there for Java/OpenGL binding frameworks. So, if you now choose to use LWJGL 3 and see no reason why you would switch back to JOGL in the near future then in my opinion don't abstract LWJGL away.

2. if LWJGL 3 happens to change its input handling somewhere in the future with LWJGL 4 maybe, then abstracting that away likely creates more work later when trying to adapt your abstraction to the new input handling in LWJGL 4, which we don't know how it will even look like and whether your abstraction still suits the new underlying input handling.

3. with performance-critical applications like a game or game engine, any abstractions that do not closely reflect the underlying schemes of what they abstract away, will likely cause a degradation in overall performance. So in performance-critical applications, your abstractions will likely just be a renaming of the LWJGL-provided callback interfaces to your own names, with likely the same method signatures. If your underlying library changes (either LWJGL itself changes or you use JOGL again), then you will have the same amount of work changing your abstraction as if you would have used no abstractions at all and used LWJGL directly right from the start.

4. if you really like to build an abstraction that can deal with both JOGL and LWJGL then it is a tremendous amount of work, since you need to find the common denominator of JOGL and LWJGL which is the basis for your abstraction. This again would likely hurt performance either with LWJGL or JOGL.

I know that abstracting away everything can be really tempting, but in the end at least from what I experienced it creates a) more work and b) is harder to understand for people that aren't familiar with your engine but are so with LWJGL or JOGL.

abcdef

It is possible and other engines such as Libgdx already do this, when using their engine you have no idea that you are using LWJGL.

In general there are 2 reasons you would want to do this is to

a) Make it so that you can support multiple back ends
b) Make the front end code easier to use by hiding complicated reusable code

I also do this in my own code and it wasn't that difficut to implement.

Kai

Yes, of course it is possible. I'm not saying it is impossible. :)
I wanted to just clarify that depending on the goal one has with the game engine, one has to weigh the pros and cons of building such abstractions and what needs they fulfill.
libGDX does this because they want to support even multiple platforms, such as Web, Android and PC.
In this scenario it totally makes sense and building an abstraction is even a requirement, because on Android and Web there is no LWJGL available.

xghost

Hi all,

Thanks for your responses. I'll keep them in mind, but it does seem like it's not really possible to go back to the Java interfaces (e.g. KeyListener, MouseListener) if/when the window is created using the glfw* functions, at least not without a potentially significant amount of work.

Does this seem accurate?

Thanks,
-x

PS: Unrelated, but important: When I created my account yesterday, I couldn't help but notice that this site does not use HTTPS/HSTS to protect users and their login credentials :-X The admin of this web-server needs to 1) do due diligence and fix this security hole ASAP, and 2) cause all users to reset their passwords after that's done.

Cornix

Do an internet search on Object-Adapters. Read all the material you can find carefully. Then you should be able to do what you want to achieve.

xsupermetroidx

Quote from: xghost on July 07, 2015, 00:52:51
it's not really possible to go back to the Java interfaces (e.g. KeyListener, MouseListener)

KeyListener and MouseListener are interfaces. You can create your own class that implements KeyListener/MouseListener and manually convert GLFW's event outputs into KeyListener/MouseListener inputs.

xghost

Quote from: Cornix on July 07, 2015, 05:36:11
Do an internet search on Object-Adapters. Read all the material you can find carefully. Then you should be able to do what you want to achieve.
Quote from: xsupermetroidx on July 07, 2015, 06:10:01
KeyListener and MouseListener are interfaces. You can create your own class that implements KeyListener/MouseListener and manually convert GLFW's event outputs into KeyListener/MouseListener inputs.

This is something I had been thinking about earlier today. The fact that this is now the 3rd suggestion on adapters (and this one specifically about object, rather than class, adapters) seems like a good fit to some of the things I had in mind.

Thanks to everyone for the responses and help. :)

-x