Skip to content

Instantly share code, notes, and snippets.

@Unh0lyTigg
Created August 5, 2015 20:15
Show Gist options
  • Save Unh0lyTigg/0f24362a46ce230860aa to your computer and use it in GitHub Desktop.
Save Unh0lyTigg/0f24362a46ce230860aa to your computer and use it in GitHub Desktop.
What I use for window management in lwjgl3.
import static org.lwjgl.glfw.Callbacks.glfwSetCallback;
import static org.lwjgl.glfw.Callbacks.releaseAllCallbacks;
import static org.lwjgl.glfw.GLFW.GLFWCursorEnterCallback;
import static org.lwjgl.glfw.GLFW.GLFWCursorPosCallback;
import static org.lwjgl.glfw.GLFW.GLFWDropCallback;
import static org.lwjgl.glfw.GLFW.GLFWFramebufferSizeCallback;
import static org.lwjgl.glfw.GLFW.GLFWKeyCallback;
import static org.lwjgl.glfw.GLFW.GLFWMouseButtonCallback;
import static org.lwjgl.glfw.GLFW.GLFWScrollCallback;
import static org.lwjgl.glfw.GLFW.GLFWWindowCloseCallback;
import static org.lwjgl.glfw.GLFW.GLFWWindowFocusCallback;
import static org.lwjgl.glfw.GLFW.GLFWWindowIconifyCallback;
import static org.lwjgl.glfw.GLFW.GLFWWindowPosCallback;
import static org.lwjgl.glfw.GLFW.GLFWWindowRefreshCallback;
import static org.lwjgl.glfw.GLFW.GLFWWindowSizeCallback;
import static org.lwjgl.glfw.GLFW.GLFW_KEY_ESCAPE;
import static org.lwjgl.glfw.GLFW.GLFW_PRESS;
import static org.lwjgl.glfw.GLFW.GLFW_RELEASE;
import static org.lwjgl.glfw.GLFW.GLFW_REPEAT;
import static org.lwjgl.glfw.GLFW.GLFW_RESIZABLE;
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.glfwGetMonitors;
import static org.lwjgl.glfw.GLFW.glfwGetPrimaryMonitor;
import static org.lwjgl.glfw.GLFW.glfwGetVideoMode;
import static org.lwjgl.glfw.GLFW.glfwGetWindowAttrib;
import static org.lwjgl.glfw.GLFW.glfwGetWindowMonitor;
import static org.lwjgl.glfw.GLFW.glfwHideWindow;
import static org.lwjgl.glfw.GLFW.glfwInit;
import static org.lwjgl.glfw.GLFW.glfwMakeContextCurrent;
import static org.lwjgl.glfw.GLFW.glfwSetErrorCallback;
import static org.lwjgl.glfw.GLFW.glfwSetWindowPos;
import static org.lwjgl.glfw.GLFW.glfwSetWindowShouldClose;
import static org.lwjgl.glfw.GLFW.glfwSetWindowSize;
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.opengl.GL11.glViewport;
import static org.lwjgl.system.MemoryUtil.NULL;
import java.awt.Dimension;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Point;
import java.awt.Rectangle;
import java.io.File;
import java.nio.ByteBuffer;
import java.util.Map;
import org.lwjgl.LWJGLUtil;
import org.lwjgl.PointerBuffer;
import org.lwjgl.glfw.Callbacks;
import org.lwjgl.glfw.Callbacks.DropConsumerString;
import org.lwjgl.glfw.GLFWvidmode;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GLContext;
import com.google.common.collect.Maps;
public class Window {
private long windowId;
private String title;
private Callback callback = new Callback();
private int width, height;
private int x, y;
private boolean visible = false;
private static boolean isSetup = false;
public static void setupGLFW(boolean visible, boolean resizable) {
if (isSetup)
return;
LWJGLUtil.initialize();
glfwSetErrorCallback(Callbacks.errorCallbackPrint());
if (glfwInit() != GL_TRUE)
throw new IllegalStateException("Unable to initialize GLFW");
glfwDefaultWindowHints();
glfwWindowHint(GLFW_VISIBLE, visible ? GL_TRUE : GL_FALSE);
glfwWindowHint(GLFW_RESIZABLE, resizable ? GL_TRUE : GL_FALSE);
isSetup = true;
}
public Window(String title, int width, int height) {
this(title, width, height, false);
}
public Window(String title, int width, int height, boolean fullscreen) {
windowId = glfwCreateWindow(width, height, title, fullscreen ? glfwGetPrimaryMonitor() : NULL, NULL);
if (windowId == NULL)
throw new IllegalStateException("Failed to create GLFW window");
this.callback.addCallbacks();
this.width = width;
this.height = height;
this.title = title;
}
public long getGLFWMonitor() {
int mon = getMonitor();
if (mon == -1)
return NULL;
return glfwGetMonitors().get(mon);
}
public int getMonitor() {
GraphicsEnvironment e = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice[] devices = e.getScreenDevices();
Map<Integer, Rectangle> monitorsThatOverlap = Maps.newHashMap();
Map.Entry<Integer, Rectangle> largestOverlap = null;
Rectangle window = new Rectangle(x, y, width, height);
for (int i = 0; i < devices.length; i++) {
Rectangle r = devices[i].getDefaultConfiguration().getBounds();
if (r.intersects(window))
monitorsThatOverlap.put(i, r);
}
for (Map.Entry<Integer, Rectangle> entry : monitorsThatOverlap.entrySet()) {
if (largestOverlap == null) {
largestOverlap = entry;
} else {
Rectangle entryIntersection = entry.getValue().intersection(window);
Rectangle overlapIntersection = largestOverlap.getValue().intersection(window);
double eArea = entryIntersection.getWidth() * entryIntersection.getHeight();
double oArea = overlapIntersection.getWidth() * overlapIntersection.getHeight();
if (eArea > oArea) {
largestOverlap = entry;
}
}
}
if (largestOverlap != null)
return largestOverlap.getKey();
return -1;
}
public void setSwapInterval(int interval) {
glfwSwapInterval(interval);
}
public void swapBuffers() {
glfwSwapBuffers(windowId);
}
public boolean isClosedRequested() {
return glfwWindowShouldClose(windowId) == GL_TRUE;
}
public GLContext setCurrentContext() {
glfwMakeContextCurrent(windowId);
return GLContext.createFromCurrent();
}
public boolean isResizable() {
return glfwGetWindowAttrib(windowId, GLFW_RESIZABLE) == GL_TRUE;
}
public void setSize(int width, int height) {
if (glfwGetWindowMonitor(windowId) != NULL)
return;
glfwSetWindowSize(windowId, width, height);
}
public void setSize(Dimension size) {
setSize(size.width, size.height);
}
public Dimension getSize() {
return new Dimension(width, height);
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public Point getLocation() {
return new Point(x, y);
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public void setLocation(int x, int y) {
if (glfwGetWindowMonitor(windowId) != NULL)
return;
glfwSetWindowPos(windowId, x, y);
}
public void setLocation(Point p) {
setLocation(p.x, p.y);
}
public void setVisible(boolean visible) {
if (visible)
glfwShowWindow(windowId);
else
glfwHideWindow(windowId);
this.visible = visible;
}
public boolean isVisible() {
return visible;
}
public void setTitle(String title) {
this.title = title;
glfwSetWindowTitle(windowId, title);
}
public String getTitle() {
return title;
}
public void addRefreshCallback(RefreshCallback callback) {
if (callback == null)
return;
this.callback.add(callback);
}
public void addPositionCallback(PositionCallback callback) {
if (callback == null)
return;
this.callback.add(callback);
}
public void addWindowStateCallback(WindowStateCallback callback) {
if (callback == null)
return;
this.callback.add(callback);
}
public void addMouseCallback(MouseCallback callback) {
if (callback == null)
return;
this.callback.add(callback);
}
public void addKeyCallback(KeyCallback callback) {
if (callback == null)
return;
this.callback.add(callback);
}
public void addFileDropCallback(FileDropCallback callback) {
if (callback == null)
return;
this.callback.add(callback);
}
public void destroy() {
glfwDestroyWindow(windowId);
this.callback.cleanup();
}
public void centerOnMonitor(int monitorIndex) {
if (glfwGetWindowMonitor(windowId) != NULL)
return;
GraphicsEnvironment e = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice[] devices = e.getScreenDevices();
monitorIndex = Math.min(Math.max(monitorIndex, 0), devices.length - 1);
PointerBuffer monitors = glfwGetMonitors();
long monitor = monitors.get(monitorIndex);
ByteBuffer vidmode = glfwGetVideoMode(monitor);
Rectangle bounds = devices[monitorIndex].getDefaultConfiguration().getBounds();
int xInt = bounds.x;
int yInt = bounds.y;
int xPos = xInt + ((GLFWvidmode.width(vidmode) - width) / 2);
int yPos = yInt + ((GLFWvidmode.height(vidmode) - height) / 2);
glfwSetWindowPos(windowId, xPos, yPos);
}
private class Callback {
private boolean focused = false;
private boolean shouldCallDragIfMove = false;
private Object lock = new Object();
private RefreshCallback.MultiListener refresh = null;
private PositionCallback.MultiListener position = null;
private WindowStateCallback.MultiListener windowstate = null;
private MouseCallback.MultiListener mouse = null;
private KeyCallback.MultiListener keyboard = null;
private FileDropCallback.MultiListener file = null;
public void addCallbacks() {
glfwSetCallback(windowId, GLFWWindowCloseCallback(this::windowClose));
glfwSetCallback(windowId, GLFWWindowFocusCallback(this::windowFocus));
glfwSetCallback(windowId, GLFWWindowIconifyCallback(this::windowIconify));
glfwSetCallback(windowId, GLFWWindowPosCallback(this::windowPos));
glfwSetCallback(windowId, GLFWWindowRefreshCallback(this::windowRefresh));
glfwSetCallback(windowId, GLFWWindowSizeCallback(this::windowSize));
glfwSetCallback(windowId, GLFWCursorEnterCallback(this::cursorEnter));
glfwSetCallback(windowId, GLFWDropCallback(this::drop));
glfwSetCallback(windowId, GLFWFramebufferSizeCallback(this::framebufferSize));
glfwSetCallback(windowId, GLFWMouseButtonCallback(this::mouseButton));
glfwSetCallback(windowId, GLFWKeyCallback(this::key));
glfwSetCallback(windowId, GLFWCursorPosCallback(this::cursorPos));
glfwSetCallback(windowId, GLFWScrollCallback(this::scroll));
}
public void removeCallbacks() {
releaseAllCallbacks(windowId);
}
protected void add(RefreshCallback callback) {
synchronized(lock) {
refresh = RefreshCallback.MultiListener.add(callback, refresh);
}
}
protected void add(PositionCallback callback) {
synchronized(lock) {
position = PositionCallback.MultiListener.add(callback, position);
}
}
protected void add(WindowStateCallback callback) {
synchronized(lock) {
windowstate = WindowStateCallback.MultiListener.add(callback, windowstate);
}
}
protected void add(MouseCallback callback) {
synchronized(lock) {
mouse = MouseCallback.MultiListener.add(callback, mouse);
}
}
protected void add(KeyCallback callback) {
synchronized(lock) {
keyboard = KeyCallback.MultiListener.add(callback, keyboard);
}
}
protected void add(FileDropCallback callback) {
synchronized(lock) {
file = FileDropCallback.MultiListener.add(callback, file);
}
}
protected void cleanup() {
synchronized(lock) {
refresh = null;
position = null;
windowstate = null;
mouse = null;
keyboard = null;
file = null;
removeCallbacks();
}
}
public void windowSize(long window, int width, int height) {
if (window != windowId)
return;
Window.this.width = width;
Window.this.height = height;
synchronized(lock) {
if (windowstate != null) windowstate.windowResized(Window.this, width, height);
}
}
public void cursorEnter(long window, int entered) {
if (window != windowId)
return;
synchronized(lock) {
if (entered == GL_TRUE) {
if (mouse != null) mouse.mouseEntered(Window.this);
} else if (entered == GL_FALSE) {
if (mouse != null) mouse.mouseExited(Window.this);
}
}
}
public void cursorPos(long window, double xpos, double ypos) {
if (window != windowId)
return;
synchronized(lock) {
if (mouse != null) mouse.mouseMoved(Window.this, xpos, ypos, shouldCallDragIfMove);
}
}
public void key(long window, int key, int scancode, int action, int mods) {
if (window != windowId)
return;
synchronized(lock) {
if (action == GLFW_PRESS) {
if (keyboard != null) keyboard.keyPressed(Window.this, key, scancode, mods);
} else if (action == GLFW_RELEASE) {
if (keyboard != null) keyboard.keyReleased(Window.this, key, scancode, mods);
} else if (action == GLFW_REPEAT) {
if (keyboard != null) keyboard.keyRepeated(Window.this, key, scancode, mods);
}
}
}
public void mouseButton(long window, int button, int action, int mods) {
if (window != windowId)
return;
boolean synth = !focused && (action == GLFW_RELEASE);
synchronized(lock) {
if (action == GLFW_PRESS) {
shouldCallDragIfMove = true;
if (mouse != null) mouse.mouseButtonPressed(Window.this, button, mods);
} else if (action == GLFW_RELEASE) {
shouldCallDragIfMove = false;
if (mouse != null) mouse.mouseButtonReleased(Window.this, button, mods, synth);
}
}
}
public void drop(long window, int count, long names) {
if (window != windowId)
return;
synchronized(lock) {
File[] files = new File[count];
Callbacks.dropCallbackNamesApply(count, names, (DropConsumerString)(i, s) -> {
files[i] = new File(s);
});
if (file != null) file.filesDropped(Window.this, files);
}
}
public void scroll(long window, double xoffset, double yoffset) {
if (window != windowId)
return;
synchronized(lock) {
if (mouse != null) mouse.mouseScrolled(Window.this, xoffset, yoffset);
}
}
public void windowClose(long window) {
if (window != windowId)
return;
synchronized(lock) {
if (windowstate != null) windowstate.windowClosed(Window.this);
}
}
public void windowFocus(long window, int focused) {
if (window != windowId)
return;
synchronized(lock) {
if (focused == GL_FALSE) {
this.focused = false;
if (windowstate != null) windowstate.windowFocusLost(Window.this);
} else if (focused == GL_TRUE) {
this.focused = true;
if (windowstate != null) windowstate.windowFocusGained(Window.this);
}
}
}
public void windowIconify(long window, int iconified) {
if (window != windowId)
return;
synchronized(lock) {
if (iconified == GL_FALSE) {
if (windowstate != null) windowstate.windowIconified(Window.this);
} else if (iconified == GL_TRUE) {
if (windowstate != null) windowstate.windowRestored(Window.this);
}
}
}
public void windowPos(long window, int xpos, int ypos) {
if (window != windowId)
return;
Window.this.x = xpos;
Window.this.y = ypos;
synchronized(lock) {
if (position != null) position.windowPositionChanged(Window.this, xpos, ypos);
}
}
public void windowRefresh(long window) {
if (window != windowId)
return;
synchronized(lock) {
if (refresh != null) refresh.windowRefreshed(Window.this);
}
}
public void framebufferSize(long window, int width, int height) {
if (window != windowId)
return;
synchronized(lock) {
if (windowstate != null) windowstate.frameBufferResized(Window.this, width, height);
}
}
}
public static interface RefreshCallback {
static class MultiListener implements RefreshCallback {
private RefreshCallback a, b;
public static MultiListener add(RefreshCallback a, RefreshCallback b) {
MultiListener m = new MultiListener();
m.a = a; m.b = b;
return m;
}
public void windowRefreshed(Window window) {
if (a != null) a.windowRefreshed(window);
if (b != null) b.windowRefreshed(window);
}
}
public static class Adapter implements RefreshCallback {
public void windowRefreshed(Window window) {}
}
public void windowRefreshed(Window window);
}
public static interface PositionCallback {
static class MultiListener implements PositionCallback {
private PositionCallback a, b;
public static MultiListener add(PositionCallback a, PositionCallback b) {
MultiListener m = new MultiListener();
m.a = a; m.b = b;
return m;
}
public void windowPositionChanged(Window window, int x, int y) {
if (a != null) a.windowPositionChanged(window, x, y);
if (b != null) b.windowPositionChanged(window, x, y);
}
}
public static class Adapter implements PositionCallback {
public void windowPositionChanged(Window window, int x, int y) {}
}
public void windowPositionChanged(Window window, int x, int y);
}
public static interface WindowStateCallback {
static class MultiListener implements WindowStateCallback {
private WindowStateCallback a, b;
public static MultiListener add(WindowStateCallback a, WindowStateCallback b) {
MultiListener m = new MultiListener();
m.a = a; m.b = b;
return m;
}
public void frameBufferResized(Window window, int width, int height) {
if (a != null) a.frameBufferResized(window, width, height);
if (b != null) b.frameBufferResized(window, width, height);
}
public void windowClosed(Window window) {
if (a != null) a.windowClosed(window);
if (b != null) b.windowClosed(window);
}
public void windowFocusGained(Window window) {
if (a != null) a.windowFocusGained(window);
if (b != null) b.windowFocusGained(window);
}
public void windowFocusLost(Window window) {
if (a != null) a.windowFocusLost(window);
if (b != null) b.windowFocusLost(window);
}
public void windowIconified(Window window) {
if (a != null) a.windowIconified(window);
if (b != null) b.windowIconified(window);
}
public void windowResized(Window window, int width, int height) {
if (a != null) a.windowResized(window, width, height);
if (b != null) b.windowResized(window, width, height);
}
public void windowRestored(Window window) {
if (a != null) a.windowRestored(window);
if (b != null) b.windowRestored(window);
}
}
public static class Adapter implements WindowStateCallback {
public void windowIconified(Window window) {}
public void windowRestored(Window window) {}
public void windowFocusGained(Window window) {}
public void windowFocusLost(Window window) {}
public void windowClosed(Window window) {}
public void windowResized(Window window, int width, int height) {}
public void frameBufferResized(Window window, int width, int height) {}
}
public static WindowStateCallback GL_VIEWPORT = new Adapter() {
public void windowResized(Window window, int width, int height) {
if (GL.getCurrent() == null)
return;
glViewport(0, 0, width, height);
}
};
public void windowIconified(Window window);
public void windowRestored(Window window);
public void windowFocusGained(Window window);
public void windowFocusLost(Window window);
public void windowClosed(Window window);
public void windowResized(Window window, int width, int height);
public void frameBufferResized(Window window, int width, int height);
}
public static interface MouseCallback {
static class MultiListener implements MouseCallback {
private MouseCallback a, b;
public static MultiListener add(MouseCallback a, MouseCallback b) {
MultiListener m = new MultiListener();
m.a = a; m.b = b;
return m;
}
public void mouseButtonPressed(Window window, int button, int mods) {
if (a != null) a.mouseButtonPressed(window, button, mods);
if (b != null) b.mouseButtonPressed(window, button, mods);
}
public void mouseButtonReleased(Window window, int button, int mods, boolean synth) {
if (a != null) a.mouseButtonReleased(window, button, mods, synth);
if (b != null) b.mouseButtonReleased(window, button, mods, synth);
}
public void mouseEntered(Window window) {
if (a != null) a.mouseEntered(window);
if (b != null) b.mouseEntered(window);
}
public void mouseExited(Window window) {
if (a != null) a.mouseExited(window);
if (b != null) b.mouseExited(window);
}
public void mouseMoved(Window window, double x, double y, boolean dragged) {
if (a != null) a.mouseMoved(window, x, y, dragged);
if (b != null) b.mouseMoved(window, x, y, dragged);
}
public void mouseScrolled(Window window, double xOffset, double yOffset) {
if (a != null) a.mouseScrolled(window, xOffset, yOffset);
if (b != null) b.mouseScrolled(window, xOffset, yOffset);
}
}
public static class Adapter implements MouseCallback {
public void mouseEntered(Window window) {}
public void mouseExited(Window window) {}
public void mouseMoved(Window window, double x, double y, boolean dragged) {}
public void mouseButtonPressed(Window window, int button, int mods) {}
public void mouseButtonReleased(Window window, int button, int mods, boolean synth) {}
public void mouseScrolled(Window window, double xOffset, double yOffset) {}
}
public void mouseEntered(Window window);
public void mouseExited(Window window);
public void mouseMoved(Window window, double x, double y, boolean dragged);
public void mouseButtonPressed(Window window, int button, int mods);
public void mouseButtonReleased(Window window, int button, int mods, boolean synth);
public void mouseScrolled(Window window, double xOffset, double yOffset);
}
public static interface KeyCallback {
static class MultiListener implements KeyCallback {
private KeyCallback a, b;
public static MultiListener add(KeyCallback a, KeyCallback b) {
MultiListener m = new MultiListener();
m.a = a; m.b = b;
return m;
}
public void keyPressed(Window window, int key, int scancode, int mods) {
if (a != null) a.keyPressed(window, key, scancode, mods);
if (b != null) b.keyPressed(window, key, scancode, mods);
}
public void keyReleased(Window window, int key, int scancode, int mods) {
if (a != null) a.keyReleased(window, key, scancode, mods);
if (b != null) b.keyReleased(window, key, scancode, mods);
}
public void keyRepeated(Window window, int key, int scancode, int mods) {
if (a != null) a.keyRepeated(window, key, scancode, mods);
if (b != null) b.keyRepeated(window, key, scancode, mods);
}
}
public static class Adapter implements KeyCallback {
public void keyPressed(Window window, int key, int scancode, int mods) {}
public void keyReleased(Window window, int key, int scancode, int mods) {}
public void keyRepeated(Window window, int key, int scancode, int mods) {}
}
public static KeyCallback ESC_CLOSES_WINDOW = new Adapter() {
@Override
public void keyReleased(Window window, int key, int scancode, int mods) {
if (key == GLFW_KEY_ESCAPE)
glfwSetWindowShouldClose(window.windowId, GL_TRUE);
}
};
public void keyPressed(Window window, int key, int scancode, int mods);
public void keyReleased(Window window, int key, int scancode, int mods);
public void keyRepeated(Window window, int key, int scancode, int mods);
}
public static interface FileDropCallback {
static class MultiListener implements FileDropCallback {
FileDropCallback a, b;
public static MultiListener add(FileDropCallback a, FileDropCallback b) {
MultiListener m = new MultiListener();
m.a = a; m.b = b;
return m;
}
public void filesDropped(Window window, File[] files) {
if (a != null) a.filesDropped(window, files);
if (b != null) b.filesDropped(window, files);
}
}
public static class Adapter implements FileDropCallback {
public void filesDropped(Window window, File[] files) {}
}
public void filesDropped(Window window, File[] files);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment