From 935bbaf7ceca9b78157e05d37a203f9de807c237 Mon Sep 17 00:00:00 2001 From: JeremyStarTM Date: Sat, 27 Jul 2024 02:25:10 +0200 Subject: [PATCH] Add monitor API and add UUIDs --- .../glfw/classes/GlfwInternalClass.java | 69 +++++++ .../glfw/classes/GlfwManagementClass.java | 3 + .../graphics/glfw/classes/GlfwMonitor.java | 114 ++++++++++++ .../graphics/glfw/classes/GlfwWindow.java | 42 +++-- .../graphics/opengl/OpenGlInternalApi.java | 13 +- .../opengl/classes/OpenGlMonitor.java | 35 ++++ .../graphics/opengl/classes/OpenGlWindow.java | 5 +- .../sosengine/graphics/classes/Monitor.java | 171 ++++++++++++++++++ .../sosengine/graphics/classes/Window.java | 90 ++++++++- .../classes/api/ApiInternalClass.java | 14 ++ .../sosengine/graphics/events/InputEvent.java | 3 +- .../exceptions/InvalidMonitorException.java | 27 +++ .../exceptions/NoMonitorsFoundException.java | 2 +- 13 files changed, 565 insertions(+), 23 deletions(-) create mode 100644 graphics/glfw/src/main/java/de/staropensource/sosengine/graphics/glfw/classes/GlfwInternalClass.java create mode 100644 graphics/glfw/src/main/java/de/staropensource/sosengine/graphics/glfw/classes/GlfwMonitor.java create mode 100644 graphics/opengl/src/main/java/de/staropensource/sosengine/graphics/opengl/classes/OpenGlMonitor.java create mode 100644 graphics/src/main/java/de/staropensource/sosengine/graphics/classes/Monitor.java create mode 100644 graphics/src/main/java/de/staropensource/sosengine/graphics/exceptions/InvalidMonitorException.java diff --git a/graphics/glfw/src/main/java/de/staropensource/sosengine/graphics/glfw/classes/GlfwInternalClass.java b/graphics/glfw/src/main/java/de/staropensource/sosengine/graphics/glfw/classes/GlfwInternalClass.java new file mode 100644 index 0000000..1d3ffd8 --- /dev/null +++ b/graphics/glfw/src/main/java/de/staropensource/sosengine/graphics/glfw/classes/GlfwInternalClass.java @@ -0,0 +1,69 @@ +/* + * STAROPENSOURCE ENGINE SOURCE FILE + * Copyright (c) 2024 The StarOpenSource Engine Contributors + * Licensed under the GNU Affero General Public License v3 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.staropensource.sosengine.graphics.glfw.classes; + +import de.staropensource.sosengine.base.logging.Logger; +import de.staropensource.sosengine.base.types.CodePart; +import de.staropensource.sosengine.base.types.logging.LogIssuer; +import de.staropensource.sosengine.graphics.classes.Monitor; +import de.staropensource.sosengine.graphics.classes.api.ApiInternalClass; +import de.staropensource.sosengine.graphics.exceptions.NoMonitorsFoundException; +import org.jetbrains.annotations.NotNull; +import org.lwjgl.PointerBuffer; + +import java.lang.reflect.InvocationTargetException; +import java.util.LinkedHashSet; + +import static org.lwjgl.glfw.GLFW.*; + +@SuppressWarnings({ "unused" }) +public abstract class GlfwInternalClass implements ApiInternalClass { + /** + * Returns the {@link Monitor} class. + * + * @return {@link Monitor} class + * @since v1-alpha2 + */ + @NotNull + public abstract Class getMonitorClass(); + + /** + * Returns all connected monitors. + * + * @return connected monitors + * @since v1-alpha2 + */ + @Override + public @NotNull LinkedHashSet<@NotNull Monitor> getMonitors() throws NoMonitorsFoundException { + PointerBuffer monitors = glfwGetMonitors(); + LinkedHashSet<@NotNull Monitor> output = new LinkedHashSet<>(); + if (monitors == null) + throw new NoMonitorsFoundException(); + + while (monitors.hasRemaining()) + try { + output.add(getMonitorClass().getDeclaredConstructor(Long.TYPE).newInstance(monitors.get())); + } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException exception) { + Logger.crash(new LogIssuer(getClass(), CodePart.ENGINE), "Unable to create new Monitor instance: Threw an exception", exception); + } + + return output; + } +} diff --git a/graphics/glfw/src/main/java/de/staropensource/sosengine/graphics/glfw/classes/GlfwManagementClass.java b/graphics/glfw/src/main/java/de/staropensource/sosengine/graphics/glfw/classes/GlfwManagementClass.java index 995b377..548907d 100644 --- a/graphics/glfw/src/main/java/de/staropensource/sosengine/graphics/glfw/classes/GlfwManagementClass.java +++ b/graphics/glfw/src/main/java/de/staropensource/sosengine/graphics/glfw/classes/GlfwManagementClass.java @@ -58,6 +58,7 @@ public abstract class GlfwManagementClass extends ApiManagementClass { LinkedHashMap<@NotNull Window, @NotNull Throwable> throwables = new LinkedHashMap<>(); + // Update and render all windows for (Window window : Window.getWindows()) { try { window.updateState(); @@ -67,6 +68,8 @@ public abstract class GlfwManagementClass extends ApiManagementClass { throwables.put(window, throwable); } } + + // Poll for events glfwPollEvents(); return throwables; diff --git a/graphics/glfw/src/main/java/de/staropensource/sosengine/graphics/glfw/classes/GlfwMonitor.java b/graphics/glfw/src/main/java/de/staropensource/sosengine/graphics/glfw/classes/GlfwMonitor.java new file mode 100644 index 0000000..2072fbb --- /dev/null +++ b/graphics/glfw/src/main/java/de/staropensource/sosengine/graphics/glfw/classes/GlfwMonitor.java @@ -0,0 +1,114 @@ +/* + * STAROPENSOURCE ENGINE SOURCE FILE + * Copyright (c) 2024 The StarOpenSource Engine Contributors + * Licensed under the GNU Affero General Public License v3 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.staropensource.sosengine.graphics.glfw.classes; + +import de.staropensource.sosengine.base.types.vectors.Vec2i; +import de.staropensource.sosengine.graphics.classes.Monitor; +import de.staropensource.sosengine.graphics.exceptions.InvalidMonitorException; +import lombok.SneakyThrows; +import org.jetbrains.annotations.NotNull; +import org.lwjgl.glfw.GLFWVidMode; + +import java.util.Objects; + +import static org.lwjgl.glfw.GLFW.*; + +@SuppressWarnings({ "unused", "JavadocDeclaration", "JavadocBlankLines" }) +public class GlfwMonitor extends Monitor { + /** + * Contains the {@link #identifier} as a long. + * + * @since v1-alpha2 + * + * -- GETTER -- + * Returns the monitor identifier as a long. + * + * @return monitor identifier as a long + * @since v1-alpha2 + */ + private final long identifierLong; + + /** + * Constructs this class. + * + * @param identifier glfw monitor pointer + * @since v1-alpha2 + */ + @SneakyThrows + public GlfwMonitor(long identifier) throws InvalidMonitorException { + // Set identifier + setIdentifier(String.valueOf(identifier)); + identifierLong = identifier; + + // Check if connected + checkConnected(); + } + + /** {@inheritDoc} */ + @SneakyThrows + public void checkConnected() throws InvalidMonitorException { + super.checkConnected(); + } + + /** {@inheritDoc} */ + @Override + public boolean isConnected() { + return glfwGetMonitorName(identifierLong) != null; + } + + /** + * Returns the monitor name. + * + * @return monitor name + * @since v1-alpha2 + */ + @Override + public @NotNull String getName() throws InvalidMonitorException { + checkConnected(); + return Objects.requireNonNull(glfwGetMonitorName(identifierLong)); + } + + /** + * Returns the monitor size. + * + * @return monitor size + * @since v1-alpha2 + */ + @Override + public @NotNull Vec2i getSize() throws InvalidMonitorException { + checkConnected(); + + GLFWVidMode videoMode = Objects.requireNonNull(glfwGetVideoMode(identifierLong)); + + return new Vec2i(videoMode.width(), videoMode.height()); + } + + /** + * Returns the monitor refresh rate. + * + * @return monitor refresh rate + * @since v1-alpha2 + */ + @Override + public short getRefreshRate() throws InvalidMonitorException { + checkConnected(); + return (short) Objects.requireNonNull(glfwGetVideoMode(identifierLong)).refreshRate(); + } +} diff --git a/graphics/glfw/src/main/java/de/staropensource/sosengine/graphics/glfw/classes/GlfwWindow.java b/graphics/glfw/src/main/java/de/staropensource/sosengine/graphics/glfw/classes/GlfwWindow.java index eea8c51..aaafa2a 100644 --- a/graphics/glfw/src/main/java/de/staropensource/sosengine/graphics/glfw/classes/GlfwWindow.java +++ b/graphics/glfw/src/main/java/de/staropensource/sosengine/graphics/glfw/classes/GlfwWindow.java @@ -24,6 +24,7 @@ import de.staropensource.sosengine.base.types.Tristate; import de.staropensource.sosengine.base.types.vectors.Vec2i; import de.staropensource.sosengine.base.utility.Miscellaneous; import de.staropensource.sosengine.graphics.GraphicsSubsystemConfiguration; +import de.staropensource.sosengine.graphics.classes.Monitor; import de.staropensource.sosengine.graphics.classes.Window; import de.staropensource.sosengine.graphics.events.GraphicsApiErrorEvent; import de.staropensource.sosengine.graphics.events.InputEvent; @@ -41,6 +42,7 @@ import org.lwjgl.system.MemoryStack; import org.lwjgl.system.MemoryUtil; import java.nio.IntBuffer; +import java.util.Objects; import static org.lwjgl.glfw.GLFW.*; @@ -90,6 +92,7 @@ public abstract class GlfwWindow extends Window { * @param maximumSize maximum size * @param position position * @param windowMode window mode + * @param monitor monitor * @param resizable resizable flag * @param borderless borderless flag * @param focusable focusable flag @@ -99,8 +102,8 @@ public abstract class GlfwWindow extends Window { * @throws UnexpectedThrowableException stuff thrown by the {@link #initializeWindow()} and {@link #render()} methods of the implementing Graphics API * @since v1-alpha2 */ - public GlfwWindow(@NotNull String name, @NotNull String title, @NotNull Vec2i size, @NotNull Vec2i minimumSize, @NotNull Vec2i maximumSize, @NotNull Vec2i position, @NotNull WindowMode windowMode, boolean resizable, boolean borderless, boolean focusable, boolean onTop, boolean transparent, boolean rendering) throws UnexpectedThrowableException { - super(name, title, size, minimumSize, maximumSize, position, windowMode, resizable, borderless, focusable, onTop, transparent, rendering); + public GlfwWindow(@NotNull String name, @NotNull String title, @NotNull Vec2i size, @NotNull Vec2i minimumSize, @NotNull Vec2i maximumSize, @NotNull Vec2i position, @NotNull WindowMode windowMode, @NotNull Monitor monitor, boolean resizable, boolean borderless, boolean focusable, boolean onTop, boolean transparent, boolean rendering) throws UnexpectedThrowableException { + super(name, title, size, minimumSize, maximumSize, position, windowMode, monitor, resizable, borderless, focusable, onTop, transparent, rendering); } /** {@inheritDoc} */ @@ -226,6 +229,31 @@ public abstract class GlfwWindow extends Window { if (!Miscellaneous.onMainThread()) throw new NotOnMainThreadException(); + // Update window mode + if (Miscellaneous.getBooleanizedInteger(glfwGetWindowAttrib(identifierLong, GLFW_ICONIFIED))) + super.setWindowMode(WindowMode.MINIMIZED); + else if (Miscellaneous.getBooleanizedInteger(glfwGetWindowAttrib(identifierLong, GLFW_MAXIMIZED))) + super.setWindowMode(WindowMode.MAXIMIZED); + else if (Miscellaneous.getBooleanizedInteger(glfwGetWindowAttrib(identifierLong, GLFW_VISIBLE))) + super.setWindowMode(WindowMode.WINDOWED); + else if (Miscellaneous.getBooleanizedInteger(glfwGetWindowAttrib(identifierLong, GLFW_VISIBLE))) + super.setWindowMode(WindowMode.HIDDEN); + + // Update monitor + if (!getMonitor().isConnected()) { + Monitor newMonitor = null; + + for (Monitor monitor : Monitor.getMonitors()) + if (monitor.isConnected()) + newMonitor = monitor; + + if (newMonitor == null) + getLogger().crash("Unable to set a new target monitor for window " + getUniqueIdentifier() + " as no monitors are connected to the system"); + + setMonitor(Objects.requireNonNull(newMonitor)); + } + + // Update vectors try (MemoryStack stack = MemoryStack.stackPush()) { IntBuffer width = stack.mallocInt(2); IntBuffer height = stack.mallocInt(2); @@ -237,16 +265,6 @@ public abstract class GlfwWindow extends Window { super.setPosition(new Vec2i(width.get(), height.get())); } - // Update window mode - if (Miscellaneous.getBooleanizedInteger(glfwGetWindowAttrib(identifierLong, GLFW_ICONIFIED))) - super.setWindowMode(WindowMode.MINIMIZED); - else if (Miscellaneous.getBooleanizedInteger(glfwGetWindowAttrib(identifierLong, GLFW_MAXIMIZED))) - super.setWindowMode(WindowMode.MAXIMIZED); - else if (Miscellaneous.getBooleanizedInteger(glfwGetWindowAttrib(identifierLong, GLFW_VISIBLE))) - super.setWindowMode(WindowMode.WINDOWED); - else if (Miscellaneous.getBooleanizedInteger(glfwGetWindowAttrib(identifierLong, GLFW_VISIBLE))) - super.setWindowMode(WindowMode.HIDDEN); - // Update booleans super.setResizable(Miscellaneous.getBooleanizedInteger(glfwGetWindowAttrib(identifierLong, GLFW_RESIZABLE))); super.setOnTop(Miscellaneous.getBooleanizedInteger(glfwGetWindowAttrib(identifierLong, GLFW_FLOATING))); diff --git a/graphics/opengl/src/main/java/de/staropensource/sosengine/graphics/opengl/OpenGlInternalApi.java b/graphics/opengl/src/main/java/de/staropensource/sosengine/graphics/opengl/OpenGlInternalApi.java index 720ad0c..fbb1bb8 100644 --- a/graphics/opengl/src/main/java/de/staropensource/sosengine/graphics/opengl/OpenGlInternalApi.java +++ b/graphics/opengl/src/main/java/de/staropensource/sosengine/graphics/opengl/OpenGlInternalApi.java @@ -19,16 +19,27 @@ package de.staropensource.sosengine.graphics.opengl; +import de.staropensource.sosengine.graphics.classes.Monitor; import de.staropensource.sosengine.graphics.classes.api.ApiInternalClass; import de.staropensource.sosengine.graphics.classes.Window; +import de.staropensource.sosengine.graphics.glfw.classes.GlfwInternalClass; +import de.staropensource.sosengine.graphics.opengl.classes.OpenGlMonitor; import de.staropensource.sosengine.graphics.opengl.classes.OpenGlWindow; import org.jetbrains.annotations.NotNull; -public final class OpenGlInternalApi implements ApiInternalClass { +import java.util.Set; + +public final class OpenGlInternalApi extends GlfwInternalClass { /** {@inheritDoc} */ @Override @NotNull public Class getWindowClass() { return OpenGlWindow.class; } + + /** {@inheritDoc} */ + @Override + public @NotNull Class getMonitorClass() { + return OpenGlMonitor.class; + } } diff --git a/graphics/opengl/src/main/java/de/staropensource/sosengine/graphics/opengl/classes/OpenGlMonitor.java b/graphics/opengl/src/main/java/de/staropensource/sosengine/graphics/opengl/classes/OpenGlMonitor.java new file mode 100644 index 0000000..3e18666 --- /dev/null +++ b/graphics/opengl/src/main/java/de/staropensource/sosengine/graphics/opengl/classes/OpenGlMonitor.java @@ -0,0 +1,35 @@ +/* + * STAROPENSOURCE ENGINE SOURCE FILE + * Copyright (c) 2024 The StarOpenSource Engine Contributors + * Licensed under the GNU Affero General Public License v3 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.staropensource.sosengine.graphics.opengl.classes; + +import de.staropensource.sosengine.graphics.exceptions.InvalidMonitorException; +import de.staropensource.sosengine.graphics.glfw.classes.GlfwMonitor; + +public class OpenGlMonitor extends GlfwMonitor { + /** + * Constructs this class. + * + * @param identifier glfw monitor pointer + * @since v1-alpha2 + */ + public OpenGlMonitor(long identifier) throws InvalidMonitorException { + super(identifier); + } +} diff --git a/graphics/opengl/src/main/java/de/staropensource/sosengine/graphics/opengl/classes/OpenGlWindow.java b/graphics/opengl/src/main/java/de/staropensource/sosengine/graphics/opengl/classes/OpenGlWindow.java index c809eb6..9e7727c 100644 --- a/graphics/opengl/src/main/java/de/staropensource/sosengine/graphics/opengl/classes/OpenGlWindow.java +++ b/graphics/opengl/src/main/java/de/staropensource/sosengine/graphics/opengl/classes/OpenGlWindow.java @@ -21,6 +21,7 @@ package de.staropensource.sosengine.graphics.opengl.classes; import de.staropensource.sosengine.base.exceptions.UnexpectedThrowableException; import de.staropensource.sosengine.base.types.vectors.Vec2i; +import de.staropensource.sosengine.graphics.classes.Monitor; import de.staropensource.sosengine.graphics.glfw.classes.GlfwWindow; import de.staropensource.sosengine.graphics.exceptions.NotOnMainThreadException; import de.staropensource.sosengine.graphics.exceptions.WindowCreationFailureException; @@ -57,8 +58,8 @@ public final class OpenGlWindow extends GlfwWindow { * @throws UnexpectedThrowableException stuff thrown by the {@link #initializeWindow()} and {@link #render()} methods of the implementing Graphics API * @since v1-alpha2 */ - public OpenGlWindow(@NotNull String name, @NotNull String title, @NotNull Vec2i size, @NotNull Vec2i minimumSize, @NotNull Vec2i maximumSize, @NotNull Vec2i position, @NotNull WindowMode windowMode, boolean resizable, boolean borderless, boolean focusable, boolean onTop, boolean transparent, boolean rendering) throws UnexpectedThrowableException { - super(name, title, size, minimumSize, maximumSize, position, windowMode, resizable, borderless, focusable, onTop, transparent, rendering); + public OpenGlWindow(@NotNull String name, @NotNull String title, @NotNull Vec2i size, @NotNull Vec2i minimumSize, @NotNull Vec2i maximumSize, @NotNull Vec2i position, @NotNull WindowMode windowMode, @NotNull Monitor monitor, boolean resizable, boolean borderless, boolean focusable, boolean onTop, boolean transparent, boolean rendering) throws UnexpectedThrowableException { + super(name, title, size, minimumSize, maximumSize, position, windowMode, monitor, resizable, borderless, focusable, onTop, transparent, rendering); } /** {@inheritDoc} */ diff --git a/graphics/src/main/java/de/staropensource/sosengine/graphics/classes/Monitor.java b/graphics/src/main/java/de/staropensource/sosengine/graphics/classes/Monitor.java new file mode 100644 index 0000000..b68811a --- /dev/null +++ b/graphics/src/main/java/de/staropensource/sosengine/graphics/classes/Monitor.java @@ -0,0 +1,171 @@ +/* + * STAROPENSOURCE ENGINE SOURCE FILE + * Copyright (c) 2024 The StarOpenSource Engine Contributors + * Licensed under the GNU Affero General Public License v3 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.staropensource.sosengine.graphics.classes; + +import de.staropensource.sosengine.base.logging.LoggerInstance; +import de.staropensource.sosengine.base.types.CodePart; +import de.staropensource.sosengine.base.types.logging.LogIssuer; +import de.staropensource.sosengine.base.types.vectors.Vec2i; +import de.staropensource.sosengine.graphics.GraphicsSubsystem; +import de.staropensource.sosengine.graphics.exceptions.InvalidMonitorException; +import de.staropensource.sosengine.graphics.exceptions.NoMonitorsFoundException; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.Setter; +import org.jetbrains.annotations.NotNull; + +import java.util.LinkedHashSet; +import java.util.UUID; + +/** + * Abstract class for implementing monitors in a Graphics API. + *

+ * Note that monitors stop working unannounced when disconnected, + * call {@link #isConnected()} before using to avoid unexpected behaviour. + * + * @since v1-alpha2 + */ +@SuppressWarnings({ "unused", "JavadocDeclaration", "JavadocBlankLines" }) +public abstract class Monitor { + /** + * The logger instance for this class. + * + * @see LoggerInstance + * @since v1-alpha2 + * + * -- GETTER -- + * Returns the logger instance for this class. + * + * @return logger instance + * @see LoggerInstance + * @since v1-alpha2 + */ + @Getter(value = AccessLevel.PROTECTED) + private final LoggerInstance logger = new LoggerInstance(new LogIssuer(getClass(), CodePart.ENGINE)); + + /** + * Contains the unique monitor identifier. + *

+ * This identifier is unique to every monitor and does not change during runtime. + * + * @since v1-alpha2 + * + * -- GETTER -- + * Returns the unique monitor identifier. + *

+ * This identifier is unique to every monitor and does not change during runtime. + * + * @return unique identifier + * @since v1-alpha2 + */ + @Getter + private final UUID uniqueIdentifier; + + /** + * Contains the monitor identifier. + *

+ * This identifier is used by the Graphics API to refer to a monitor and may change during runtime. + * + * @since v1-alpha1 + * + * -- GETTER -- + * Returns the monitor identifier. + *

+ * This identifier is used by the Graphics API to refer to a monitor and may change during runtime. + * + * @return monitor identifier + * @since v1-alpha2 + * + * -- SETTER -- + * Sets the monitor identifier. + *

+ * This identifier is used by the Graphics API to refer to a monitor and may change during runtime. + * + * @param identifier new monitor identifier + * @since v1-alpha2 + */ + @Setter(AccessLevel.PROTECTED) + private String identifier = null; + + /** + * Constructs this class. + * + * @since v1-alpha2 + */ + public Monitor() { + this.uniqueIdentifier = UUID.randomUUID(); + } + + /** + * Returns all connected monitors. + * + * @return connected monitors + * @since v1-alpha2 + */ + @NotNull + public static LinkedHashSet<@NotNull Monitor> getMonitors() throws NoMonitorsFoundException { + return GraphicsSubsystem.getInstance().getApi().getInternalApi().getMonitors(); + } + + /** + * Checks if the monitor is actually connected. + * If not, throws an {@link InvalidMonitorException}. + * + * @since v1-alpha2 + */ + public void checkConnected() throws InvalidMonitorException, NoMonitorsFoundException { + if (!isConnected()) + throw new InvalidMonitorException(); + } + + /** + * Checks if the monitor is connected or not. + * + * @return connection status + * @since v1-alpha2 + */ + public abstract boolean isConnected() throws NoMonitorsFoundException; + + /** + * Returns the monitor name. + * + * @return monitor name + * @since v1-alpha2 + */ + @NotNull + public abstract String getName() throws InvalidMonitorException, NoMonitorsFoundException; + + /** + * Returns the monitor size. + * + * @return monitor size + * @since v1-alpha2 + */ + @NotNull + public abstract Vec2i getSize() throws InvalidMonitorException, NoMonitorsFoundException; + + /** + * Returns the monitor refresh rate. + * + * @return monitor refresh rate + * @since v1-alpha2 + */ + public abstract short getRefreshRate() throws InvalidMonitorException, NoMonitorsFoundException; +} diff --git a/graphics/src/main/java/de/staropensource/sosengine/graphics/classes/Window.java b/graphics/src/main/java/de/staropensource/sosengine/graphics/classes/Window.java index d89d280..c5fd967 100644 --- a/graphics/src/main/java/de/staropensource/sosengine/graphics/classes/Window.java +++ b/graphics/src/main/java/de/staropensource/sosengine/graphics/classes/Window.java @@ -35,6 +35,7 @@ import org.jetbrains.annotations.Nullable; import java.util.HashSet; import java.util.Set; +import java.util.UUID; /** * Abstract class for implementing windows in a Graphics API. @@ -94,13 +95,34 @@ public abstract class Window implements AutoCloseable { @Setter(AccessLevel.PROTECTED) private boolean terminated; + /** + * Contains the unique window identifier. + *

+ * This identifier is unique to every window and does not change during runtime. + * + * @since v1-alpha2 + * + * -- GETTER -- + * Returns the unique window identifier. + *

+ * This identifier is unique to every window and does not change during runtime. + * + * @return unique identifier + * @since v1-alpha2 + */ + private final UUID uniqueIdentifier; + /** * Contains the window identifier. + *

+ * This identifier is used by the Graphics API to refer to a window and may change during runtime. * * @since v1-alpha1 * * -- GETTER -- * Returns the window identifier. + *

+ * This identifier is used by the Graphics API to refer to a window and may change during runtime. * * @return window identifier * @since v1-alpha2 @@ -108,7 +130,7 @@ public abstract class Window implements AutoCloseable { * -- SETTER -- * Sets the window identifier. *

- * Recommended to be called only once. + * This identifier is used by the Graphics API to refer to a window and may change during runtime. * * @param identifier new window identifier * @since v1-alpha2 @@ -317,6 +339,27 @@ public abstract class Window implements AutoCloseable { @Setter private WindowMode windowMode; + /** + * Determines on which {@link Monitor} the window is displayed on. + * + * @since v1-alpha2 + * + * -- GETTER -- + * Returns the {@link Monitor} the window is displayed on. + * + * @return target monitor + * @since v1-alpha2 + * + * -- SETTER -- + * Sets the {@link Monitor} the window is displayed on. + * + * @param monitor new target monitor + * @since v1-alpha2 + */ + @NotNull + @Setter + private Monitor monitor; + /** * Determines how fast the window may update it's contents. * @@ -485,6 +528,7 @@ public abstract class Window implements AutoCloseable { * @param maximumSize maximum size * @param position position * @param windowMode window mode + * @param monitor monitor * @param resizable resizable flag * @param borderless borderless flag * @param focusable focusable flag @@ -494,10 +538,9 @@ public abstract class Window implements AutoCloseable { * @throws UnexpectedThrowableException stuff thrown by the {@link #initializeWindow()} and {@link #render()} methods of the implementing Graphics API * @since v1-alpha2 */ - public Window(@NotNull String name, @NotNull String title, @NotNull Vec2i size, @NotNull Vec2i minimumSize, @NotNull Vec2i maximumSize, @NotNull Vec2i position, @NotNull WindowMode windowMode, boolean resizable, boolean borderless, boolean focusable, boolean onTop, boolean transparent, boolean rendering) throws UnexpectedThrowableException { - logger.diag("Creating new window with properties: name=\"" + name + "\" title=\"" + title + "\" size=" + size + " minimumSize=" + minimumSize + " maximumSize=" + maximumSize + " position=" + position + " windowMode=" + windowMode + " resizable=" + resizable + " borderless=" + borderless + " focusable=" + focusable + " onTop=" + onTop + " transparent=" + transparent + " rendering=" + rendering); - + public Window(@NotNull String name, @NotNull String title, @NotNull Vec2i size, @NotNull Vec2i minimumSize, @NotNull Vec2i maximumSize, @NotNull Vec2i position, @NotNull WindowMode windowMode, @NotNull Monitor monitor, boolean resizable, boolean borderless, boolean focusable, boolean onTop, boolean transparent, boolean rendering) throws UnexpectedThrowableException { // Initialize variables + this.uniqueIdentifier = UUID.randomUUID(); this.name = name; this.title = title; this.size = size; @@ -505,6 +548,7 @@ public abstract class Window implements AutoCloseable { this.maximumSize = maximumSize; this.position = position; this.windowMode = windowMode; + this.monitor = monitor; this.resizable = resizable; this.borderless = borderless; this.focusable = focusable; @@ -512,6 +556,9 @@ public abstract class Window implements AutoCloseable { this.transparent = transparent; this.rendering = rendering; + // Log about window creation + logger.diag("Creating new window with properties: uniqueIdentifier=" + uniqueIdentifier + " name=\"" + name + "\" title=\"" + title + "\" size=" + size + " minimumSize=" + minimumSize + " maximumSize=" + maximumSize + " position=" + position + " windowMode=" + windowMode + " monitor=" + monitor.getUniqueIdentifier() + " (" + monitor.getName() + ") resizable=" + resizable + " borderless=" + borderless + " focusable=" + focusable + " onTop=" + onTop + " transparent=" + transparent + " rendering=" + rendering); + try { // Allow Graphics API to initialize window initializeWindow(); @@ -752,6 +799,22 @@ public abstract class Window implements AutoCloseable { @Nullable private WindowMode windowMode = null; + /** + * Contains the target monitor. + * + * @see Window#monitor + * @since v1-alpha2 + * + * -- GETTER -- + * Returns the target monitor. + * + * @return target monitor + * @see Window#monitor + * @since v1-alpha2 + */ + @Nullable + private Monitor monitor = null; + /** * Contains the resizable flag. * @@ -888,6 +951,8 @@ public abstract class Window implements AutoCloseable { maximumSize = new Vec2i(-1, -1); if (windowMode == null) windowMode = WindowMode.WINDOWED; + if (monitor == null) + monitor = Monitor.getMonitors().getFirst(); // Override booleanized tristate defaults if (resizable == Tristate.FALSE) @@ -906,8 +971,8 @@ public abstract class Window implements AutoCloseable { // Create new Window instance try { return GraphicsSubsystem.getInstance().getApi().getInternalApi().getWindowClass() - .getDeclaredConstructor(String.class, String.class, Vec2i.class, Vec2i.class, Vec2i.class, Vec2i.class, WindowMode.class, Boolean.TYPE, Boolean.TYPE, Boolean.TYPE, Boolean.TYPE, Boolean.TYPE, Boolean.TYPE) - .newInstance(name, title, size, minimumSize, maximumSize, position, windowMode, resizableBoolean, borderlessBoolean, focusableBoolean, onTopBoolean, transparentBoolean, renderingBoolean); + .getDeclaredConstructor(String.class, String.class, Vec2i.class, Vec2i.class, Vec2i.class, Vec2i.class, WindowMode.class, Monitor.class, Boolean.TYPE, Boolean.TYPE, Boolean.TYPE, Boolean.TYPE, Boolean.TYPE, Boolean.TYPE) + .newInstance(name, title, size, minimumSize, maximumSize, position, windowMode, monitor, resizableBoolean, borderlessBoolean, focusableBoolean, onTopBoolean, transparentBoolean, renderingBoolean); } catch (Throwable throwable) { throw new UnexpectedThrowableException(throwable, "Window.Builder was unable to create new Window instance"); } @@ -1004,6 +1069,19 @@ public abstract class Window implements AutoCloseable { return this; } + /** + * Sets the target monitor. + * + * @param monitor new target monitor + * @return builder instance + * @since v1-alpha2 + */ + @NotNull + private synchronized Builder setMonitor(@Nullable Monitor monitor) { + this.monitor = monitor; + return this; + } + /** * Sets the resizable flag. * diff --git a/graphics/src/main/java/de/staropensource/sosengine/graphics/classes/api/ApiInternalClass.java b/graphics/src/main/java/de/staropensource/sosengine/graphics/classes/api/ApiInternalClass.java index c62c5ad..cfc10e5 100644 --- a/graphics/src/main/java/de/staropensource/sosengine/graphics/classes/api/ApiInternalClass.java +++ b/graphics/src/main/java/de/staropensource/sosengine/graphics/classes/api/ApiInternalClass.java @@ -19,9 +19,13 @@ package de.staropensource.sosengine.graphics.classes.api; +import de.staropensource.sosengine.graphics.classes.Monitor; import de.staropensource.sosengine.graphics.classes.Window; +import de.staropensource.sosengine.graphics.exceptions.NoMonitorsFoundException; import org.jetbrains.annotations.NotNull; +import java.util.LinkedHashSet; + /** * The interface for internal API access, used by the graphics subsystem. * @@ -33,7 +37,17 @@ public interface ApiInternalClass { * Returns the {@link Window} class. * * @return {@link Window} class + * @since v1-alpha2 */ @NotNull Class getWindowClass(); + + /** + * Returns all connected monitors. + * + * @return connected monitors + * @since v1-alpha2 + */ + @NotNull + LinkedHashSet<@NotNull Monitor> getMonitors() throws NoMonitorsFoundException; } diff --git a/graphics/src/main/java/de/staropensource/sosengine/graphics/events/InputEvent.java b/graphics/src/main/java/de/staropensource/sosengine/graphics/events/InputEvent.java index ad9dae0..42eb976 100644 --- a/graphics/src/main/java/de/staropensource/sosengine/graphics/events/InputEvent.java +++ b/graphics/src/main/java/de/staropensource/sosengine/graphics/events/InputEvent.java @@ -64,7 +64,8 @@ public class InputEvent implements Event { */ public void callEvent(@Nullable Window window, @NotNull Key key, @NotNull KeyState state) { if (GraphicsSubsystemConfiguration.getInstance().isDebugInput()) - logger.diag("Got input event: window=" + (window == null ? "" : window.getName() + (window.getName() == null ? "" : "(" + window.getName() + ")") + "[" + window.hashCode() + "]") + " key=" + key.name() + " state=" + state.name()); + logger.diag("Got input event: window=" + (window == null ? "\\" : window.getUniqueIdentifier()) + " key=" + key.name() + " state=" + state.name()); + EventHelper.invokeAnnotatedMethods(getClass(), window, key, state); } } diff --git a/graphics/src/main/java/de/staropensource/sosengine/graphics/exceptions/InvalidMonitorException.java b/graphics/src/main/java/de/staropensource/sosengine/graphics/exceptions/InvalidMonitorException.java new file mode 100644 index 0000000..bdcfc15 --- /dev/null +++ b/graphics/src/main/java/de/staropensource/sosengine/graphics/exceptions/InvalidMonitorException.java @@ -0,0 +1,27 @@ +/* + * STAROPENSOURCE ENGINE SOURCE FILE + * Copyright (c) 2024 The StarOpenSource Engine Contributors + * Licensed under the GNU Affero General Public License v3 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.staropensource.sosengine.graphics.exceptions; + +/** + * Thrown when the specified monitor could not be found. + * + * @since v1-alpha2 + */ +public class InvalidMonitorException extends RuntimeException {} diff --git a/graphics/src/main/java/de/staropensource/sosengine/graphics/exceptions/NoMonitorsFoundException.java b/graphics/src/main/java/de/staropensource/sosengine/graphics/exceptions/NoMonitorsFoundException.java index 4259358..8e2ed28 100644 --- a/graphics/src/main/java/de/staropensource/sosengine/graphics/exceptions/NoMonitorsFoundException.java +++ b/graphics/src/main/java/de/staropensource/sosengine/graphics/exceptions/NoMonitorsFoundException.java @@ -25,4 +25,4 @@ package de.staropensource.sosengine.graphics.exceptions; * @since v1-alpha2 */ @SuppressWarnings({ "unused" }) -public final class NoMonitorsFoundException extends Exception {} +public final class NoMonitorsFoundException extends RuntimeException {}