Progress on the new Window API

This commit is contained in:
2024-05-14 01:38:13 +02:00
parent fea2b5ea22
commit 00671c00ff
13 changed files with 497 additions and 1969 deletions
@@ -0,0 +1,20 @@
package speiger.src.coreengine;
import speiger.src.coreengine.rendering.input.window.Window;
import speiger.src.coreengine.rendering.input.window.WindowManager;
public class NewInputTest {
WindowManager manager = new WindowManager();
public static void main(String[] args) {
new NewInputTest();
}
public void run() {
Window window = manager.builder().title("Testing").build();
while(true) {
}
}
}
@@ -2,7 +2,10 @@ package speiger.src.coreengine;
import java.nio.file.Path;
import org.lwjgl.glfw.GLFW;
import speiger.src.coreengine.application.Application;
import speiger.src.coreengine.rendering.inputOld.events.KeyEvent.KeyPressEvent;
import speiger.src.coreengine.rendering.inputOld.window.Window;
import speiger.src.coreengine.rendering.inputOld.window.WindowProvider;
@@ -12,9 +15,17 @@ public class Testing extends Application {
new Testing().run();
}
@Override
public String getMainWindowName() { return "Testing"; }
@Override
public boolean initUI() {
return true;
}
@Override
public Window createWindow(WindowProvider provider) throws Exception {
return provider.createBuilder().setWidth(250).setHeight(250).setName("Testing").build();
@@ -22,6 +33,7 @@ public class Testing extends Application {
@Override
public void init(Path file) {
eventBus.register(KeyPressEvent.class, this::addKeyPressed);
}
@Override
@@ -37,4 +49,20 @@ public class Testing extends Application {
}
public void addKeyPressed(KeyPressEvent event) {
if(event.key == GLFW.GLFW_KEY_F12) {
getUiManager().getDebug().toggleDebug();
event.cancel();
}
else if(event.key == GLFW.GLFW_KEY_PAGE_DOWN) {
mainWindow.setAntiAliasing(Math.max(0, mainWindow.getAntiAliasingLevel()-1));
event.cancel();
System.out.println("AA: "+mainWindow.getAntiAliasingLevel());
}
else if(event.key == GLFW.GLFW_KEY_PAGE_UP) {
mainWindow.setAntiAliasing(Math.min(4, mainWindow.getAntiAliasingLevel()+1));
event.cancel();
System.out.println("AA: "+mainWindow.getAntiAliasingLevel());
}
}
}
@@ -2,6 +2,7 @@ package speiger.src.coreengine.application;
import speiger.src.coreengine.rendering.guiOld.GuiManager;
import speiger.src.coreengine.rendering.guiOld.base.DebugOverlay;
import speiger.src.coreengine.rendering.guiOld.components.TextComponent;
import speiger.src.coreengine.rendering.models.buffers.UniformBuffer;
import speiger.src.coreengine.utils.collections.FlagHolder;
import speiger.src.coreengine.utils.profiler.EmptyProfiler;
@@ -62,6 +63,7 @@ public class BaseUIManager extends GuiManager
public static class InternalDebugOverlay extends DebugOverlay
{
TextComponent text = new TextComponent(0, 0, 200, 100, "Testing string");
public static final int UPDATING = 1;
public static final int RENDERING = 2;
FlagHolder flags = new FlagHolder(RENDERING);
@@ -77,5 +79,16 @@ public class BaseUIManager extends GuiManager
public boolean isUpdating() { return flags.isFlagSet(UPDATING); }
@Override
public boolean isRendering() { return flags.isFlagSet(RENDERING); }
@Override
public void onInit() {
super.onInit();
addComponent(text);
}
@Override
protected void render(int mouseX, int mouseY, float particalTicks) {
super.render(mouseX, mouseY, particalTicks);
}
}
}
@@ -9,66 +9,51 @@ import org.lwjgl.glfw.GLFWVidMode;
import speiger.src.collections.longs.maps.impl.hash.Long2ObjectLinkedOpenHashMap;
import speiger.src.collections.longs.maps.interfaces.Long2ObjectMap;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.lists.ObjectList;
public class Monitor
{
final long monitor;
List<VideoMode> modes = new ObjectArrayList<>();
final long id;
ObjectList<VideoMode> modes = new ObjectArrayList<>();
VideoMode defaultMode;
int xOffset;
int yOffset;
public Monitor(long monitor) {
this.monitor = monitor;
GLFWVidMode.Buffer buffer = GLFW.glfwGetVideoModes(monitor);
public Monitor(long id) {
this.id = id;
GLFWVidMode.Buffer buffer = GLFW.glfwGetVideoModes(id);
for(int i = buffer.limit() - 1;i >= 0;--i) {
VideoMode videomode = new VideoMode(this, buffer.position(i));
if(videomode.redBits() >= 8 && videomode.greenBits() >= 8 && videomode.blueBits() >= 8)
modes.add(videomode);
}
defaultMode = new VideoMode(this, GLFW.glfwGetVideoMode(monitor));
defaultMode = new VideoMode(this, GLFW.glfwGetVideoMode(id));
int[] xPos = new int[1];
int[] yPos = new int[1];
GLFW.glfwGetMonitorPos(monitor, xPos, yPos);
GLFW.glfwGetMonitorPos(id, xPos, yPos);
xOffset = xPos[0];
yOffset = yPos[0];
}
public String getMonitorName() {
return GLFW.glfwGetMonitorName(monitor);
}
//@formatter:off
public long id() { return id; }
public String name() { return GLFW.glfwGetMonitorName(id); }
public int size() { return modes.size(); }
public VideoMode getMode(int index) { return modes.get(index); }
public boolean contains(VideoMode mode) { return modes.indexOf(mode) != -1; }
public List<VideoMode> videoModes() { return modes.unmodifiable(); }
public VideoMode defaultMode() { return defaultMode; }
public int xOffset() { return xOffset; }
public int yOffset() { return yOffset; }
//@formatter:on
public long getMonitorId() {
return monitor;
}
@Override
public boolean equals(Object obj) { return obj instanceof Monitor mon && mon.id == id; }
@Override
public int hashCode() { return Long.hashCode(id); }
@Override
public String toString() { return "Monitor[Name=\""+name()+"\", Id="+id+", Width="+defaultMode.width()+", Height="+defaultMode.height()+", Modes="+size()+"]"; }
public int size() {
return modes.size();
}
public VideoMode getMode(int index) {
return modes.get(index);
}
public boolean contains(VideoMode mode) {
return modes.indexOf(mode) != -1;
}
public List<VideoMode> getVideoMods() {
return new ObjectArrayList<>(modes);
}
public VideoMode getDefaultMode() {
return defaultMode;
}
public int getXOffset() {
return xOffset;
}
public int getYOffset() {
return yOffset;
}
public static Long2ObjectMap<Monitor> createMonitors() {
Long2ObjectMap<Monitor> monitors = new Long2ObjectLinkedOpenHashMap<>();
@@ -0,0 +1,206 @@
package speiger.src.coreengine.rendering.input.window;
import java.util.List;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GLCapabilities;
import org.lwjgl.system.CallbackI;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.coreengine.rendering.input.window.WindowCallback.ReloadFunction;
import speiger.src.coreengine.rendering.input.window.WindowManager.WindowBuilder;
import speiger.src.coreengine.utils.collections.FlagHolder;
public class Window {
static final int FLAG_VISIBLE = 1;
static final int FLAG_VSYNC = 2;
static final int FLAG_FOCUS = 4;
static final int FLAG_CPU_FPS_CAP = 8;
static final int FLAG_FULL_SCREEN = 16;
static final int FLAG_MAXIMIZED = 32;
static final int FLAG_BORDERLESS = 64;
static final int FLAG_CLOSE = 128;
static final int FLAG_WINDOW_CHANGE = 256;
static final int FLAG_FLOATING = 512;
WindowManager manager;
FlagHolder flags = new FlagHolder();
long id;
VideoMode mode;
String title = "";
int x;
int y;
int width;
int height;
int frameWidth;
int frameHeight;
int windowX;
int windowY;
int windowWidth;
int windowHeight;
final int antialiasing;
List<WindowCallback> callbacks = new ObjectArrayList<>();
GLCapabilities capabilities;
protected Window(WindowBuilder builder) {
manager = builder.manager;
title = builder.title;
width = builder.width;
height = builder.height;
antialiasing = builder.antiAlis;
mode = builder.mode;
flags.setFlag(FLAG_BORDERLESS, builder.borderless);
flags.setFlag(FLAG_FULL_SCREEN, builder.fullScreen);
flags.setFlag(FLAG_FLOATING, builder.floating);
flags.setFlag(FLAG_VSYNC, builder.vsync);
flags.setFlag(FLAG_CPU_FPS_CAP, builder.fpsCap);
createDefaultWindowHints();
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_FLOATING, flags.isFlagNotSet(FLAG_FULL_SCREEN) && flags.isFlagSet(FLAG_FLOATING) ? 1 : 0);
GLFW.glfwWindowHint(GLFW.GLFW_MAXIMIZED, flags.isFlagNotSet(FLAG_FULL_SCREEN) && flags.isFlagSet(FLAG_MAXIMIZED) ? 1 : 0);
if(mode == null || mode.monitor() == null) throw new IllegalStateException("Monitor or Video Mode is missing: "+mode);
Monitor monitor = mode.monitor();
boolean fullscreen = builder.fullScreen;
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");
manager.addWindow(this);
createWindowListeners();
GLFW.glfwMakeContextCurrent(id);
capabilities = GL.createCapabilities(true);
x = monitor.xOffset() + (builder.center ? (mode.width() / 2) - (width / 2) : 0);
y = monitor.yOffset() + (builder.center ? (mode.height() / 2) - (height / 2) : 0);
if(!fullscreen) GLFW.glfwSetWindowPos(id, x, y);
GLFW.glfwSwapInterval(flags.isFlagSet(FLAG_VSYNC) ? 1 : 0);
fetchWindowBounds();
}
protected void createDefaultWindowHints() {
GLFW.glfwDefaultWindowHints();
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_MINOR, 0);
GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_PROFILE, GLFW.GLFW_OPENGL_CORE_PROFILE);
GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_FORWARD_COMPAT, GLFW.GLFW_TRUE);
}
protected void createWindowListeners() {
}
protected void fetchWindowBounds() {
int[] width = new int[1];
int[] height = new int[1];
GLFW.glfwGetWindowSize(id, width, height);
this.frameWidth = width[0];
this.frameHeight = height[0];
}
@SuppressWarnings("unchecked")
public <T extends CallbackI> void addCallback(T listener, ReloadFunction<T> function) {
WindowCallback callback = new WindowCallback(listener, (ReloadFunction<CallbackI>)function);
callbacks.add(callback);
callback.load(id);
}
public void title(String name) {
if(name == null || title.equals(name)) return;
title = name;
GLFW.glfwSetWindowTitle(id, title);
}
public void vsync(boolean vsync) {
if(!flags.setFlag(FLAG_VSYNC, vsync)) return;
GLFW.glfwSwapInterval(vsync ? 1 : 0);
}
public void fpsCap(boolean fpsCap) {
flags.setFlag(FLAG_CPU_FPS_CAP, fpsCap);
}
public void visible(boolean visible) {
if(!flags.setFlag(FLAG_VISIBLE, visible)) return;
if(visible) GLFW.glfwShowWindow(id);
else GLFW.glfwHideWindow(id);
}
public void floating(boolean floating) {
if(flags.isFlagNotSet(FLAG_FULL_SCREEN) && flags.setFlag(FLAG_FLOATING, floating)) {
GLFW.glfwSetWindowAttrib(id, GLFW.GLFW_FLOATING, floating ? GLFW.GLFW_TRUE : GLFW.GLFW_FALSE);
}
}
public void maximized(boolean maximized) {
if(flags.isFlagNotSet(FLAG_FULL_SCREEN) && flags.setFlag(FLAG_MAXIMIZED, maximized)) {
if(maximized) {
windowX = x;
windowY = y;
windowWidth = width;
windowHeight = height;
GLFW.glfwMaximizeWindow(id);
}
else {
x = windowX;
y = windowY;
width = windowWidth;
height = windowHeight;
GLFW.glfwRestoreWindow(id);
}
fetchWindowBounds();
}
}
public void resizeable(boolean resizeable) {
}
public void borderless(boolean borderless) {
}
public void fullscreen(boolean fullscreen) {
}
public boolean position(int x, int y) {
return false;
}
public boolean size(int width, int height) {
return false;
}
public boolean width(int width) {
return false;
}
public boolean height(int height) {
return false;
}
public long id() { return id; }
public VideoMode mode() { return mode; }
public int x() { return x; }
public int y() { return y; }
public int width() { return frameWidth; }
public int height() { return frameHeight; }
public int screenWidth() { return width; }
public int screenHeight() { return height; }
public boolean changed() { return flags.isFlagSet(FLAG_WINDOW_CHANGE); }
public String title() { return title; }
public boolean isVsync() { return false; }
public boolean isFPSCapped() { return false; }
public boolean isVisible() { return false; }
public boolean isFloating() { return false; }
public boolean isMaximized() { return false; }
public boolean isResizeable() { return false; }
public boolean isBorderless() { return false; }
public boolean isFullscreen() { return false; }
public int antialiasing() { return antialiasing; }
}
@@ -0,0 +1,34 @@
package speiger.src.coreengine.rendering.input.window;
import org.lwjgl.system.Callback;
import org.lwjgl.system.CallbackI;
public class WindowCallback {
ReloadFunction<CallbackI> function;
CallbackI listener;
Callback callback;
public WindowCallback(CallbackI listener, ReloadFunction<CallbackI> function) {
this.function = function;
this.listener = listener;
}
public void reload(long windowId) {
destroy();
load(windowId);
}
public void load(long windowId) {
callback = function.applyListener(windowId, listener);
}
public void destroy() {
if(callback == null) return;
callback.free();
callback = null;
}
public static interface ReloadFunction<T extends CallbackI> {
Callback applyListener(long window, T listener);
}
}
@@ -1,15 +1,157 @@
package speiger.src.coreengine.rendering.input.window;
import java.util.Objects;
import java.util.function.Consumer;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.system.Callback;
import speiger.src.collections.longs.maps.impl.concurrent.Long2ObjectConcurrentOpenHashMap;
import speiger.src.collections.longs.maps.interfaces.Long2ObjectMap;
public class WindowManager {
Long2ObjectMap<Monitor> monitors;
Long2ObjectMap<Window> windows = new Long2ObjectConcurrentOpenHashMap<>();
Window activeWindow;
Window primaryWindow;
Callback monitorTracker;
public void initialize() {
monitors = Monitor.createMonitors();
monitorTracker = GLFW.glfwSetMonitorCallback(this::onMonitorChanged);
}
private void onMonitorChanged(long monitor, int event) {
switch(event) {
case GLFW.GLFW_CONNECTED -> monitors.put(monitor, new Monitor(monitor));
case GLFW.GLFW_DISCONNECTED -> monitors.remove(monitor);
}
}
public WindowBuilder builder() { return new WindowBuilder(this); }
private Window create(WindowBuilder builder) {
return new Window(builder);
}
void addWindow(Window window) {
windows.put(window.id, window);
}
void updateWindow(long oldId) {
Window prev = windows.remove(oldId);
if(prev == null) return;
windows.put(prev.id, prev);
}
public long getPrimaryWindow() {
return primaryWindow == null ? 0 : primaryWindow.id;
}
public Monitor getMonitorForWindow(Window window) {
return null;
}
public static class WindowBuilder {
WindowManager manager;
VideoMode mode;
String title = "";
int width = 640;
int height = 480;
int antiAlis = 4;
boolean vsync = true;
boolean fpsCap;
boolean fullScreen;
boolean maximized;
boolean floating;
boolean borderless;
boolean center = true;
Consumer<Window> carrierThread;
private WindowBuilder(WindowManager manager) {
this.manager = manager;
mode = manager.monitors.get(GLFW.glfwGetPrimaryMonitor()).defaultMode();
}
public WindowBuilder title(String title) {
this.title = Objects.requireNonNull(title);
return this;
}
public WindowBuilder width(int width) {
this.width = Math.max(1, width);
return this;
}
public WindowBuilder height(int height) {
this.height = Math.max(1, height);
return this;
}
public WindowBuilder antialis(int antiAlis) {
this.antiAlis = Math.max(1, antiAlis);
return this;
}
public WindowBuilder fullscreen(boolean fullScreen) {
this.fullScreen = fullScreen;
borderless &= !fullScreen;
floating &= !fullScreen;
maximized &= !fullScreen;
center &= !fullScreen;
return this;
}
public WindowBuilder maximized(boolean maximized) {
this.maximized = maximized;
this.fullScreen &= !maximized;
center &= !maximized;
return this;
}
public WindowBuilder borderless(boolean borderless) {
this.borderless = borderless;
fullScreen &= !borderless;
return this;
}
public WindowBuilder floating(boolean floating) {
this.floating = floating;
fullScreen &= !floating;
return this;
}
public WindowBuilder centered(boolean center) {
this.center = center;
this.maximized &= !center;
this.fullScreen &= !center;
return this;
}
public WindowBuilder monitor(Monitor monitor) {
if(monitor == null || monitor.defaultMode() == null) return this;
this.mode = monitor.defaultMode();
return this;
}
public WindowBuilder vsync(boolean value) {
vsync = value;
return this;
}
public WindowBuilder fpsCap(boolean cap) {
fpsCap = cap;
return this;
}
public WindowBuilder carrierThread(Consumer<Window> run) {
carrierThread = run;
return this;
}
public Window build() {
return manager.create(this);
}
}
}
@@ -7,6 +7,7 @@ import org.lwjgl.glfw.GLFW;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GLCapabilities;
import org.lwjgl.system.Callback;
import org.lwjgl.system.MemoryUtil;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.coreengine.math.MathUtils;
@@ -68,6 +69,11 @@ public class Window
addCallback(T -> GLFW.glfwSetWindowMaximizeCallback(T, (K, V) -> flags.setFlag(FLAG_WINDOW_CHANGE)));
addCallback(T -> GLFW.glfwSetWindowPosCallback(T, (W, X, Y) -> setPosition(X, Y)));
addCallback(T -> GLFW.glfwSetWindowFocusCallback(T, (K, V) -> flags.setFlag(FLAG_FOCUS, V)));
addCallback(T -> GLFW.glfwSetErrorCallback(this::error));
}
private void error(int error, long text) {
System.out.println("Error: "+error+", "+MemoryUtil.memUTF8(text));
}
Window createWindow(WindowStats stat) {
@@ -253,6 +259,7 @@ public class Window
public boolean setAntiAliasing(int level) {
if(aaLevel != level) {
aaLevel = level;
// GLFW.glfwWindowHint(GLFW.GLFW_SAMPLES, aaLevel);
long last = windowId;
GLFW.glfwDefaultWindowHints();
GLFW.glfwWindowHint(GLFW.GLFW_VISIBLE, 1); // 0 = False, 1 = true
@@ -9,6 +9,7 @@ public class FloatState implements IGLState {
public FloatState(float defaultValue, FloatConsumer setter) {
this.defaultValue = this.value = defaultValue;
this.setter = setter;
}
public FloatState set(float value) {
@@ -1,70 +1,29 @@
package speiger.src.coreengine.utils.collections;
public class FlagHolder
{
public class FlagHolder {
int flags;
public FlagHolder()
{
}
public FlagHolder() {}
public FlagHolder(int initFlags)
{
public FlagHolder(int initFlags) {
flags = initFlags;
}
public void setFlag(int flag)
{
flags |= flag;
}
public boolean setFlag(int flag, boolean value)
{
if(isFlagSet(flag) == value)
{
return false;
}
flags = (value ? flags | flag : flags & ~(flag));
public void setFlag(int flag) { flags |= flag; }
public boolean setFlag(int flag, boolean value) {
if(isFlagSet(flag) == value) return false;
flags = (value ? flags | flag : flags & ~flag);
return true;
}
public void setFlags(int flags)
{
this.flags = flags;
}
public void setFlags(int flags) { this.flags = flags; }
public void flipFlag(int flag) { flags ^= flag; }
public void clearFlag(int flag) { flags &= ~flag; }
public void clearFlags() { flags = 0; }
public int getFlags() { return flags; }
public int getFlags()
{
return flags;
}
public void flipFlag(int flag)
{
flags ^= flag;
}
public void clearFlag(int flag)
{
flags &= ~flag;
}
public void clearFlags()
{
flags = 0;
}
public boolean isFlagSet(int flag)
{
return (flags & flag) == flag;
}
public boolean isAnyFlagSet(int flag)
{
return (flags & flag) != 0;
}
public boolean isFlagNotSet(int flag)
{
return (flags & flag) == 0;
}
public boolean isFlagSet(int flag) { return (flags & flag) == flag; }
public boolean isAnyFlagSet(int flag) { return (flags & flag) != 0; }
public boolean isFlagNotSet(int flag) { return (flags & flag) == 0; }
}
@@ -4,6 +4,8 @@ import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -15,7 +17,7 @@ import speiger.src.collections.objects.utils.ObjectLists;
public class EventBus
{
private static final Lookup LOOKUP = MethodHandles.lookup();
Object2ObjectMap<Class<? extends Event>, Listeners> listeners = new Object2ObjectConcurrentOpenHashMap<>();
Map<Class<? extends Event>, Listeners> listeners = new ConcurrentHashMap<>();
Object2ObjectMap<Object, List<EventListener>> instances = new Object2ObjectConcurrentOpenHashMap<>();
public <T extends Event> void register(Class<T> event, Consumer<T> listener) {