Przeglądaj źródła

Merge pull request #559 from JavaSaBr/master-original

added supporting window icons ans OffscreenSurface context for LWJGL3
empirephoenix 8 lat temu
rodzic
commit
c5a24eb5f0

+ 9 - 0
jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglOffscreenBuffer.java

@@ -31,6 +31,7 @@
  */
 package com.jme3.system.lwjgl;
 
+import com.jme3.system.AppSettings;
 import com.jme3.system.JmeContext;
 
 /**
@@ -41,4 +42,12 @@ public class LwjglOffscreenBuffer extends LwjglWindow {
     public LwjglOffscreenBuffer() {
         super(JmeContext.Type.OffscreenSurface);
     }
+
+    @Override
+    protected void showWindow() {
+    }
+
+    @Override
+    protected void setWindowIcon(final AppSettings settings) {
+    }
 }

+ 143 - 62
jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java

@@ -32,6 +32,48 @@
 
 package com.jme3.system.lwjgl;
 
+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_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.system.MemoryUtil.NULL;
+
 import com.jme3.input.JoyInput;
 import com.jme3.input.KeyInput;
 import com.jme3.input.MouseInput;
@@ -43,20 +85,21 @@ 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 java.awt.*;
+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 java.awt.Graphics2D;
 import java.awt.image.BufferedImage;
 import java.nio.ByteBuffer;
 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 static org.lwjgl.opengl.GL11.GL_FALSE;
-import static org.lwjgl.opengl.GL11.GL_TRUE;
-import static org.lwjgl.system.MemoryUtil.NULL;
 
 /**
  * A wrapper class over the GLFW framework in LWJGL 3.
@@ -67,15 +110,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 +121,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");
@@ -170,8 +216,6 @@ 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_DEPTH_BITS, settings.getDepthBits());
         glfwWindowHint(GLFW_STENCIL_BITS, settings.getStencilBits());
         glfwWindowHint(GLFW_SAMPLES, settings.getSamples());
@@ -271,12 +315,89 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
             glfwSwapInterval(0);
         }
 
+        setWindowIcon(settings);
+        showWindow();
+
+        allowSwapBuffers = settings.isSwapBuffers();
+    }
 
+    protected void showWindow() {
         glfwShowWindow(window);
+    }
 
-        allowSwapBuffers = settings.isSwapBuffers();
+    /**
+     * Set custom icons to the window of this application.
+     */
+    protected void setWindowIcon(final AppSettings settings) {
+
+        final Object[] icons = settings.getIcons();
+        if (icons == null) return;
+
+        final GLFWImage[] images = imagesToGLFWImages(icons);
+
+        try (final GLFWImage.Buffer iconSet = GLFWImage.malloc(images.length)) {
 
-        // TODO: When GLFW 3.2 is released and included in LWJGL 3.x then we should hopefully be able to set the window icon.
+            for (int i = images.length - 1; i >= 0; i--) {
+                final GLFWImage image = images[i];
+                iconSet.put(i, image);
+            }
+
+            glfwSetWindowIcon(window, iconSet);
+        }
+    }
+
+    /**
+     * 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 ByteBuffer buffer = BufferUtils.createByteBuffer(image.getWidth() * image.getHeight() * 4);
+
+        for (int i = 0; i < image.getHeight(); i++) {
+            for (int j = 0; j < image.getWidth(); j++) {
+                int colorSpace = image.getRGB(j, i);
+                buffer.put((byte) ((colorSpace << 8) >> 24));
+                buffer.put((byte) ((colorSpace << 16) >> 24));
+                buffer.put((byte) ((colorSpace << 24) >> 24));
+                buffer.put((byte) (colorSpace >> 24));
+            }
+        }
+
+        buffer.flip();
+
+        final GLFWImage result = GLFWImage.create();
+        result.set(image.getWidth(), image.getHeight(), buffer);
+
+        return result;
     }
 
     /**
@@ -307,7 +428,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);
         }
     }
@@ -355,13 +476,13 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
 
             created.set(true);
             super.internalCreate();
-            
+
             //create OpenCL
             //Must be done here because the window handle is needed
             if (settings.isOpenCLSupport()) {
                 initOpenCL(window);
             }
-            
+
         } catch (Exception ex) {
             try {
                 if (window != NULL) {
@@ -543,44 +664,4 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
     public long getWindowHandle() {
         return window;
     }
-
-
-    // TODO: Implement support for window icon when GLFW supports it.
-
-    private ByteBuffer[] imagesToByteBuffers(Object[] images) {
-        ByteBuffer[] out = new ByteBuffer[images.length];
-        for (int i = 0; i < images.length; i++) {
-            BufferedImage image = (BufferedImage) images[i];
-            out[i] = imageToByteBuffer(image);
-        }
-        return out;
-    }
-
-    private ByteBuffer imageToByteBuffer(BufferedImage image) {
-        if (image.getType() != BufferedImage.TYPE_INT_ARGB_PRE) {
-            BufferedImage convertedImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB_PRE);
-            Graphics2D g = convertedImage.createGraphics();
-            double width = image.getWidth() * (double) 1;
-            double height = image.getHeight() * (double) 1;
-            g.drawImage(image, (int) ((convertedImage.getWidth() - width) / 2),
-                    (int) ((convertedImage.getHeight() - height) / 2),
-                    (int) (width), (int) (height), null);
-            g.dispose();
-            image = convertedImage;
-        }
-
-        byte[] imageBuffer = new byte[image.getWidth() * image.getHeight() * 4];
-        int counter = 0;
-        for (int i = 0; i < image.getHeight(); i++) {
-            for (int j = 0; j < image.getWidth(); j++) {
-                int colorSpace = image.getRGB(j, i);
-                imageBuffer[counter + 0] = (byte) ((colorSpace << 8) >> 24);
-                imageBuffer[counter + 1] = (byte) ((colorSpace << 16) >> 24);
-                imageBuffer[counter + 2] = (byte) ((colorSpace << 24) >> 24);
-                imageBuffer[counter + 3] = (byte) (colorSpace >> 24);
-                counter += 4;
-            }
-        }
-        return ByteBuffer.wrap(imageBuffer);
-    }
 }