|
|
|
@ -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); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|