libGDX 1.8.0 released

libGDX 1.8.0

Oh boy do we have a nice release for you this time! Scroll past the change log for an explanation of all the new shiny things!

- API Change: Rewrote FreeType shadow rendering (much better).
- Added spaceX/Y to FreeType fonts.
- Higher quality FreeType font rendering.
- Hiero updated to v5, now with FreeType support and other new features!
- GlyphLayout now allocates much, much less memory when processing long text that wraps.
- Added LWJGL 3 backend, see for more info.
- Added Graphics#getFramebufferWidth and Graphics#getFramebufferHeight for HDPI handling
- API Change: Added HdpiUtils. Instead of calling GL20#glViewport and GL20#glScissor yourself
  please use HdpiUtils instead. It will ensure that you handle HDPI monitors correctly when
  using those OpenGL functions. On HDPI monitors, the size reported by 
  getWidth/getHeight is in logical coordinates as dictated by the operating system, usually half
  the HDPI resolution. The OpenGL drawing surface works in backbuffer coordinates at the full
  HDPI resolution. If you pass logical coordinates to glViewport and glScissor, you only 
  affect a quarter of the real backbuffer size. Use HdpiUtils instead, it will do the right thing, while letting you continue to work in logical (aka returned by coordinates.
- API Change: Graphis#getDesktopDisplayMode() has been renamed to Graphics#getDisplayMode() and
  returns the current display mode of the monitor the window is shown on (primary monitor on
  all backends except LWJGL3, which supports real multi-monitor setups).
- API Change: Graphics#getDisplayModes() return the display modes of the monitor the monitor
  the window is shown on (primary monitor on all backends except LWJGL3 which supports real
  multi-monitor setups).
- API Change: Graphics#setDisplayMode(DisplayMode) has been renamed to 
  Graphics#setFullscreenMode(). If the window is in windowed mode, it will be switched 
  to fullscreen mode on the monitor from which the DisplayMode stems from.
- API Change: Graphics#setDisplayMode(int, int, boolean) has been renamed to 
  Graphics#setWindowedMode(int, int). This will NOT allow you to switch to fullscreen anymore, 
  use Graphics#setFullscreenMode() instead. If the window is in fullscreen mode, it will be
  switched to windowed mode on the monitor the window was in fullscreen mode on.
 - API Addition: Graphics#Monitor, represents a monitor connected to the machine the app is
  running on. A monitor is defined by a name and it's position relative to other connected
  monitors. All backends except the LWJGL3 backend will report only the primary monitor
 - API Addition: Graphics#getPrimaryMonitor() returns the primary monitor you usually want
  to work with.
 - API Addition: Graphics#getMonitor() returns the monitor your app's window is shown on,
  which may not be the primary monitor in >= 2 monitor systems. All backends except the 
  LWJGL3 backend will report only the primary monitor.
 - API Addition: Graphics#getMonitors() returns all monitors connected to the system. All
  backends except the LWJGL3 backend will only report the primary monitor.
 - API Addition: Graphics#getDisplayMode(Monitor) returns the display mode of the monitor
  the app's window is shown on. All backends except the LWJGL3 backend will report the
  primary monitor display mode instead of the actual monitor's display mode. Not a problem
  as all other backends run on systems with only a single monitor so far (primary monitor).
- Added option to include credentials on cross-origin http requests (used only for GWT backend).
- Added option to specify crossorigin attribute when loading images with AssetDownloader (GWT), see #3216.
- API Change: removed Sound#setPriority, this was only implemented for the Android backend. However, Android itself never honoured priority settings.
- API Change: cursor API has been cleaned up. To create a custom cursor, call Graphics#newCursor(), to set the custom cursor call Graphics#setCursor(), to set a system cursor call Graphics#setSystemCursor(). The Cursor#setSystemCursor method has been removed as that was not the
right place. Note that cursors only work on the LWJGL, LWJGL3 and GWT backends. Note that system cursors only fully work on LWJGL3 as the other two backends lack a means to set a specific system cursor. These backends fall back to displaying an arrow cursor when setting any system cursor.
- API Addition: Added Lwjgl3WindowListener, allows you to hook into per-window iconficiation, focus and close events. Also allows you to prevent closing the window when a close event arrives.

Update your project as usual.

While we try to be as backward compatible as possible, occasionally we find ways to improve the API, introducing breaking changes. Let’s look at what has changed.

New monitor API

It’s a multi-monitor world. Nothing is more frustrating than an app using the wrong monitor. With this release, we introduce a new monitor API. Here’s how it works.

To get a list of all monitors, ask Graphics:

Every Monitor has a name and a virtual position. All monitors together span a virtual surface with the top-left most monitor being the origin. The virtual position of a monitor is expressed in this coordinate system.

Every monitor setup also has what’s called a primary monitor. This is the monitor that usually hosts the task bar. You can get the primary monitor as follows:

All backends except the new LWJGL3 backend only report and work on the primary monitor. This is due to platform and/or API limitations imposed on these backends.

To figure out what monitor a window is on do this:

The methods Graphics#getPpiX(), Graphics#getPpiY(), Graphics#getPpcX(), Graphics#getPpcY() and Graphics#getDensity() will now return the various densities of the monitor the window is located on.

Display mode API changes

Enumerating display modes and setting a window to fullscreen or windowed mode has also changed slightly.

Display mode enumeration is now aware of monitors. As with the monitor API, all backends except for the LWJGL3 backend will only report the primary monitor. To retrieve the display modes of a specific monitor call:

As a shortcut, you can also get the display modes of the monitor your window is currently on:

Previously, this method would return the display modes of the primary monitor, not the display modes your window is on.

Finally, there’s an API breaking change. The method Graphics#getDesktopDisplayMode() has been replaced Graphics#getDisplayMode(). Before, the method would only return the current display mode of the primary monitor. With this release, the method returns the display monitor your window is on!

All of these monitor aware display mode methods allow you to make your users happier. Switching from windowed to fullscreen mode will now do the right thing, i.e. go fullscreen on the monitor the window is on instead of the primary monitor!

Note again that all this capabilities are only implemented in the new LWJGL3 backend. Old backends will still only operate on the primary monitor.

Fullscreen and windowed mode API changes

Previously, we exposed changes between fullscreen and windowed mode with two overloaded methods, Graphics#setDisplayMode(DisplayMode mode) and Graphics#setDisplayMode(int width, int height, boolean fullscreen). This was a bit muddled. We’ve therefor made a clear distinction between setting fullscreen modes and windowed modes. To set a fullscreen mode, you need a DisplayMode instance for a specific monitor. Here’s what you’d generally want to do:

I’d recommend always using the current display mode of the monitor the window is on, as that is least likely to fail.

Of course you can also set the window to fullscreen on a different monitor:

Here we fetch all monitors, pick one based on some criteria (e.g. highest current resolution), then tell libGDX to make the current window fullscreen on that monitor using the specified display mode.

Finally, to go back to windowed mode, we call this method:

This will make set the window to windowed mode, positioning it in the center of the monitor it’s currently on. You can also use this method to change the size of the window in windowed mode.

As with the monitor and display mode API, only the new LWJGL3 backend will work with all monitors, while the old backends only work with the primary monitor.

Dealing with HDPI screens

HDPI screen handling is a complicated topic. On iOS and Android, we got you (mostly) covered via the Graphics#getDensity() and Graphics#getPpiXXX() methods. On desktop systems, those values may not be precise, especially on Windows (they are perfect on Mac OS X most of the time).

Every desktop operating system deals with HDPI differently. The general principal is quite similar though. The operating system has a scale factor, either per monitor as it should be, or a global one (Windows < 8.1, booh). Your UI then works in logical coordinates based on the scale factor. The actual rendering is then performed in pixel coordinates to a drawing surface (back buffer). That back buffer can have the same resolution as your logical coordinate system, in which case the OS will simply upscale it to the full HDPI resolution once you are done rendering. This results in blurriness and other artifacts. The alternative is for the OS to provide you with a higher resolution back buffer. Your UI code still works in the logical coordinate system, but your rendering is performed on a full resolution back buffer, resulting in crisp pixels. To give you an example: on a Mac Book Pro retina, the OS would tell you your window is 640×480 pixels in logical units, but provides you with a back buffer of resolution 1280×960.

All this leads to two new API additions for dealing with HDPI displays in libGDX. The first one allows you to poll the actual back buffer size, which may be different from the logical size of your window’s client area as reported by Graphics#getWidth() and Graphics#getHeight(). The two methods are called Graphics#getBackBufferWidth() and Graphics#getBackBufferHeight(). When should you use them?

Every time you specify pixel coordinates to an OpenGL call you should use the back buffer size instead of the logical size. OpenGL only has a handful of calls for which this is relevant:

Since it’s easy to mess this up, we provide you with a new class called HdpiUtils which will do the right thing automatically for you.

It expects logical coordinates and will automatically translate them to the back buffer resolution. All internal libGDX classes like ScissorStack have been changed to this way of doing things.

In general, if you haven’t cared for HDPI displays on the desktop until now, there’s nothing that has changed for you, expect for the calls to glViewport and glScissor, which now require you to pass back buffer sizes instead of logical window sizes.

All input events will still be reported in logical coordinates instead of back buffer coordinates.

Note that only the new LWJGL3 backend is aware of differences in logical and pixel sizes so far. Older backends continue to work as before.

Cursor API changes

The old API allowed you to create custom cursors but had no way to use system cursors. Also, resources of custom cursors were never deallocated, opening up the potential for (minor) memory leaks. We changed this API to be more functional and to properly dispose of resources when they are no longer needed.

To create a new custom mouse cursor, use this method:

The Pixmap can be loaded from an image file as usual, or composed at runtime. Whatever you choose, it has to have the format Pixmap.Format#RGBA8888. The two other parameters specify the hotspot position of the cursor relative to the pixmap. You can dispose the pixmap you pass into this method if you no longer need it, the backend will make a copy of it.

To set the custom cursor, call this method:

The final piece of the puzzle is to set the cursor to a system cursor. Previously, this was not quite possible. We introduced a new method to do just that:

The SystemCursor enum provides you with all standard system cursors you’d expect (expect that pesky hour glass one, working on it!).

Once you no longer use your custom cursor, dispose it to free all associated resources:

If you forget about this, the backend will actually dispose it for you when the application is closed.

Sound API changes

The Sound class had a method called setPriority() which was supposed to set the, well, priority of the sound relative to other sounds being played back. This was only implemented for the Android backend.

Problem is, that method didn’t work on Android, and it’s unlikely it will ever get implemented on other backends. As such, we decided to remove that method.

New LWJGL 3 backend

Our old LWJGL backend has been around for quite a few years now. It’s based on the latest LWJGL 2 release version (2.9.3) and works quite well. However, there are few minor issues, e.g. dealing with HDPI, multi-monitor setups, and so on, that prompted us to look into a new implementation based on LWJGL 3. LWJGL 3 is based on GLFW an excellent cross-platform windowing toolkit abstraction specifically focused on OpenGL applications like games. It allows us to do a metric ton of things (see above and below) that were not possible with the LWJGL 2 backend. Let’s see what it has in store!

Switching from LWJGL 2 to LWJGL 3

The new LWJGL 3 backend does not yet replace the LWJGL 2 backend. It’s only about a week old, and while exceptionally stable already, still needs more testing to become the default. If you have some time on your hand, please switch your projects over to the new LWJGL 3 backend and report any issues you find.

To switch to LWJGL 3, open your build.gradle file and and make sure you are using libGDX version 1.8.0 or 1.8.1-SNAPSHOT. Next, replace the LWJGL backend dependency:

with the LWJGL 3 backend dependency:

Additionally, if you use the controllers extensions, add the LWJGL 3 controllers backend to your desktop project’s dependencies:

Next, you need to fix up your desktop launcher class. It should look something like this:

You’ll need to change it to this:

And that’s it! Everything should pretty much work right out of the box. If your desktop launcher enumerated display modes, you can do this with the new Lwjgl3ApplicationConfiguration as well. Note that I opted to use setters instead of public fields this time. Check out the code for the configuration class to learn what’s available to you.

LWJGL 3 backend specific APIs

One of the main motivators for writing this backend for me was to be able to do multi-window, multi-monitor applications, such as editors and similar tools. It’s also aimed at being more robust for desktop games, specifically when it comes to desktop UI events such as iconficiation (minimization), focus changes and so on.

The LWJGL 3 backend provides a couple of backend specific APIs to help write desktop class applications with ease.

Window events

Our ApplicationListener interface pipes cross-platform events to your app, such as creation, pause/resume, resize and rendering. This is the lowest common denominator that all platforms expose. However, desktop class applications require additional events to behave as expected.

Iconification (minimization and restoration) of your window is such an event. If your app is iconified, your ApplicationListener will be paused, and rendering will not be performed until the app is restored again. While you can catch this event with the standard ApplicationListener interface, we felt it’d be nice to expose the actual event to you.

Focus loss and gain is another class of events that is specific to desktop applications. The difference to iconification is that your app may still be visible partially on screen and will thus not be paused. As such, you may want to continue rendering, stop audio, stop updating your game logic and welcome the user with a “Continue” screen once the focus is gained again”. This is usually not available on other platforms such as Android or iOS, where a focus loss means the screen is entirely replaced with another app, and your app will be properly paused.

Finally, the user can close your app via buttons on the window or keyboard shortcuts. Again, this is reported to your ApplicationListener in form of pause and dispose events already. However, you may not want the window to be closed but instead prompt the user to save her progress.

All these desktop specific events are now available to you via the LWJGL 3 backend. We created a new interface called Lwjgl3WindowListener. As the name indicates, this interface is backend specific and may only be used from your desktop project. I’m considering making it a general interface available in from the core API.

To set a Lwjgl3WindowListener for your window, specify it in the Lwjgl3ApplicationConfiguration:

In the above example, we tell the MyApplicationListener via custom methods to do “the right thing”(tm). In the windowIsClosing() method we also ask the listener to tell us whether the window should really be closed. If it returns false, it can happily continue rendering, e.g. a prompt asking the user to save her progress.

Multi-window support

Screen Shot 2016-01-05 at 15.29.42

The by far coolest feature of the new LWJGL 3 backend is multi-window support (closely followed by multi-monitor support). The screenshot above was generated via the the multi-window test:

Each window has its own ApplicationListener. To create a new window, you need to cast to Lwjgl3Application, then call app.newWindow(), passing in an ApplicationListener and a Lwjgl3WindowConfiguration.

The LWJGL 3 backend will then happily process both of your windows! Each window receives its own Graphics and Input instance. When the ApplicationListener of a window is called, the statics and Gdx.input are set to the appropriate instances, so everything is as seemless as it can be.

The Lwjgl3Window class has additional methods that let you interact with that specific window. You can set and get the position of the window in the virtual monitor coordinate system, you can iconify and deiconify the window, hide and show it and close it (without closing other windows of your app).

All your normal OpenGL resources like textures, shaders or meshes are shared between all windows. All ApplicationListeners are called on the same thread so you don’t run into multi-threading issues. Of course, if one of your windows is super slow at rendering, the other windows will also suffer. This is not so much laziness on our part, but a limitation of GLFW, which requires us to do everything on the same main thread for all windows.

The only pitfall with this new API is when you post a Runnable via When your Runnable is executed, the statics and Gdx.input may not be set to the instances specific to your window. If you for example query the current width or height of your window in your runnable via the statics, you may get the values from another window (the last one that was processed).

To make sure the statics are the correct ones for your window on which the Runnable should act, use Lwjgl3Window#postRunnable() instead. This will ensure that if your Runnable accesses the statics, they are the correct ones.

LWJGL 3 Controllers backend

LWJGL 3 also has a new controller API for joysticks and gamepads, courtesy of GLFW. This API allows us to finally report connect and disconnect events of individual gamepads on the desktop. All you need to do is to add the gdx-controllers-lwjgl3 dependency to your desktop project as described above.

Known Issue

As said in the introduction, the LWJGL 3 backend is only a week old at this point. I encourage everyone to switch over to it and report issues on our issue tracker. My goal is it to make this backend the default in the next release, then remove the old LWJGL 2 backend in the release after the next one.

Here are the known issues we are still working on:

  • On Mac OS X, you need to specify “-XstartOnFirstThread” as a VM argument when running your app. GLFW requires this. It’s unlikely this can be fixed in code.
  • On Mac OS X, no support for AWT and Swing. If your desktop app relied on either APIs to show dialogs or read images, you will have to find a replacement. LWJGL 3 has added support for native dialogs, which should cover all bases. I’ll expose these APIs in Lwjgl3Window soon.
  • On Mac OS X, if you use gdx-tools in your app, please call System.setProperty("java.awt.headless", "true"); before any other code!
  • On Mac OS X, when minimizing an app or having it fully obscured by a window, the vsync setting is not honored, burning a whole into your CPU. This is a known bug in GLFW which will hopefully be fixed for their 3.2 release. If not, we’ll add a fix on our end.
  • Non-continuous rendering is not supported.
  • On Mac OS X, switching to a fullscreen resolution that’s not a multiple of the current monitor resolution fails. This is a known bug in GLFW
  • On Windows, switching to fullscreen on a HDPI monitor can fail in various ways. This is a known bug in GLFW.
  • On Windows, gamepad names are all the same, irrespective of the model. This makes mapping to specific gamepads impossible. This is a known bug in GLFW.
  • The application icon can currently not be set. This will be fixed in LWJGL. For Mac OS X, an app bundle must be generated, e.g. via packr, which is good practice anyways.
  • Lwjgl3GL30#glGetBufferPointerv() currently throws an exception.
  • Lwjgl3Input#getTextInput() is not implemented as we lack support for AWT/Swing. Use Scene2D instead
  • Lwjgl3Net#openURI() relies on AWT and currently does not work on Mac OS X


Special thanks go out to all my core contributors who helped with this release. I’d also like to thank Ioannis Tsakpinis of LWJGL fame, who supported me tremendously while implementing the new backend.

12 thoughts on “libGDX 1.8.0 released

  1. Awesome! I’ve really been looking forward to multi-monitor support. It’ll be nice to be able to fullscreen my game on whichever monitor I want!

  2. That’s an awesome new year gift, thanks! : ) I’m really looking forward to that LWJGL3 backend.

  3. A quick and mostly unrelated question, Mario: you mention LWJGL 2.9.3 in the post, but I was under the impression that libGDX used 2.9.2 (as per the pom.xml and backends/gdx-backend-lwjgl/libs/lwjgl.jar files) – am I missing something? Not exactly important given the impending switch to LWJGL 3, just me being curious. : p

  4. Hi Mario, It would be great if you add a hide cursor option:


  5. “Not a problem
    as all other backends run on systems with only a single monitor so far (primary monitor).” – unfortunately it seems to be a problem on my system. The resolution I get is for the bigger monitor (secondary screen), while the game starts on smaller monitor (laptop screen, primary)…

Leave a Reply

Your email address will not be published.