Bläddra i källkod

added supporting window icons for LWJGL3

javasabr 9 år sedan
förälder
incheckning
190f30afe5
1 ändrade filer med 146 tillägg och 14 borttagningar
  1. 146 14
      jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java

+ 146 - 14
jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java

@@ -43,19 +43,69 @@ import com.jme3.system.AppSettings;
 import com.jme3.system.JmeContext;
 import com.jme3.system.JmeSystem;
 import com.jme3.system.NanoTimer;
-import org.lwjgl.glfw.*;
+import com.jme3.util.BufferUtils;
+
+import org.lwjgl.Version;
+import org.lwjgl.glfw.GLFWErrorCallback;
+import org.lwjgl.glfw.GLFWImage;
+import org.lwjgl.glfw.GLFWVidMode;
+import org.lwjgl.glfw.GLFWWindowFocusCallback;
+import org.lwjgl.glfw.GLFWWindowSizeCallback;
+import org.lwjgl.stb.STBImage;
 
 import java.awt.*;
 import java.awt.image.BufferedImage;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
 import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import org.lwjgl.Version;
 
-import static org.lwjgl.glfw.GLFW.*;
+import javax.imageio.ImageIO;
+
+import static org.lwjgl.glfw.GLFW.GLFW_ALPHA_BITS;
+import static org.lwjgl.glfw.GLFW.GLFW_BLUE_BITS;
+import static org.lwjgl.glfw.GLFW.GLFW_CONTEXT_VERSION_MAJOR;
+import static org.lwjgl.glfw.GLFW.GLFW_CONTEXT_VERSION_MINOR;
+import static org.lwjgl.glfw.GLFW.GLFW_DEPTH_BITS;
+import static org.lwjgl.glfw.GLFW.GLFW_DOUBLEBUFFER;
+import static org.lwjgl.glfw.GLFW.GLFW_FALSE;
+import static org.lwjgl.glfw.GLFW.GLFW_GREEN_BITS;
+import static org.lwjgl.glfw.GLFW.GLFW_OPENGL_CORE_PROFILE;
+import static org.lwjgl.glfw.GLFW.GLFW_OPENGL_DEBUG_CONTEXT;
+import static org.lwjgl.glfw.GLFW.GLFW_OPENGL_FORWARD_COMPAT;
+import static org.lwjgl.glfw.GLFW.GLFW_OPENGL_PROFILE;
+import static org.lwjgl.glfw.GLFW.GLFW_RED_BITS;
+import static org.lwjgl.glfw.GLFW.GLFW_REFRESH_RATE;
+import static org.lwjgl.glfw.GLFW.GLFW_RESIZABLE;
+import static org.lwjgl.glfw.GLFW.GLFW_SAMPLES;
+import static org.lwjgl.glfw.GLFW.GLFW_SRGB_CAPABLE;
+import static org.lwjgl.glfw.GLFW.GLFW_STENCIL_BITS;
+import static org.lwjgl.glfw.GLFW.GLFW_STEREO;
+import static org.lwjgl.glfw.GLFW.GLFW_TRUE;
+import static org.lwjgl.glfw.GLFW.GLFW_VISIBLE;
+import static org.lwjgl.glfw.GLFW.glfwCreateWindow;
+import static org.lwjgl.glfw.GLFW.glfwDefaultWindowHints;
+import static org.lwjgl.glfw.GLFW.glfwDestroyWindow;
+import static org.lwjgl.glfw.GLFW.glfwGetPrimaryMonitor;
+import static org.lwjgl.glfw.GLFW.glfwGetVideoMode;
+import static org.lwjgl.glfw.GLFW.glfwInit;
+import static org.lwjgl.glfw.GLFW.glfwMakeContextCurrent;
+import static org.lwjgl.glfw.GLFW.glfwPollEvents;
+import static org.lwjgl.glfw.GLFW.glfwSetErrorCallback;
+import static org.lwjgl.glfw.GLFW.glfwSetWindowFocusCallback;
+import static org.lwjgl.glfw.GLFW.glfwSetWindowIcon;
+import static org.lwjgl.glfw.GLFW.glfwSetWindowPos;
+import static org.lwjgl.glfw.GLFW.glfwSetWindowSizeCallback;
+import static org.lwjgl.glfw.GLFW.glfwSetWindowTitle;
+import static org.lwjgl.glfw.GLFW.glfwShowWindow;
+import static org.lwjgl.glfw.GLFW.glfwSwapBuffers;
+import static org.lwjgl.glfw.GLFW.glfwSwapInterval;
+import static org.lwjgl.glfw.GLFW.glfwWindowHint;
+import static org.lwjgl.glfw.GLFW.glfwWindowShouldClose;
 import static org.lwjgl.opengl.GL11.GL_FALSE;
