Start of the Device API
This commit is contained in:
parent
00671c00ff
commit
d7fbc6e93b
|
@ -0,0 +1,69 @@
|
||||||
|
package speiger.src.coreengine.rendering.input.divices;
|
||||||
|
|
||||||
|
import java.util.Deque;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.ConcurrentLinkedDeque;
|
||||||
|
|
||||||
|
import speiger.src.collections.longs.maps.impl.concurrent.Long2ObjectConcurrentOpenHashMap;
|
||||||
|
import speiger.src.collections.longs.maps.interfaces.Long2ObjectMap;
|
||||||
|
import speiger.src.coreengine.rendering.input.window.IWindowListener.Reason;
|
||||||
|
import speiger.src.coreengine.rendering.input.window.Window;
|
||||||
|
import speiger.src.coreengine.utils.eventbus.Event;
|
||||||
|
import speiger.src.coreengine.utils.eventbus.EventBus;
|
||||||
|
|
||||||
|
public abstract class AbstractDevice<T, E> implements InputDevice {
|
||||||
|
protected Long2ObjectMap<Deque<E>> queues = new Long2ObjectConcurrentOpenHashMap<>();
|
||||||
|
protected Long2ObjectMap<T> windowData = new Long2ObjectConcurrentOpenHashMap<>();
|
||||||
|
protected EventBus bus;
|
||||||
|
|
||||||
|
public void init(EventBus bus) {
|
||||||
|
this.bus = bus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void register(Window window) {
|
||||||
|
registerCallbacks(window);
|
||||||
|
long id = window.id();
|
||||||
|
queues.putIfAbsent(id, new ConcurrentLinkedDeque<>());
|
||||||
|
T data = createData(id);
|
||||||
|
if(data == null) return;
|
||||||
|
windowData.put(id, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void registerCallbacks(Window window) {
|
||||||
|
window.addListener(this::onClose);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onClose(Window window, Reason reason) {
|
||||||
|
if(reason == Reason.CLOSING) {
|
||||||
|
queues.remove(window.id());
|
||||||
|
windowData.remove(window.id());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract T createData(long windowId);
|
||||||
|
protected abstract void process(E task);
|
||||||
|
|
||||||
|
protected void pushEvent(Event event) {
|
||||||
|
bus.post(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void push(long windowId, E task) {
|
||||||
|
Objects.requireNonNull(task);
|
||||||
|
Deque<E> queue = queues.get(windowId);
|
||||||
|
if(queue == null) return;
|
||||||
|
queue.add(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void processInput(long windowId) {
|
||||||
|
Deque<E> queue = queues.get(windowId);
|
||||||
|
if(queue == null) return;
|
||||||
|
while(!queue.isEmpty()) {
|
||||||
|
process(queue.poll());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected T getData(long windowId) {
|
||||||
|
return windowData.get(windowId);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
package speiger.src.coreengine.rendering.input.divices;
|
||||||
|
|
||||||
|
import speiger.src.coreengine.rendering.input.window.Window;
|
||||||
|
|
||||||
|
public interface InputDevice {
|
||||||
|
public void register(Window window);
|
||||||
|
public void processInput(long windowId);
|
||||||
|
}
|
|
@ -0,0 +1,102 @@
|
||||||
|
package speiger.src.coreengine.rendering.input.divices;
|
||||||
|
|
||||||
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
|
||||||
|
import speiger.src.collections.ints.sets.IntOpenHashSet;
|
||||||
|
import speiger.src.collections.ints.sets.IntSet;
|
||||||
|
import speiger.src.coreengine.math.vector.ints.Vec2i;
|
||||||
|
import speiger.src.coreengine.rendering.input.divices.Mouse.MouseData;
|
||||||
|
import speiger.src.coreengine.rendering.input.divices.Mouse.MouseTask;
|
||||||
|
import speiger.src.coreengine.rendering.input.window.Window;
|
||||||
|
|
||||||
|
public class Mouse extends AbstractDevice<MouseData, MouseTask> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected MouseData createData(long windowId) { return new MouseData(); }
|
||||||
|
protected void process(MouseTask task) { task.process(this); }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void registerCallbacks(Window window) {
|
||||||
|
super.registerCallbacks(window);
|
||||||
|
window.addCallback(this::move, GLFW::glfwSetCursorPosCallback);
|
||||||
|
window.addCallback(this::click, GLFW::glfwSetMouseButtonCallback);
|
||||||
|
window.addCallback(this::enter, GLFW::glfwSetCursorEnterCallback);
|
||||||
|
window.addCallback(this::scroll, GLFW::glfwSetScrollCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void move(long window, double x, double y) {
|
||||||
|
push(window, new Move(window, x, y));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void click(long window, int button, int action, int mods) {
|
||||||
|
push(window, new Click(window, button, action, mods));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void enter(long window, boolean enter) {
|
||||||
|
push(window, new Enter(window, enter));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void scroll(long window, double xoffset, double yoffset) {
|
||||||
|
push(window, new Scroll(window, xoffset, yoffset));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class MouseData {
|
||||||
|
IntSet buttons = new IntOpenHashSet();
|
||||||
|
Vec2i position = Vec2i.mutable();
|
||||||
|
Vec2i movement = Vec2i.mutable();
|
||||||
|
Vec2i scroll = Vec2i.mutable();
|
||||||
|
boolean active = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface MouseTask {
|
||||||
|
public void process(Mouse mouse);
|
||||||
|
}
|
||||||
|
|
||||||
|
private record Move(long window, double x, double y) implements MouseTask {
|
||||||
|
@Override
|
||||||
|
public void process(Mouse mouse) {
|
||||||
|
MouseData data = mouse.getData(window);
|
||||||
|
int xOff = (int)(x - data.position.x());
|
||||||
|
int yOff = (int)(y - data.position.y());
|
||||||
|
data.position.set((int)x, (int)y);
|
||||||
|
//TODO Post event!
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
private record Click(long window, int button, int action, int mods) implements MouseTask {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void process(Mouse mouse) {
|
||||||
|
MouseData data = mouse.getData(window);
|
||||||
|
if(action == GLFW.GLFW_PRESS) data.buttons.add(action);
|
||||||
|
else if(action == GLFW.GLFW_RELEASE) data.buttons.remove(action);
|
||||||
|
//TODO post event
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private record Scroll(long window, double xoffset, double yoffset) implements MouseTask {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void process(Mouse mouse) {
|
||||||
|
//TODO post event
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
private record Enter(long window, boolean enter) implements MouseTask {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void process(Mouse mouse) {
|
||||||
|
MouseData data = mouse.getData(window);
|
||||||
|
data.active = enter;
|
||||||
|
if(!enter) {
|
||||||
|
//TODO decide if this should also push phantom events clearing the pressed keys?
|
||||||
|
data.buttons.clear();
|
||||||
|
data.movement.negate();
|
||||||
|
data.position.negate();
|
||||||
|
data.scroll.negate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
package speiger.src.coreengine.rendering.input.window;
|
||||||
|
|
||||||
|
public interface IWindowListener {
|
||||||
|
|
||||||
|
public void onChanged(Window window, Reason reason);
|
||||||
|
|
||||||
|
public static enum Reason {
|
||||||
|
CHANGE,
|
||||||
|
CLOSING;
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,11 +23,11 @@ public class Monitor
|
||||||
this.id = id;
|
this.id = id;
|
||||||
GLFWVidMode.Buffer buffer = GLFW.glfwGetVideoModes(id);
|
GLFWVidMode.Buffer buffer = GLFW.glfwGetVideoModes(id);
|
||||||
for(int i = buffer.limit() - 1;i >= 0;--i) {
|
for(int i = buffer.limit() - 1;i >= 0;--i) {
|
||||||
VideoMode videomode = new VideoMode(this, buffer.position(i));
|
VideoMode videomode = new VideoMode(buffer.position(i));
|
||||||
if(videomode.redBits() >= 8 && videomode.greenBits() >= 8 && videomode.blueBits() >= 8)
|
if(videomode.redBits() >= 8 && videomode.greenBits() >= 8 && videomode.blueBits() >= 8)
|
||||||
modes.add(videomode);
|
modes.add(videomode);
|
||||||
}
|
}
|
||||||
defaultMode = new VideoMode(this, GLFW.glfwGetVideoMode(id));
|
defaultMode = new VideoMode(GLFW.glfwGetVideoMode(id));
|
||||||
int[] xPos = new int[1];
|
int[] xPos = new int[1];
|
||||||
int[] yPos = new int[1];
|
int[] yPos = new int[1];
|
||||||
GLFW.glfwGetMonitorPos(id, xPos, yPos);
|
GLFW.glfwGetMonitorPos(id, xPos, yPos);
|
||||||
|
@ -40,13 +40,19 @@ public class Monitor
|
||||||
public String name() { return GLFW.glfwGetMonitorName(id); }
|
public String name() { return GLFW.glfwGetMonitorName(id); }
|
||||||
public int size() { return modes.size(); }
|
public int size() { return modes.size(); }
|
||||||
public VideoMode getMode(int index) { return modes.get(index); }
|
public VideoMode getMode(int index) { return modes.get(index); }
|
||||||
public boolean contains(VideoMode mode) { return modes.indexOf(mode) != -1; }
|
public boolean has(VideoMode mode) { return modes.indexOf(mode) != -1; }
|
||||||
public List<VideoMode> videoModes() { return modes.unmodifiable(); }
|
public List<VideoMode> videoModes() { return modes.unmodifiable(); }
|
||||||
public VideoMode defaultMode() { return defaultMode; }
|
public VideoMode defaultMode() { return defaultMode; }
|
||||||
public int xOffset() { return xOffset; }
|
public int xOffset() { return xOffset; }
|
||||||
public int yOffset() { return yOffset; }
|
public int yOffset() { return yOffset; }
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
|
|
||||||
|
public int getOverlap(int minX, int minY, int maxX, int maxY) {
|
||||||
|
int x = Math.max(0, Math.clamp(maxX, xOffset, xOffset + defaultMode.width()) - Math.clamp(minX, xOffset, xOffset + defaultMode.width()));
|
||||||
|
int y = Math.max(0, Math.clamp(maxY, yOffset, yOffset + defaultMode.height()) - Math.clamp(minY, yOffset, yOffset + defaultMode.height()));
|
||||||
|
return x * y;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) { return obj instanceof Monitor mon && mon.id == id; }
|
public boolean equals(Object obj) { return obj instanceof Monitor mon && mon.id == id; }
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -2,13 +2,13 @@ package speiger.src.coreengine.rendering.input.window;
|
||||||
|
|
||||||
import org.lwjgl.glfw.GLFWVidMode;
|
import org.lwjgl.glfw.GLFWVidMode;
|
||||||
|
|
||||||
public record VideoMode(Monitor monitor, int width, int height, int redBits, int greenBits, int blueBits, int refreshrate) {
|
public record VideoMode(int width, int height, int redBits, int greenBits, int blueBits, int refreshrate) {
|
||||||
|
|
||||||
public VideoMode(Monitor monitor, GLFWVidMode buffer) {
|
public VideoMode(GLFWVidMode buffer) {
|
||||||
this(monitor, buffer.width(), buffer.height(), buffer.redBits(), buffer.greenBits(), buffer.blueBits(), buffer.refreshRate());
|
this(buffer.width(), buffer.height(), buffer.redBits(), buffer.greenBits(), buffer.blueBits(), buffer.refreshRate());
|
||||||
}
|
}
|
||||||
|
|
||||||
public VideoMode(Monitor monitor, GLFWVidMode.Buffer buffer) {
|
public VideoMode(GLFWVidMode.Buffer buffer) {
|
||||||
this(monitor, buffer.width(), buffer.height(), buffer.redBits(), buffer.greenBits(), buffer.blueBits(), buffer.refreshRate());
|
this(buffer.width(), buffer.height(), buffer.redBits(), buffer.greenBits(), buffer.blueBits(), buffer.refreshRate());
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -8,25 +8,29 @@ import org.lwjgl.opengl.GLCapabilities;
|
||||||
import org.lwjgl.system.CallbackI;
|
import org.lwjgl.system.CallbackI;
|
||||||
|
|
||||||
import speiger.src.collections.objects.lists.ObjectArrayList;
|
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||||
|
import speiger.src.coreengine.math.vector.ints.Vec4i;
|
||||||
|
import speiger.src.coreengine.rendering.input.window.IWindowListener.Reason;
|
||||||
import speiger.src.coreengine.rendering.input.window.WindowCallback.ReloadFunction;
|
import speiger.src.coreengine.rendering.input.window.WindowCallback.ReloadFunction;
|
||||||
import speiger.src.coreengine.rendering.input.window.WindowManager.WindowBuilder;
|
import speiger.src.coreengine.rendering.input.window.WindowManager.WindowBuilder;
|
||||||
|
import speiger.src.coreengine.rendering.utils.GLStateTracker;
|
||||||
import speiger.src.coreengine.utils.collections.FlagHolder;
|
import speiger.src.coreengine.utils.collections.FlagHolder;
|
||||||
|
|
||||||
public class Window {
|
public class Window {
|
||||||
static final int FLAG_VISIBLE = 1;
|
static final int VISIBLE = 1;
|
||||||
static final int FLAG_VSYNC = 2;
|
static final int VSYNC = 2;
|
||||||
static final int FLAG_FOCUS = 4;
|
static final int FOCUS = 4;
|
||||||
static final int FLAG_CPU_FPS_CAP = 8;
|
static final int CPU_FPS_CAP = 8;
|
||||||
static final int FLAG_FULL_SCREEN = 16;
|
static final int FULL_SCREEN = 16;
|
||||||
static final int FLAG_MAXIMIZED = 32;
|
static final int MAXIMIZED = 32;
|
||||||
static final int FLAG_BORDERLESS = 64;
|
static final int BORDERLESS = 64;
|
||||||
static final int FLAG_CLOSE = 128;
|
static final int RESIZABLE = 128;
|
||||||
static final int FLAG_WINDOW_CHANGE = 256;
|
static final int FLOATING = 256;
|
||||||
static final int FLAG_FLOATING = 512;
|
static final int CLOSE = 512;
|
||||||
|
static final int WINDOW_CHANGE = 1024;
|
||||||
WindowManager manager;
|
WindowManager manager;
|
||||||
FlagHolder flags = new FlagHolder();
|
FlagHolder flags = new FlagHolder();
|
||||||
long id;
|
long id;
|
||||||
VideoMode mode;
|
VideoMode fullScreenMode;
|
||||||
String title = "";
|
String title = "";
|
||||||
int x;
|
int x;
|
||||||
int y;
|
int y;
|
||||||
|
@ -36,34 +40,36 @@ public class Window {
|
||||||
int frameWidth;
|
int frameWidth;
|
||||||
int frameHeight;
|
int frameHeight;
|
||||||
|
|
||||||
int windowX;
|
Vec4i[] backup = new Vec4i[] {Vec4i.mutable(), Vec4i.mutable()};
|
||||||
int windowY;
|
int backupIndex = 0;
|
||||||
int windowWidth;
|
|
||||||
int windowHeight;
|
|
||||||
|
|
||||||
final int antialiasing;
|
final int antialiasing;
|
||||||
List<WindowCallback> callbacks = new ObjectArrayList<>();
|
List<WindowCallback> callbacks = new ObjectArrayList<>();
|
||||||
|
List<IWindowListener> listeners = new ObjectArrayList<>();
|
||||||
GLCapabilities capabilities;
|
GLCapabilities capabilities;
|
||||||
|
|
||||||
protected Window(WindowBuilder builder) {
|
protected Window(WindowBuilder builder) {
|
||||||
manager = builder.manager;
|
manager = builder.manager;
|
||||||
title = builder.title;
|
title = builder.title;
|
||||||
width = builder.width;
|
frameWidth = width = builder.width;
|
||||||
height = builder.height;
|
frameHeight = height = builder.height;
|
||||||
antialiasing = builder.antiAlis;
|
antialiasing = builder.antiAlis;
|
||||||
mode = builder.mode;
|
fullScreenMode = builder.fullScreenTarget;
|
||||||
flags.setFlag(FLAG_BORDERLESS, builder.borderless);
|
flags.setFlag(BORDERLESS, builder.borderless);
|
||||||
flags.setFlag(FLAG_FULL_SCREEN, builder.fullScreen);
|
flags.setFlag(FULL_SCREEN, builder.fullScreen);
|
||||||
flags.setFlag(FLAG_FLOATING, builder.floating);
|
flags.setFlag(FLOATING, builder.floating);
|
||||||
flags.setFlag(FLAG_VSYNC, builder.vsync);
|
flags.setFlag(RESIZABLE, builder.resizable);
|
||||||
flags.setFlag(FLAG_CPU_FPS_CAP, builder.fpsCap);
|
flags.setFlag(VSYNC, builder.vsync);
|
||||||
|
flags.setFlag(CPU_FPS_CAP, builder.fpsCap);
|
||||||
createDefaultWindowHints();
|
createDefaultWindowHints();
|
||||||
GLFW.glfwWindowHint(GLFW.GLFW_SAMPLES, antialiasing);
|
GLFW.glfwWindowHint(GLFW.GLFW_SAMPLES, antialiasing);
|
||||||
GLFW.glfwWindowHint(GLFW.GLFW_DECORATED, flags.isFlagNotSet(FLAG_FULL_SCREEN) && flags.isFlagSet(FLAG_BORDERLESS) ? 0 : 1);
|
GLFW.glfwWindowHint(GLFW.GLFW_RESIZABLE, flags.isFlagNotSet(RESIZABLE) ? GLFW.GLFW_TRUE : GLFW.GLFW_FALSE);
|
||||||
GLFW.glfwWindowHint(GLFW.GLFW_FLOATING, flags.isFlagNotSet(FLAG_FULL_SCREEN) && flags.isFlagSet(FLAG_FLOATING) ? 1 : 0);
|
GLFW.glfwWindowHint(GLFW.GLFW_DECORATED, flags.isFlagNotSet(FULL_SCREEN) && flags.isFlagSet(BORDERLESS) ? GLFW.GLFW_FALSE : GLFW.GLFW_TRUE);
|
||||||
GLFW.glfwWindowHint(GLFW.GLFW_MAXIMIZED, flags.isFlagNotSet(FLAG_FULL_SCREEN) && flags.isFlagSet(FLAG_MAXIMIZED) ? 1 : 0);
|
GLFW.glfwWindowHint(GLFW.GLFW_FLOATING, flags.isFlagNotSet(FULL_SCREEN) && flags.isFlagSet(FLOATING) ? GLFW.GLFW_TRUE : GLFW.GLFW_FALSE);
|
||||||
if(mode == null || mode.monitor() == null) throw new IllegalStateException("Monitor or Video Mode is missing: "+mode);
|
GLFW.glfwWindowHint(GLFW.GLFW_MAXIMIZED, flags.isFlagNotSet(FULL_SCREEN) && flags.isFlagSet(MAXIMIZED) ? GLFW.GLFW_TRUE : GLFW.GLFW_FALSE);
|
||||||
Monitor monitor = mode.monitor();
|
Monitor monitor = manager.getMonitor(builder.monitor);
|
||||||
|
if(monitor == null) throw new IllegalStateException("Monitor is missing: "+monitor);
|
||||||
|
VideoMode mode = monitor.defaultMode();
|
||||||
boolean fullscreen = builder.fullScreen;
|
boolean fullscreen = builder.fullScreen;
|
||||||
id = GLFW.glfwCreateWindow(fullscreen ? mode.width() : width, fullscreen ? mode.height() : height, title, builder.fullScreen ? monitor.id() : 0, manager.getPrimaryWindow());
|
id = GLFW.glfwCreateWindow(fullscreen ? mode.width() : width, fullscreen ? mode.height() : height, title, builder.fullScreen ? monitor.id() : 0, manager.getPrimaryWindow());
|
||||||
if(id == 0) throw new IllegalStateException("Window Couldn't be Created");
|
if(id == 0) throw new IllegalStateException("Window Couldn't be Created");
|
||||||
|
@ -74,14 +80,14 @@ public class Window {
|
||||||
x = monitor.xOffset() + (builder.center ? (mode.width() / 2) - (width / 2) : 0);
|
x = monitor.xOffset() + (builder.center ? (mode.width() / 2) - (width / 2) : 0);
|
||||||
y = monitor.yOffset() + (builder.center ? (mode.height() / 2) - (height / 2) : 0);
|
y = monitor.yOffset() + (builder.center ? (mode.height() / 2) - (height / 2) : 0);
|
||||||
if(!fullscreen) GLFW.glfwSetWindowPos(id, x, y);
|
if(!fullscreen) GLFW.glfwSetWindowPos(id, x, y);
|
||||||
GLFW.glfwSwapInterval(flags.isFlagSet(FLAG_VSYNC) ? 1 : 0);
|
GLFW.glfwSwapInterval(flags.isFlagSet(VSYNC) ? 1 : 0);
|
||||||
fetchWindowBounds();
|
fetchWindowBounds();
|
||||||
|
updateViewport();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void createDefaultWindowHints() {
|
protected void createDefaultWindowHints() {
|
||||||
GLFW.glfwDefaultWindowHints();
|
GLFW.glfwDefaultWindowHints();
|
||||||
GLFW.glfwWindowHint(GLFW.GLFW_VISIBLE, GLFW.GLFW_FALSE);
|
GLFW.glfwWindowHint(GLFW.GLFW_VISIBLE, GLFW.GLFW_FALSE);
|
||||||
GLFW.glfwWindowHint(GLFW.GLFW_RESIZABLE, GLFW.GLFW_TRUE);
|
|
||||||
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MAJOR, 4);
|
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MAJOR, 4);
|
||||||
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MINOR, 0);
|
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MINOR, 0);
|
||||||
GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_PROFILE, GLFW.GLFW_OPENGL_CORE_PROFILE);
|
GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_PROFILE, GLFW.GLFW_OPENGL_CORE_PROFILE);
|
||||||
|
@ -89,7 +95,31 @@ public class Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void createWindowListeners() {
|
protected void createWindowListeners() {
|
||||||
|
addCallback(this::framebuffer, GLFW::glfwSetFramebufferSizeCallback);
|
||||||
|
addCallback(this::focused, GLFW::glfwSetWindowFocusCallback);
|
||||||
|
addCallback(this::position, GLFW::glfwSetWindowPosCallback);
|
||||||
|
addCallback(this::bounds, GLFW::glfwSetWindowSizeCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void framebuffer(long window, int width, int height) {
|
||||||
|
frameWidth = width;
|
||||||
|
frameHeight = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void focused(long window, boolean focused) {
|
||||||
|
manager.updateFocus(this, focused);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void position(long window, int x, int y) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
flags.setFlag(WINDOW_CHANGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void bounds(long window, int width, int height) {
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
flags.setFlag(WINDOW_CHANGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void fetchWindowBounds() {
|
protected void fetchWindowBounds() {
|
||||||
|
@ -100,11 +130,51 @@ public class Window {
|
||||||
this.frameHeight = height[0];
|
this.frameHeight = height[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void updateViewport() {
|
||||||
|
flags.clearFlag(WINDOW_CHANGE);
|
||||||
|
GLStateTracker.instance().viewPort.setDefault(0, 0, frameWidth, frameHeight);
|
||||||
|
for(int i = 0,m=listeners.size();i<m;i++) {
|
||||||
|
listeners.get(i).onChanged(this, Reason.CHANGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update() {
|
||||||
|
if(flags.isFlagSet(WINDOW_CHANGE)) updateViewport();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void finishFrame() {
|
||||||
|
GLFW.glfwSwapBuffers(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void destroy() {
|
||||||
|
for(int i = 0,m=listeners.size();i<m;i++) {
|
||||||
|
listeners.get(i).onChanged(this, Reason.CLOSING);
|
||||||
|
}
|
||||||
|
GLFW.glfwDestroyWindow(id);
|
||||||
|
callbacks.forEach(WindowCallback::destroy);
|
||||||
|
callbacks.clear();
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <T extends CallbackI> void addCallback(T listener, ReloadFunction<T> function) {
|
public <T extends CallbackI> WindowCallback addCallback(T listener, ReloadFunction<T> function) {
|
||||||
WindowCallback callback = new WindowCallback(listener, (ReloadFunction<CallbackI>)function);
|
WindowCallback callback = new WindowCallback(listener, (ReloadFunction<CallbackI>)function);
|
||||||
callbacks.add(callback);
|
callbacks.add(callback);
|
||||||
callback.load(id);
|
callback.load(id);
|
||||||
|
return callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeCallback(WindowCallback callback) {
|
||||||
|
if(callbacks.remove(callback)) {
|
||||||
|
callback.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addListener(IWindowListener listener) {
|
||||||
|
listeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeListener(IWindowListener listener) {
|
||||||
|
listeners.remove(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void title(String name) {
|
public void title(String name) {
|
||||||
|
@ -114,76 +184,127 @@ public class Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void vsync(boolean vsync) {
|
public void vsync(boolean vsync) {
|
||||||
if(!flags.setFlag(FLAG_VSYNC, vsync)) return;
|
if(!flags.setFlag(VSYNC, vsync)) return;
|
||||||
GLFW.glfwSwapInterval(vsync ? 1 : 0);
|
GLFW.glfwSwapInterval(vsync ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void fpsCap(boolean fpsCap) {
|
public void fpsCap(boolean fpsCap) {
|
||||||
flags.setFlag(FLAG_CPU_FPS_CAP, fpsCap);
|
flags.setFlag(CPU_FPS_CAP, fpsCap);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void visible(boolean visible) {
|
public void visible(boolean visible) {
|
||||||
if(!flags.setFlag(FLAG_VISIBLE, visible)) return;
|
if(!flags.setFlag(VISIBLE, visible)) return;
|
||||||
if(visible) GLFW.glfwShowWindow(id);
|
if(visible) GLFW.glfwShowWindow(id);
|
||||||
else GLFW.glfwHideWindow(id);
|
else GLFW.glfwHideWindow(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void floating(boolean floating) {
|
public void floating(boolean floating) {
|
||||||
if(flags.isFlagNotSet(FLAG_FULL_SCREEN) && flags.setFlag(FLAG_FLOATING, floating)) {
|
if(flags.isFlagNotSet(FULL_SCREEN) && flags.setFlag(FLOATING, floating)) {
|
||||||
GLFW.glfwSetWindowAttrib(id, GLFW.GLFW_FLOATING, floating ? GLFW.GLFW_TRUE : GLFW.GLFW_FALSE);
|
GLFW.glfwSetWindowAttrib(id, GLFW.GLFW_FLOATING, floating ? GLFW.GLFW_TRUE : GLFW.GLFW_FALSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void maximized(boolean maximized) {
|
public void maximized(boolean maximized) {
|
||||||
if(flags.isFlagNotSet(FLAG_FULL_SCREEN) && flags.setFlag(FLAG_MAXIMIZED, maximized)) {
|
if(flags.isFlagNotSet(FULL_SCREEN) && flags.setFlag(MAXIMIZED, maximized)) {
|
||||||
if(maximized) {
|
if(maximized) {
|
||||||
windowX = x;
|
backupSize();
|
||||||
windowY = y;
|
|
||||||
windowWidth = width;
|
|
||||||
windowHeight = height;
|
|
||||||
GLFW.glfwMaximizeWindow(id);
|
GLFW.glfwMaximizeWindow(id);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
x = windowX;
|
|
||||||
y = windowY;
|
|
||||||
width = windowWidth;
|
|
||||||
height = windowHeight;
|
|
||||||
GLFW.glfwRestoreWindow(id);
|
GLFW.glfwRestoreWindow(id);
|
||||||
|
restoreSize();
|
||||||
}
|
}
|
||||||
fetchWindowBounds();
|
fetchWindowBounds();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resizeable(boolean resizeable) {
|
public void resizeable(boolean resizeable) {
|
||||||
|
if(flags.isFlagNotSet(FULL_SCREEN) && flags.setFlag(RESIZABLE, resizeable)) {
|
||||||
|
GLFW.glfwSetWindowAttrib(id, GLFW.GLFW_RESIZABLE, resizeable ? GLFW.GLFW_TRUE : GLFW.GLFW_FALSE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void borderless(boolean borderless) {
|
public void borderless(boolean borderless) {
|
||||||
|
if(flags.isFlagNotSet(FULL_SCREEN) && flags.setFlag(BORDERLESS, borderless)) {
|
||||||
|
GLFW.glfwSetWindowAttrib(id, GLFW.GLFW_DECORATED, borderless ? GLFW.GLFW_FALSE : GLFW.GLFW_TRUE);
|
||||||
|
if(flags.isFlagSet(MAXIMIZED)) {
|
||||||
|
GLFW.glfwRestoreWindow(id);
|
||||||
|
GLFW.glfwMaximizeWindow(id);
|
||||||
|
fetchWindowBounds();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void fullscreen(boolean fullscreen) {
|
public void fullscreen(boolean fullscreen) {
|
||||||
|
if(flags.setFlag(FULL_SCREEN, fullscreen)) {
|
||||||
|
if(fullscreen) {
|
||||||
|
Monitor monitor = manager.getMonitorForWindow(this);
|
||||||
|
if(monitor == null) {
|
||||||
|
flags.clearFlag(FULL_SCREEN);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
backupSize();
|
||||||
|
VideoMode mode = fullScreenMode == null || !monitor.has(fullScreenMode) ? monitor.defaultMode() : fullScreenMode;
|
||||||
|
x = 0;
|
||||||
|
y = 0;
|
||||||
|
width = mode.width();
|
||||||
|
height = mode.height();
|
||||||
|
GLFW.glfwSetWindowMonitor(id, monitor.id(), 0, 0, mode.width(), mode.height(), mode.refreshrate());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
restoreSize();
|
||||||
|
GLFW.glfwSetWindowMonitor(id, 0, x, y, width, height, -1);
|
||||||
|
if(flags.isFlagSet(BORDERLESS)) {
|
||||||
|
GLFW.glfwSetWindowAttrib(id, GLFW.GLFW_DECORATED, GLFW.GLFW_FALSE);
|
||||||
|
}
|
||||||
|
if(flags.isFlagSet(MAXIMIZED)) {
|
||||||
|
GLFW.glfwMaximizeWindow(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fetchWindowBounds();
|
||||||
|
updateViewport();
|
||||||
|
GLFW.glfwSwapInterval(flags.isFlagSet(VSYNC) ? 1 : 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void backupSize() {
|
||||||
|
if(backupIndex >= backup.length) return;
|
||||||
|
backup[backupIndex++].set(x, y, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void restoreSize() {
|
||||||
|
if(backupIndex == 0) return;
|
||||||
|
Vec4i prev = backup[--backupIndex];
|
||||||
|
x = prev.x();
|
||||||
|
y = prev.y();
|
||||||
|
width = prev.z();
|
||||||
|
height = prev.w();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean position(int x, int y) {
|
public boolean position(int x, int y) {
|
||||||
return false;
|
if(flags.isAnyFlagSet(MAXIMIZED | FULL_SCREEN) || (this.x == x && this.y == y)) return false;
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
GLFW.glfwSetWindowPos(id, x, y);
|
||||||
|
flags.setFlag(WINDOW_CHANGE);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean size(int width, int height) {
|
public boolean size(int width, int height) {
|
||||||
return false;
|
if(flags.isAnyFlagSet(MAXIMIZED | FULL_SCREEN) || (this.width == width && this.height == height)) return false;
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
GLFW.glfwSetWindowSize(id, width, height);
|
||||||
|
flags.setFlag(WINDOW_CHANGE);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean width(int width) {
|
public boolean width(int width) { return size(width, height); }
|
||||||
return false;
|
public boolean height(int height) { return size(width, height); }
|
||||||
}
|
|
||||||
|
|
||||||
public boolean height(int height) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long id() { return id; }
|
public long id() { return id; }
|
||||||
public VideoMode mode() { return mode; }
|
public VideoMode desiredFullScreen() { return fullScreenMode; }
|
||||||
|
|
||||||
public int x() { return x; }
|
public int x() { return x; }
|
||||||
public int y() { return y; }
|
public int y() { return y; }
|
||||||
|
@ -191,16 +312,16 @@ public class Window {
|
||||||
public int height() { return frameHeight; }
|
public int height() { return frameHeight; }
|
||||||
public int screenWidth() { return width; }
|
public int screenWidth() { return width; }
|
||||||
public int screenHeight() { return height; }
|
public int screenHeight() { return height; }
|
||||||
public boolean changed() { return flags.isFlagSet(FLAG_WINDOW_CHANGE); }
|
public boolean changed() { return flags.isFlagSet(WINDOW_CHANGE); }
|
||||||
|
|
||||||
public String title() { return title; }
|
public String title() { return title; }
|
||||||
public boolean isVsync() { return false; }
|
public boolean isVsync() { return flags.isFlagSet(VSYNC); }
|
||||||
public boolean isFPSCapped() { return false; }
|
public boolean shouldFPSCap() { return flags.isFlagSet(CPU_FPS_CAP); }
|
||||||
public boolean isVisible() { return false; }
|
public boolean isVisible() { return flags.isFlagSet(VISIBLE); }
|
||||||
public boolean isFloating() { return false; }
|
public boolean isFloating() { return flags.isFlagSet(FLOATING); }
|
||||||
public boolean isMaximized() { return false; }
|
public boolean isMaximized() { return flags.isFlagSet(MAXIMIZED); }
|
||||||
public boolean isResizeable() { return false; }
|
public boolean isResizeable() { return flags.isFlagSet(RESIZABLE); }
|
||||||
public boolean isBorderless() { return false; }
|
public boolean isBorderless() { return flags.isFlagSet(BORDERLESS); }
|
||||||
public boolean isFullscreen() { return false; }
|
public boolean isFullscreen() { return flags.isFlagSet(FULL_SCREEN); }
|
||||||
public int antialiasing() { return antialiasing; }
|
public int antialiasing() { return antialiasing; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,26 +35,55 @@ public class WindowManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
void addWindow(Window window) {
|
void addWindow(Window window) {
|
||||||
windows.put(window.id, window);
|
windows.put(window.id(), window);
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateWindow(long oldId) {
|
void updateWindow(long oldId) {
|
||||||
Window prev = windows.remove(oldId);
|
Window prev = windows.remove(oldId);
|
||||||
if(prev == null) return;
|
if(prev == null) return;
|
||||||
windows.put(prev.id, prev);
|
windows.put(prev.id(), prev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateFocus(Window window, boolean focus) {
|
||||||
|
if(focus) this.activeWindow = window;
|
||||||
|
else if(activeWindow == window) activeWindow = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getPrimaryWindow() {
|
public long getPrimaryWindow() {
|
||||||
return primaryWindow == null ? 0 : primaryWindow.id;
|
return primaryWindow == null ? 0 : primaryWindow.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Monitor getMonitor(long id) {
|
||||||
|
return monitors.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Monitor getPriamryMonitor() {
|
||||||
|
return getMonitor(GLFW.glfwGetPrimaryMonitor());
|
||||||
|
}
|
||||||
|
|
||||||
public Monitor getMonitorForWindow(Window window) {
|
public Monitor getMonitorForWindow(Window window) {
|
||||||
return null;
|
long current = GLFW.glfwGetWindowMonitor(window.id());
|
||||||
|
if(current != 0L) return getMonitor(current);
|
||||||
|
int minX = window.x();
|
||||||
|
int minY = window.y();
|
||||||
|
int maxX = minX + window.screenWidth();
|
||||||
|
int maxY = minY + window.screenHeight();
|
||||||
|
int largest = 0;
|
||||||
|
Monitor mon = null;
|
||||||
|
for(Monitor monitor : monitors.values()) {
|
||||||
|
int next = monitor.getOverlap(minX, minY, maxX, maxY);
|
||||||
|
if(next > largest) {
|
||||||
|
largest = next;
|
||||||
|
mon = monitor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mon;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class WindowBuilder {
|
public static class WindowBuilder {
|
||||||
WindowManager manager;
|
WindowManager manager;
|
||||||
VideoMode mode;
|
long monitor;
|
||||||
|
VideoMode fullScreenTarget;
|
||||||
String title = "";
|
String title = "";
|
||||||
int width = 640;
|
int width = 640;
|
||||||
int height = 480;
|
int height = 480;
|
||||||
|
@ -63,6 +92,7 @@ public class WindowManager {
|
||||||
boolean fpsCap;
|
boolean fpsCap;
|
||||||
boolean fullScreen;
|
boolean fullScreen;
|
||||||
boolean maximized;
|
boolean maximized;
|
||||||
|
boolean resizable = true;
|
||||||
boolean floating;
|
boolean floating;
|
||||||
boolean borderless;
|
boolean borderless;
|
||||||
boolean center = true;
|
boolean center = true;
|
||||||
|
@ -70,7 +100,7 @@ public class WindowManager {
|
||||||
|
|
||||||
private WindowBuilder(WindowManager manager) {
|
private WindowBuilder(WindowManager manager) {
|
||||||
this.manager = manager;
|
this.manager = manager;
|
||||||
mode = manager.monitors.get(GLFW.glfwGetPrimaryMonitor()).defaultMode();
|
monitor = GLFW.glfwGetPrimaryMonitor();
|
||||||
}
|
}
|
||||||
|
|
||||||
public WindowBuilder title(String title) {
|
public WindowBuilder title(String title) {
|
||||||
|
@ -121,6 +151,11 @@ public class WindowManager {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public WindowBuilder resizeable(boolean resizable) {
|
||||||
|
this.resizable = resizable;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public WindowBuilder centered(boolean center) {
|
public WindowBuilder centered(boolean center) {
|
||||||
this.center = center;
|
this.center = center;
|
||||||
this.maximized &= !center;
|
this.maximized &= !center;
|
||||||
|
@ -130,7 +165,12 @@ public class WindowManager {
|
||||||
|
|
||||||
public WindowBuilder monitor(Monitor monitor) {
|
public WindowBuilder monitor(Monitor monitor) {
|
||||||
if(monitor == null || monitor.defaultMode() == null) return this;
|
if(monitor == null || monitor.defaultMode() == null) return this;
|
||||||
this.mode = monitor.defaultMode();
|
this.monitor = monitor.id();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WindowBuilder fullScreenMode(VideoMode mode) {
|
||||||
|
this.fullScreenTarget = mode;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue