2 package com.badlogic.gdx.backends.jglfw;
4 import static com.badlogic.jglfw.Glfw.*;
6 import com.badlogic.gdx.ApplicationListener;
7 import com.badlogic.gdx.Gdx;
8 import com.badlogic.gdx.Graphics;
9 import com.badlogic.gdx.graphics.Color;
10 import com.badlogic.gdx.graphics.GL10;
11 import com.badlogic.gdx.graphics.GL11;
12 import com.badlogic.gdx.graphics.GL20;
13 import com.badlogic.gdx.graphics.GLCommon;
14 import com.badlogic.gdx.utils.Array;
15 import com.badlogic.gdx.utils.GdxRuntimeException;
16 import com.badlogic.jglfw.GlfwVideoMode;
17 import com.badlogic.jglfw.gl.GL;
19 import java.awt.Toolkit;
21 /** An implementation of the {@link Graphics} interface based on GLFW.
22 * @author Nathan Sweet */
23 public class JglfwGraphics implements Graphics {
24 static int glMajorVersion, glMinorVersion;
27 private boolean fullscreen;
28 private long fullscreenMonitor;
30 private boolean resizable, undecorated;
31 private BufferFormat bufferFormat;
32 private boolean vSync;
33 private int x, y, width, height;
34 private boolean visible;
35 private Color initialBackgroundColor;
36 private volatile boolean isContinuous = true, renderRequested;
37 volatile boolean foreground, minimized;
39 private float deltaTime;
40 private long frameStart, lastTime = -1;
41 private int frames, fps;
44 private JglfwGL10 gl10;
45 private JglfwGL11 gl11;
46 private JglfwGL20 gl20;
48 public JglfwGraphics (JglfwApplicationConfiguration config) {
49 // Store values from config.
50 bufferFormat = new BufferFormat(config.r, config.g, config.b, config.a, config.depth, config.stencil, config.samples, false);
52 resizable = config.resizable;
53 undecorated = config.undecorated;
57 initialBackgroundColor = config.initialBackgroundColor;
58 if (config.fullscreenMonitorIndex != -1) { // Use monitor specified in config if it is valid.
59 long[] monitors = glfwGetMonitors();
60 if (config.fullscreenMonitorIndex < monitors.length) fullscreenMonitor = monitors[config.fullscreenMonitorIndex];
64 if (!createWindow(config.width, config.height, config.fullscreen)) {
65 throw new GdxRuntimeException("Unable to create window: " + config.width + "x" + config.height + ", fullscreen: "
70 String version = GL.glGetString(GL11.GL_VERSION);
71 glMajorVersion = Integer.parseInt("" + version.charAt(0));
72 glMinorVersion = Integer.parseInt("" + version.charAt(2));
73 if (config.useGL20 && (glMajorVersion >= 2 || version.contains("2.1"))) { // special case for MESA, wtf...
74 gl20 = new JglfwGL20();
78 if (glMajorVersion == 1 && glMinorVersion < 5)
79 gl10 = new JglfwGL10();
81 gl11 = new JglfwGL11();
91 if (!config.hidden) show();
94 private boolean createWindow (int width, int height, boolean fullscreen) {
95 if (fullscreen && fullscreenMonitor == 0) fullscreenMonitor = getWindowMonitor();
97 glfwWindowHint(GLFW_VISIBLE, 0);
98 glfwWindowHint(GLFW_RESIZABLE, resizable ? 1 : 0);
99 glfwWindowHint(GLFW_UNDECORATED, undecorated ? 1 : 0);
100 glfwWindowHint(GLFW_RED_BITS, bufferFormat.r);
101 glfwWindowHint(GLFW_GREEN_BITS, bufferFormat.g);
102 glfwWindowHint(GLFW_BLUE_BITS, bufferFormat.b);
103 glfwWindowHint(GLFW_ALPHA_BITS, bufferFormat.a);
104 glfwWindowHint(GLFW_DEPTH_BITS, bufferFormat.depth);
105 glfwWindowHint(GLFW_STENCIL_BITS, bufferFormat.stencil);
106 glfwWindowHint(GLFW_SAMPLES, bufferFormat.samples);
108 boolean mouseCaptured = window != 0 && glfwGetInputMode(window, GLFW_CURSOR_MODE) == GLFW_CURSOR_CAPTURED;
110 long oldWindow = window;
111 long newWindow = glfwCreateWindow(width, height, title, fullscreen ? fullscreenMonitor : 0, oldWindow);
112 if (newWindow == 0) return false;
113 if (oldWindow != 0) glfwDestroyWindow(oldWindow);
115 this.width = Math.max(1, width);
116 this.height = Math.max(1, height);
118 this.fullscreen = fullscreen;
120 if (x == -1 || y == -1) {
121 DisplayMode mode = getDesktopDisplayMode();
122 x = (mode.width - width) / 2;
123 y = (mode.height - height) / 2;
125 glfwSetWindowPos(window, x, y);
128 if (!mouseCaptured) glfwSetInputMode(window, GLFW_CURSOR_MODE, GLFW_CURSOR_NORMAL); // Prevent fullscreen from taking mouse.
130 glfwMakeContextCurrent(newWindow);
132 if (visible) glfwShowWindow(window);
137 void frameStart (long time) {
138 if (lastTime == -1) lastTime = time;
139 deltaTime = (time - lastTime) / 1000000000.0f;
142 if (time - frameStart >= 1000000000) {
150 void sizeChanged (int width, int height) {
151 width = Math.max(1, width);
152 height = Math.max(1, height);
154 this.height = height;
155 Gdx.gl.glViewport(0, 0, width, height);
156 ApplicationListener listener = Gdx.app.getApplicationListener();
157 if (listener != null) listener.resize(width, height);
161 void positionChanged (int x, int y) {
166 public boolean isGL11Available () {
170 public boolean isGL20Available () {
174 public GLCommon getGLCommon () {
178 public GL10 getGL10 () {
182 public GL11 getGL11 () {
186 public GL20 getGL20 () {
190 public int getWidth () {
194 public int getHeight () {
198 public float getDeltaTime () {
202 public float getRawDeltaTime () {
206 public int getFramesPerSecond () {
210 public GraphicsType getType () {
211 return GraphicsType.JGLFW;
214 public float getPpiX () {
215 // return getWidth() / (glfwGetMonitorPhysicalWidth(getWindowMonitor()) * 0.03937f); // mm to inches
216 return Toolkit.getDefaultToolkit().getScreenResolution();
219 public float getPpiY () {
220 // return getHeight() / (glfwGetMonitorPhysicalHeight(getWindowMonitor()) * 0.03937f); // mm to inches
221 return Toolkit.getDefaultToolkit().getScreenResolution();
224 public float getPpcX () {
225 // return getWidth() / (glfwGetMonitorPhysicalWidth(getWindowMonitor()) / 10); // mm to cm
226 return Toolkit.getDefaultToolkit().getScreenResolution() / 2.54f;
229 public float getPpcY () {
230 // return getHeight() / (glfwGetMonitorPhysicalHeight(getWindowMonitor()) / 10); // mm to cm
231 return Toolkit.getDefaultToolkit().getScreenResolution() / 2.54f;
234 public float getDensity () {
235 // long monitor = getWindowMonitor();
236 // float mmWidth = glfwGetMonitorPhysicalWidth(monitor);
237 // float mmHeight = glfwGetMonitorPhysicalHeight(monitor);
238 // float inches = (float)Math.sqrt(mmWidth * mmWidth + mmHeight * mmHeight) * 0.03937f; // mm to inches
239 // float pixelWidth = getWidth();
240 // float pixelHeight = getHeight();
241 // float pixels = (float)Math.sqrt(pixelWidth * pixelWidth + pixelHeight * pixelHeight);
242 // float diagonalPpi = pixels / inches;
243 // return diagonalPpi / 160f;
244 return Toolkit.getDefaultToolkit().getScreenResolution() / 160f;
247 public boolean supportsDisplayModeChange () {
251 private long getWindowMonitor () {
253 long monitor = glfwGetWindowMonitor(window);
254 if (monitor != 0) return monitor;
256 return glfwGetPrimaryMonitor();
259 public DisplayMode[] getDisplayModes () {
260 Array<DisplayMode> modes = new Array();
261 for (GlfwVideoMode mode : glfwGetVideoModes(getWindowMonitor()))
262 modes.add(new JglfwDisplayMode(mode.width, mode.height, 0, mode.redBits + mode.greenBits + mode.blueBits));
263 return modes.toArray(DisplayMode.class);
266 public DisplayMode getDesktopDisplayMode () {
267 GlfwVideoMode mode = glfwGetVideoMode(getWindowMonitor());
268 return new JglfwDisplayMode(mode.width, mode.height, 0, mode.redBits + mode.greenBits + mode.blueBits);
271 public boolean setDisplayMode (DisplayMode displayMode) {
272 bufferFormat = new BufferFormat( //
273 displayMode.bitsPerPixel == 16 ? 5 : 8, //
274 displayMode.bitsPerPixel == 16 ? 6 : 8, //
275 displayMode.bitsPerPixel == 16 ? 6 : 8, //
276 bufferFormat.a, bufferFormat.depth, bufferFormat.stencil, bufferFormat.samples, false);
277 boolean success = createWindow(displayMode.width, displayMode.height, fullscreen);
278 if (success && fullscreen) sizeChanged(displayMode.width, displayMode.height);
282 public boolean setDisplayMode (int width, int height, boolean fullscreen) {
283 if (fullscreen || this.fullscreen) {
284 boolean success = createWindow(width, height, fullscreen);
285 if (success && fullscreen) sizeChanged(width, height);
289 glfwSetWindowSize(window, width, height);
293 public void setTitle (String title) {
294 if (title == null) title = "";
295 glfwSetWindowTitle(window, title);
299 public void setVSync (boolean vsync) {
301 glfwSwapInterval(vsync ? 1 : 0);
304 public BufferFormat getBufferFormat () {
308 public boolean supportsExtension (String extension) {
309 return glfwExtensionSupported(extension);
312 public void setContinuousRendering (boolean isContinuous) {
313 this.isContinuous = isContinuous;
316 public boolean isContinuousRendering () {
320 public void requestRendering () {
321 renderRequested = true;
324 public boolean isFullscreen () {
328 /** Returns the JGLFW window handle. Note this should not be stored externally as it may change if the window is recreated to
329 * enter/exit fullscreen. */
330 public long getWindow () {
342 public void setPosition (int x, int y) {
343 glfwSetWindowPos(window, x, y);
346 public void hide () {
348 glfwHideWindow(window);
351 public void show () {
353 glfwShowWindow(window);
355 Gdx.gl.glClearColor(initialBackgroundColor.r, initialBackgroundColor.g, initialBackgroundColor.b, initialBackgroundColor.a);
356 Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
357 glfwSwapBuffers(window);
360 public boolean isHidden () {
364 public boolean isMinimized () {
368 public boolean isForeground () {
372 public void minimize () {
373 glfwIconifyWindow(window);
376 public void restore () {
377 glfwRestoreWindow(window);
380 boolean shouldRender () {
382 return renderRequested || isContinuous;
384 renderRequested = false;
388 static class JglfwDisplayMode extends DisplayMode {
389 protected JglfwDisplayMode (int width, int height, int refreshRate, int bitsPerPixel) {
390 super(width, height, refreshRate, bitsPerPixel);