-import static org.lwjgl.opengl.GL11.GL_TRUE;
 import static org.lwjgl.system.MemoryUtil.NULL;
 
 /**
@@ -67,15 +117,10 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
 
     private static final Logger LOGGER = Logger.getLogger(LwjglWindow.class.getName());
 
-    protected AtomicBoolean needClose = new AtomicBoolean(false);
+    protected final AtomicBoolean needClose = new AtomicBoolean(false);
     protected final AtomicBoolean needRestart = new AtomicBoolean(false);
-    protected boolean wasActive = false;
-    protected boolean autoFlush = true;
-    protected boolean allowSwapBuffers = false;
-    private long window = NULL;
+
     private final JmeContext.Type type;
-    private int frameRateLimit = -1;
-    private double frameSleepTime;
 
     private GLFWErrorCallback errorCallback;
     private GLFWWindowSizeCallback windowSizeCallback;
@@ -83,6 +128,14 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
 
     private Thread mainThread;
 
+    private double frameSleepTime;
+    private long window = NULL;
+    private int frameRateLimit = -1;
+
+    protected boolean wasActive = false;
+    protected boolean autoFlush = true;
+    protected boolean allowSwapBuffers = false;
+
     public LwjglWindow(final JmeContext.Type type) {
         if (!JmeContext.Type.Display.equals(type) && !JmeContext.Type.OffscreenSurface.equals(type) && !JmeContext.Type.Canvas.equals(type)) {
             throw new IllegalArgumentException("Unsupported type '" + type.name() + "' provided");
@@ -171,7 +224,7 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
         glfwWindowHint(GLFW_VISIBLE, GL_FALSE);
         glfwWindowHint(GLFW_RESIZABLE, settings.isResizable() ? GLFW_TRUE : GLFW_FALSE);
 
-        //glfwWindowHint(GLFW_DOUBLE_BUFFER, GLFW_TRUE);
+        glfwWindowHint(GLFW_DOUBLEBUFFER, GLFW_TRUE);
         glfwWindowHint(GLFW_DEPTH_BITS, settings.getDepthBits());
         glfwWindowHint(GLFW_STENCIL_BITS, settings.getStencilBits());
         glfwWindowHint(GLFW_SAMPLES, settings.getSamples());
@@ -271,12 +324,91 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
             glfwSwapInterval(0);
         }
 
+        final Object[] icons = settings.getIcons();
+
+        if (icons != null) {
+
+            final GLFWImage[] images = imagesToGLFWImages(icons);
+            final GLFWImage.Buffer iconSet = GLFWImage.malloc(images.length);
+
+            for (int i = images.length - 1; i >= 0; i--) {
+                final GLFWImage image = images[i];
+                iconSet.put(i, image);
+            }
+
+            glfwSetWindowIcon(window, iconSet);
+
+            iconSet.free();
+
+            for (final GLFWImage image : images) {
+                image.free();
+            }
+        }
 
         glfwShowWindow(window);
 
         allowSwapBuffers = settings.isSwapBuffers();
+    }
 
-        // TODO: When GLFW 3.2 is released and included in LWJGL 3.x then we should hopefully be able to set the window icon.
+    /**
+     * Convert array of images to array of {@link GLFWImage}.
+     */
+    private GLFWImage[] imagesToGLFWImages(final Object[] images) {
+
+        final GLFWImage[] out = new GLFWImage[images.length];
+
+        for (int i = 0; i < images.length; i++) {
+            final BufferedImage image = (BufferedImage) images[i];
+            out[i] = imageToGLFWImage(image);
+        }
+
+        return out;
+    }
+
+    /**
+     * Convert the {@link BufferedImage} to the {@link GLFWImage}.
+     */
+    private GLFWImage imageToGLFWImage(BufferedImage image) {
+
+        if (image.getType() != BufferedImage.TYPE_INT_ARGB_PRE) {
+
+            final BufferedImage convertedImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB_PRE);
+            final Graphics2D graphics = convertedImage.createGraphics();
+
+            final int targetWidth = image.getWidth();
+            final int targetHeight = image.getHeight();
+
+            graphics.drawImage(image, 0, 0, targetWidth, targetHeight, null);
+            graphics.dispose();
+
+            image = convertedImage;
+        }
+
+        final IntBuffer w = BufferUtils.createIntBuffer(1);
+        final IntBuffer h = BufferUtils.createIntBuffer(1);
+        final IntBuffer comp = BufferUtils.createIntBuffer(1);
+
+        final ByteArrayOutputStream bout = new ByteArrayOutputStream(4096);
+        try {
+            ImageIO.write(image, "png", bout);
+        } catch (final IOException e) {
+            throw new RuntimeException(e);
+        }
+
+        final byte[] bytes = bout.toByteArray();
+
+        final ByteBuffer buffer = BufferUtils.createByteBuffer(bytes.length);
+        buffer.put(bytes);
+        buffer.flip();
+
+        final ByteBuffer pixels = STBImage.stbi_load_from_memory(buffer, h, w, comp, 4);
+
+        BufferUtils.destroyDirectBuffer(buffer);
+
+        final GLFWImage result = GLFWImage.create();
+        result.set(w.get(0), h.get(0), pixels);
+
+        return result;
     }
 
     /**
@@ -307,7 +439,7 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
                 glfwDestroyWindow(window);
                 window = NULL;
             }
-        } catch (Exception ex) {
+        } catch (final Exception ex) {
             listener.handleError("Failed to destroy context", ex);
         }
     }