From 42d0feb574fd85a6fb71b271f460256f0acd2055 Mon Sep 17 00:00:00 2001 From: JeremyStarTM Date: Mon, 22 Jul 2024 13:40:03 +0200 Subject: [PATCH] Update Window classes --- .../graphics/glfw/GlfwSubsystem.java | 1 - .../graphics/glfw/classes/GlfwWindow.java | 359 ++++++++++++++++++ .../graphics/glfw/classes/Window.java | 154 -------- .../graphics/opengl/OpenGlInternalApi.java | 3 +- .../{Window.java => OpenGlWindow.java} | 26 +- .../GraphicsSubsystemConfiguration.java | 37 ++ .../sosengine/graphics/classes/Window.java | 265 ++++++++++++- .../sosengine/graphics/types/WindowMode.java | 30 +- .../sosengine/testapp/Main.java | 1 + 9 files changed, 705 insertions(+), 171 deletions(-) create mode 100644 graphics/glfw/src/main/java/de/staropensource/sosengine/graphics/glfw/classes/GlfwWindow.java delete mode 100644 graphics/glfw/src/main/java/de/staropensource/sosengine/graphics/glfw/classes/Window.java rename graphics/opengl/src/main/java/de/staropensource/sosengine/graphics/opengl/classes/{Window.java => OpenGlWindow.java} (66%) diff --git a/graphics/glfw/src/main/java/de/staropensource/sosengine/graphics/glfw/GlfwSubsystem.java b/graphics/glfw/src/main/java/de/staropensource/sosengine/graphics/glfw/GlfwSubsystem.java index ea633f7..66a0266 100644 --- a/graphics/glfw/src/main/java/de/staropensource/sosengine/graphics/glfw/GlfwSubsystem.java +++ b/graphics/glfw/src/main/java/de/staropensource/sosengine/graphics/glfw/GlfwSubsystem.java @@ -130,7 +130,6 @@ public class GlfwSubsystem implements SubsystemMainClass { glfwSetErrorCallback(null).free(); } - /** * Called when the engine shuts down. * 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 new file mode 100644 index 0000000..1e8672d --- /dev/null +++ b/graphics/glfw/src/main/java/de/staropensource/sosengine/graphics/glfw/classes/GlfwWindow.java @@ -0,0 +1,359 @@ +/* + * 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.exceptions.UnexpectedThrowableException; +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.Window; +import de.staropensource.sosengine.graphics.events.GraphicsApiErrorEvent; +import de.staropensource.sosengine.graphics.glfw.exceptions.NotOnMainThreadException; +import de.staropensource.sosengine.graphics.glfw.exceptions.WindowCreationFailureException; +import de.staropensource.sosengine.graphics.types.VsyncMode; +import de.staropensource.sosengine.graphics.types.WindowMode; +import lombok.Getter; +import org.jetbrains.annotations.NotNull; +import org.lwjgl.system.MemoryUtil; + +import static org.lwjgl.glfw.GLFW.*; + +/** + * A window on your screen. + * + * @since v1-alpha0 + */ +@Getter +@SuppressWarnings({ "unused", "JavadocDeclaration", "JavadocBlankLines" }) +public abstract class GlfwWindow extends Window { + /** + * Contains the {@link #identifier} as a long. + * + * @since v1-alpha2 + * + * -- GETTER -- + * Returns the window identifier as a long. + * + * @return window identifier as a long + * @since v1-alpha2 + */ + private long identifierLong; + + /** + * Creates a new window. + * + * @param name name + * @param title title + * @param size size + * @param minimumSize minimum size + * @param maximumSize maximum size + * @param position position + * @param windowMode window mode + * @param vsyncMode V-Sync mode + * @param resizable resizable flag + * @param borderless borderless flag + * @param focusable focusable flag + * @param onTop on top flag + * @param transparent transparency flag + * @param rendering rendering flag + * @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, @NotNull VsyncMode vsyncMode, boolean resizable, boolean borderless, boolean focusable, boolean onTop, boolean transparent, boolean rendering) throws UnexpectedThrowableException { + super(name, title, size, minimumSize, maximumSize, position, windowMode, vsyncMode, resizable, borderless, focusable, onTop, transparent, rendering); + } + + /** {@inheritDoc} */ + @Override + protected void initializeWindow() throws Throwable { + // Ensure running on the main thread + if (!Miscellaneous.onMainThread()) + throw new NotOnMainThreadException(); + + createGlfwWindow(); // Create the GLFW window + initializeGlfwWindow(); // Call GLFW window initialization method + } + + /** + * Initializes the GLFW window. + * + * @throws Throwable throwable + * @since v1-alpha2 + */ + protected abstract void initializeGlfwWindow() throws Throwable; + + /** + * Updates the window state. + * + * @since v1-alpha2 + */ + @Override + public void updateState() { + // Ensure running on the main thread + if (!Miscellaneous.onMainThread()) + throw new NotOnMainThreadException(); + + // Own context + ownContext(); + + // Set swap interval based on isDisallowTearing setting + glfwSwapInterval(Miscellaneous.getIntegerizedBoolean(GraphicsSubsystemConfiguration.getInstance().isDisallowTearing())); + + // Integer arrays, used for 'size' and 'position' + int[] width = new int[0]; + int[] height = new int[0]; + + // Set window size + glfwGetWindowSize(identifierLong, width, height); + super.setSize(new Vec2i(width[0], height[0])); + + // Set window position + glfwGetWindowPos(identifierLong, width, height); + super.setPosition(new Vec2i(width[0], height[0])); + + // Set 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); + + // Set booleans + super.setResizable(Miscellaneous.getBooleanizedInteger(glfwGetWindowAttrib(identifierLong, GLFW_RESIZABLE))); + super.setOnTop(Miscellaneous.getBooleanizedInteger(glfwGetWindowAttrib(identifierLong, GLFW_FLOATING))); + super.setTransparent(Miscellaneous.getBooleanizedInteger(glfwGetWindowAttrib(identifierLong, GLFW_TRANSPARENT_FRAMEBUFFER))); + + // Make Graphics API update it's state + updateGlfwState(); + } + + /** + * Updates the state of the GLFW window. + * + * @throws Throwable throwable + * @since v1-alpha2 + */ + protected abstract void updateGlfwState(); + + /** {@inheritDoc} */ + @Override + public void render() throws NotOnMainThreadException { + // Ensure running on the main thread + if (!Miscellaneous.onMainThread()) + throw new NotOnMainThreadException(); + + glfwSwapBuffers(identifierLong); + glfwPollEvents(); + } + + /** {@inheritDoc} */ + @Override + public boolean isClosureRequested() { + return glfwWindowShouldClose(identifierLong); + } + + /** {@inheritDoc} */ + @Override + public boolean isFocused() { + return Tristate.toBoolean(Miscellaneous.getTristatedInteger(glfwGetWindowAttrib(identifierLong, GLFW_FOCUSED))); + } + + /** {@inheritDoc} */ + public void focus() { + glfwFocusWindow(identifierLong); + } + + /** {@inheritDoc} */ + public void requestAttention() { + glfwRequestWindowAttention(identifierLong); + } + + /** + * Updates the OpenGL context. + * + * @since v1-alpha2 + */ + public void ownContext() { + glfwMakeContextCurrent(identifierLong); + } + + /** + * (Re-)Creates the GLFW window. + * + * @since v1-alpha2 + */ + public void createGlfwWindow() throws WindowCreationFailureException { + // Get current focus + boolean focused = true; + + // Destroy existing window + if (getIdentifier() != null) { + focused = isFocused(); + glfwDestroyWindow(identifierLong); + } + + // Set window hints + setWindowHints(); + glfwWindowHint(GLFW_POSITION_X, getPosition().getX()); + glfwWindowHint(GLFW_POSITION_Y, getPosition().getY()); + glfwWindowHint(GLFW_CENTER_CURSOR, 0); + glfwWindowHint(GLFW_FOCUSED, Miscellaneous.getIntegerizedBoolean(focused)); + glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, Miscellaneous.getIntegerizedBoolean(isTransparent())); + glfwWindowHint(GLFW_COCOA_GRAPHICS_SWITCHING, Miscellaneous.getIntegerizedBoolean(GraphicsSubsystemConfiguration.getInstance().isDisallowIntegratedGraphics())); + glfwWindowHintString(GLFW_WAYLAND_APP_ID, getName()); + glfwWindowHintString(GLFW_X11_CLASS_NAME, getName()); + glfwWindowHintString(GLFW_X11_INSTANCE_NAME, getName()); + + // Create window + long identifier = glfwCreateWindow(getSize().getX(), getSize().getY(), getTitle(), MemoryUtil.NULL, MemoryUtil.NULL); + if (identifier == MemoryUtil.NULL) { + new GraphicsApiErrorEvent().callEvent("Unable to create window: Identifier is null"); + throw new WindowCreationFailureException(); + } + + // Set identifier + identifierLong = identifier; + setIdentifier(String.valueOf(identifier)); + + // Update the window state + setTitle(getTitle()); + setSize(getSize()); + setMinimumSize(getMinimumSize()); + setMaximumSize(getMaximumSize()); + setPosition(getPosition()); + setWindowMode(getWindowMode()); + } + + /** + * Sets window hints. + * + * @since v1-alpha2 + */ + public abstract void setWindowHints(); + + /** {@inheritDoc} */ + @Override + public void setName(@NotNull String name) { + super.setName(name); + createGlfwWindow(); + } + + /** {@inheritDoc} */ + @Override + public void setTitle(@NotNull String title) { + super.setTitle(title); + glfwSetWindowTitle(identifierLong, title); + } + + /** {@inheritDoc} */ + @Override + public void setSize(@NotNull Vec2i size) { + super.setSize(size); + glfwSetWindowSize(identifierLong, size.getX(), size.getY()); + } + + /** {@inheritDoc} */ + @Override + public void setMinimumSize(@NotNull Vec2i minimumSize) { + super.setMinimumSize(minimumSize); + glfwSetWindowSizeLimits(identifierLong, minimumSize.getX(), minimumSize.getY(), getMaximumSize().getX(), getMaximumSize().getY()); + } + + /** {@inheritDoc} */ + @Override + public void setMaximumSize(@NotNull Vec2i maximumSize) { + super.setMaximumSize(maximumSize); + glfwSetWindowSizeLimits(identifierLong, getMinimumSize().getX(), getMinimumSize().getY(), maximumSize.getX(), maximumSize.getY()); + } + + /** {@inheritDoc} */ + @Override + public void setPosition(@NotNull Vec2i position) { + super.setPosition(position); + glfwSetWindowSize(identifierLong, position.getX(), position.getY()); + } + + /** {@inheritDoc} */ + @Override + public void setWindowMode(@NotNull WindowMode windowMode) { + super.setWindowMode(windowMode); + switch (windowMode) { + case HIDDEN -> glfwHideWindow(identifierLong); + case WINDOWED -> { + glfwShowWindow(identifierLong); + glfwRestoreWindow(identifierLong); + } + case MINIMIZED -> { + glfwShowWindow(identifierLong); + glfwIconifyWindow(identifierLong); + } + case MAXIMIZED -> { + glfwShowWindow(identifierLong); + glfwRestoreWindow(identifierLong); + glfwMaximizeWindow(identifierLong); + } + case BORDERLESS_FULLSCREEN -> { + glfwShowWindow(identifierLong); + glfwRestoreWindow(identifierLong); + // TODO + } + case EXCLUSIVE_FULLSCREEN -> { + glfwShowWindow(identifierLong); + glfwRestoreWindow(identifierLong); + // TODO + } + } + } + + /** {@inheritDoc} */ + @Override + public void setResizable(boolean resizable) { + super.setResizable(resizable); + } + + /** {@inheritDoc} */ + @Override + public void setBorderless(boolean borderless) { + super.setBorderless(borderless); + } + + /** {@inheritDoc} */ + @Override + public void setFocusable(boolean focusable) { + super.setFocusable(focusable); + } + + /** {@inheritDoc} */ + @Override + public void setOnTop(boolean onTop) { + super.setOnTop(onTop); + } + + /** {@inheritDoc} */ + @Override + public void setTransparent(boolean transparent) { + super.setTransparent(transparent); + createGlfwWindow(); + } +} diff --git a/graphics/glfw/src/main/java/de/staropensource/sosengine/graphics/glfw/classes/Window.java b/graphics/glfw/src/main/java/de/staropensource/sosengine/graphics/glfw/classes/Window.java deleted file mode 100644 index cf52b94..0000000 --- a/graphics/glfw/src/main/java/de/staropensource/sosengine/graphics/glfw/classes/Window.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * 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.exceptions.UnexpectedThrowableException; -import de.staropensource.sosengine.base.types.vectors.Vec2i; -import de.staropensource.sosengine.base.utility.Miscellaneous; -import de.staropensource.sosengine.graphics.events.GraphicsApiErrorEvent; -import de.staropensource.sosengine.graphics.glfw.exceptions.NotOnMainThreadException; -import de.staropensource.sosengine.graphics.glfw.exceptions.WindowCreationFailureException; -import de.staropensource.sosengine.graphics.types.VsyncMode; -import de.staropensource.sosengine.graphics.types.WindowMode; -import org.jetbrains.annotations.NotNull; -import org.lwjgl.system.MemoryUtil; - -import static org.lwjgl.glfw.GLFW.*; - -/** - * A window on your screen. - * - * @since v1-alpha0 - */ -@SuppressWarnings({ "unused" }) -public abstract class Window extends de.staropensource.sosengine.graphics.classes.Window { - /** - * Creates a new window. - * - * @param title title - * @param size size - * @param position position - * @param windowMode window mode - * @param vsyncMode V-Sync mode - * @param resizable resizable flag - * @param borderless borderless flag - * @param focusable focusable flag - * @param onTop on top flag - * @param transparent transparency flag - * @param rendering rendering flag - * @throws UnexpectedThrowableException stuff thrown by the {@link #initializeWindow()} of the Graphics API - * @since v1-alpha2 - */ - public Window(@NotNull String title, @NotNull Vec2i size, @NotNull Vec2i position, @NotNull WindowMode windowMode, @NotNull VsyncMode vsyncMode, boolean resizable, boolean borderless, boolean focusable, boolean onTop, boolean transparent, boolean rendering) throws UnexpectedThrowableException { - super(title, size, position, windowMode, vsyncMode, resizable, borderless, focusable, onTop, transparent, rendering); - } - - /** {@inheritDoc} */ - @Override - protected void initializeWindow() throws Throwable { - // Ensure running on the main thread - if (!Miscellaneous.onMainThread()) - throw new NotOnMainThreadException(); - - // Create window - long identifier = glfwCreateWindow(getSize().getX(), getSize().getY(), getTitle(), MemoryUtil.NULL, MemoryUtil.NULL); - if (identifier == MemoryUtil.NULL) { - new GraphicsApiErrorEvent().callEvent("Unable to create window: Identifier is null"); - throw new WindowCreationFailureException(); - } - - // Set identifier - setIdentifier(String.valueOf(identifier)); - - // Call GLFW window initialization method - initializeGlfwWindow(); - } - - /** - * Initializes the GLFW window. - * - * @throws Throwable throwable - * @since v1-alpha2 - */ - protected abstract void initializeGlfwWindow() throws Throwable; - - /** {@inheritDoc} */ - @Override - public void updateState() throws Throwable { - // Ensure running on the main thread - if (!Miscellaneous.onMainThread()) - throw new NotOnMainThreadException(); - - ownContext(getIdentifierAsLong()); - - // Update window visibility - if (getWindowMode() == WindowMode.HIDDEN) - glfwHideWindow(getIdentifierAsLong()); - else - glfwShowWindow(getIdentifierAsLong()); - - updateGlfwState(); - } - - /** - * Updates the state of the GLFW window. - * - * @throws Throwable throwable - * @since v1-alpha2 - */ - protected abstract void updateGlfwState() throws Throwable; - - /** {@inheritDoc} */ - @Override - public void render() throws NotOnMainThreadException { - // Ensure running on the main thread - if (!Miscellaneous.onMainThread()) - throw new NotOnMainThreadException(); - - glfwSwapBuffers(getIdentifierAsLong()); - glfwPollEvents(); - } - - /** {@inheritDoc} */ - @Override - public boolean isClosureRequested() { - return glfwWindowShouldClose(getIdentifierAsLong()); - } - - /** - * Returns the window identifier as a long. - * - * @return window identifier as a long - * @since v1-alpha2 - */ - public long getIdentifierAsLong() { - return Long.parseLong(getIdentifier()); - } - - /** - * Updates the OpenGL context. - * - * @param identifier window to own the context of - * @since v1-alpha2 - */ - public void ownContext(long identifier) { - glfwMakeContextCurrent(identifier); - } -} 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 233d128..a0dc4b6 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 @@ -21,6 +21,7 @@ package de.staropensource.sosengine.graphics.opengl; import de.staropensource.sosengine.graphics.classes.ApiInternalClass; import de.staropensource.sosengine.graphics.classes.Window; +import de.staropensource.sosengine.graphics.opengl.classes.OpenGlWindow; import org.jetbrains.annotations.NotNull; public class OpenGlInternalApi implements ApiInternalClass { @@ -28,6 +29,6 @@ public class OpenGlInternalApi implements ApiInternalClass { @Override @NotNull public Class getWindowClass() { - return de.staropensource.sosengine.graphics.opengl.classes.Window.class; + return OpenGlWindow.class; } } diff --git a/graphics/opengl/src/main/java/de/staropensource/sosengine/graphics/opengl/classes/Window.java b/graphics/opengl/src/main/java/de/staropensource/sosengine/graphics/opengl/classes/OpenGlWindow.java similarity index 66% rename from graphics/opengl/src/main/java/de/staropensource/sosengine/graphics/opengl/classes/Window.java rename to graphics/opengl/src/main/java/de/staropensource/sosengine/graphics/opengl/classes/OpenGlWindow.java index 27a7de5..26d926c 100644 --- a/graphics/opengl/src/main/java/de/staropensource/sosengine/graphics/opengl/classes/Window.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.glfw.classes.GlfwWindow; import de.staropensource.sosengine.graphics.glfw.exceptions.NotOnMainThreadException; import de.staropensource.sosengine.graphics.glfw.exceptions.WindowCreationFailureException; import de.staropensource.sosengine.graphics.types.VsyncMode; @@ -28,18 +29,23 @@ import de.staropensource.sosengine.graphics.types.WindowMode; import org.jetbrains.annotations.NotNull; import org.lwjgl.opengl.GL; +import static org.lwjgl.glfw.GLFW.*; + /** * A window on your screen. * * @since v1-alpha0 */ @SuppressWarnings({ "unused" }) -public class Window extends de.staropensource.sosengine.graphics.glfw.classes.Window { +public class OpenGlWindow extends GlfwWindow { /** * Creates a new window. * + * @param name name * @param title title * @param size size + * @param minimumSize minimum size + * @param maximumSize maximum size * @param position position * @param windowMode window mode * @param vsyncMode V-Sync mode @@ -49,17 +55,17 @@ public class Window extends de.staropensource.sosengine.graphics.glfw.classes.Wi * @param onTop on top flag * @param transparent transparency flag * @param rendering rendering flag - * @throws UnexpectedThrowableException stuff thrown by the {@link #initializeWindow()} of the Graphics API + * @throws UnexpectedThrowableException stuff thrown by the {@link #initializeWindow()} and {@link #render()} methods of the implementing Graphics API * @since v1-alpha2 */ - public Window(@NotNull String title, @NotNull Vec2i size, @NotNull Vec2i position, @NotNull WindowMode windowMode, @NotNull VsyncMode vsyncMode, boolean resizable, boolean borderless, boolean focusable, boolean onTop, boolean transparent, boolean rendering) throws UnexpectedThrowableException { - super(title, size, position, windowMode, vsyncMode, 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 VsyncMode vsyncMode, boolean resizable, boolean borderless, boolean focusable, boolean onTop, boolean transparent, boolean rendering) throws UnexpectedThrowableException { + super(name, title, size, minimumSize, maximumSize, position, windowMode, vsyncMode, resizable, borderless, focusable, onTop, transparent, rendering); } /** {@inheritDoc} */ @Override public void initializeGlfwWindow() throws WindowCreationFailureException, NotOnMainThreadException { - ownContext(getIdentifierAsLong()); // Own context + ownContext(); // Own the context GL.createCapabilities(); // Create OpenGL capabilities } @@ -67,6 +73,16 @@ public class Window extends de.staropensource.sosengine.graphics.glfw.classes.Wi @Override public void updateGlfwState() throws NotOnMainThreadException {} + /** {@inheritDoc} */ + @Override + public void setWindowHints() { + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API); + glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API); + } + /** {@inheritDoc} */ @NotNull @Override diff --git a/graphics/src/main/java/de/staropensource/sosengine/graphics/GraphicsSubsystemConfiguration.java b/graphics/src/main/java/de/staropensource/sosengine/graphics/GraphicsSubsystemConfiguration.java index 4b864a3..f1dc30b 100644 --- a/graphics/src/main/java/de/staropensource/sosengine/graphics/GraphicsSubsystemConfiguration.java +++ b/graphics/src/main/java/de/staropensource/sosengine/graphics/GraphicsSubsystemConfiguration.java @@ -98,6 +98,36 @@ public final class GraphicsSubsystemConfiguration implements SubsystemConfigurat */ private boolean errorGraphicsError; + /** + * If enabled, will make the Graphics API try to prevent tearing from happening. + * + * @since v1-alph2 + * + * -- GETTER -- + * Gets the value for {@link #disallowTearing}. + * + * @return variable value + * @see GraphicsSubsystemConfiguration#disallowTearing + * @since v1-alpha2 + */ + private boolean disallowTearing; + + /** + * If enabled, will make the Graphics API try to prevent using the integrated graphics card in your computer. + *

+ * Will have no effect if no integrated or discrete graphics card is installed in the system. + * + * @since v1-alph2 + * + * -- GETTER -- + * Gets the value for {@link #disallowIntegratedGraphics}. + * + * @return variable value + * @see GraphicsSubsystemConfiguration#disallowIntegratedGraphics + * @since v1-alpha2 + */ + private boolean disallowIntegratedGraphics; + /** * Constructs this class. * @@ -132,6 +162,8 @@ public final class GraphicsSubsystemConfiguration implements SubsystemConfigurat case "debug" -> debug = parser.getBoolean(group + property); case "errorGraphicsError" -> errorGraphicsError = parser.getBoolean(group + property); + + case "disallowTearing" -> disallowTearing = parser.getBoolean(group + property); } } catch (NullPointerException ignored) {} } @@ -150,6 +182,8 @@ public final class GraphicsSubsystemConfiguration implements SubsystemConfigurat debug = false; errorGraphicsError = true; + + disallowTearing = false; } /** {@inheritDoc} */ @@ -162,6 +196,9 @@ public final class GraphicsSubsystemConfiguration implements SubsystemConfigurat case "errorGraphicsError" -> { return errorGraphicsError; } + case "disallowTearing" -> { + return disallowTearing; + } default -> { return null; } 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 0903a68..5db986d 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 @@ -48,6 +48,7 @@ import java.util.Set; * * @since v1-alpha0 */ +// TODO monitors @Getter @SuppressWarnings({ "unused", "JavadocDeclaration", "JavadocBlankLines" }) public abstract class Window { @@ -97,6 +98,69 @@ public abstract class Window { @Setter(AccessLevel.PROTECTED) private String identifier = null; + /** + * Determines the name of this window. + *

+ * Window names should: + *

    + *
  • be lowercase,
  • + *
  • be simple,
  • + *
  • be not very long,
  • + *
  • only contain letters, numbers, hyphens and dots, and
  • + *
  • represent the name of your application and window purpose (if your application supports multiple windows)
  • + *
+ *

+ * On some platforms this may be used for window identification. + * A prime example of this is X11 and Wayland, where window + * managers and compositors can use this information to identify + * windows and customize them. + * + * @since v1-alpha1 + * + * -- GETTER -- + * Returns the name of this window. + *

+ * Window names should: + *

    + *
  • be lowercase,
  • + *
  • be simple,
  • + *
  • be not very long,
  • + *
  • only contain letters, numbers, hyphens and dots, and
  • + *
  • represent the name of your application and window purpose (if your application supports multiple windows)
  • + *
+ *

+ * On some platforms this may be used for window identification. + * A prime example of this is X11 and Wayland, where window + * managers and compositors can use this information to identify + * windows and customize them. + * + * @return window title + * @since v1-alpha2 + * + * -- SETTER -- + * Sets the name of this window. + *

+ * Window names should: + *

    + *
  • be lowercase,
  • + *
  • be simple,
  • + *
  • be not very long,
  • + *
  • only contain letters, numbers, hyphens and dots, and
  • + *
  • represent the name of your application and window purpose (if your application supports multiple windows)
  • + *
+ *

+ * On some platforms this may be used for window identification. + * A prime example of this is X11 and Wayland, where window + * managers and compositors can use this information to identify + * windows and customize them. + * + * @param name new window name + * @since v1-alpha2 + */ + @NotNull + @Setter + private String name; + /** * Determines the title of this window. * @@ -139,6 +203,48 @@ public abstract class Window { @Setter private Vec2i size; + /** + * Determines the minimum size of this window. + * + * @since v1-alpha1 + * + * -- GETTER -- + * Returns the minimum window size. + * + * @return minimum window size + * @since v1-alpha2 + * + * -- SETTER -- + * Sets the minimum window size. + * + * @param size new minimum window size + * @since v1-alpha2 + */ + @NotNull + @Setter + private Vec2i minimumSize; + + /** + * Determines the maximum size of this window. + * + * @since v1-alpha1 + * + * -- GETTER -- + * Returns the maximum window size. + * + * @return maximum window size + * @since v1-alpha2 + * + * -- SETTER -- + * Sets the maximum window size. + * + * @param size new maximum window size + * @since v1-alpha2 + */ + @NotNull + @Setter + private Vec2i maximumSize; + /** * Determines the position of this window. * @@ -202,6 +308,26 @@ public abstract class Window { @Setter private VsyncMode vsyncMode; + /** + * Determines how fast the window may update it's contents. + * + * @since v1-alpha1 + * + * -- GETTER -- + * Returns how fast the window may update it's contents. + * + * @return new window frame limit + * @since v1-alpha2 + * + * -- SETTER -- + * Sets how fast the window may update it's contents. + * + * @param framerate new window frame limit + * @since v1-alpha2 + */ + @Setter + private int framerate; + /** * Determines if this window can be resized by the user. * @@ -343,8 +469,11 @@ public abstract class Window { /** * Creates a new window. * + * @param name name * @param title title * @param size size + * @param minimumSize minimum size + * @param maximumSize maximum size * @param position position * @param windowMode window mode * @param vsyncMode V-Sync mode @@ -354,15 +483,18 @@ public abstract class Window { * @param onTop on top flag * @param transparent transparency flag * @param rendering rendering flag - * @throws UnexpectedThrowableException stuff thrown by the {@link #initializeWindow()}, {@link #updateState()} and {@link #render()} methods of the implementing Graphics API + * @throws UnexpectedThrowableException stuff thrown by the {@link #initializeWindow()} and {@link #render()} methods of the implementing Graphics API * @since v1-alpha2 */ - public Window(@NotNull String title, @NotNull Vec2i size, @NotNull Vec2i position, @NotNull WindowMode windowMode, @NotNull VsyncMode vsyncMode, boolean resizable, boolean borderless, boolean focusable, boolean onTop, boolean transparent, boolean rendering) throws UnexpectedThrowableException { + public Window(@NotNull String name, @NotNull String title, @NotNull Vec2i size, @NotNull Vec2i minimumSize, @NotNull Vec2i maximumSize, @NotNull Vec2i position, @NotNull WindowMode windowMode, @NotNull VsyncMode vsyncMode, boolean resizable, boolean borderless, boolean focusable, boolean onTop, boolean transparent, boolean rendering) throws UnexpectedThrowableException { logger.diag("Creating new window with properties: title=\"" + title + "\" size=" + size + " position=" + position + " windowMode=" + windowMode + " vsyncMode=" + vsyncMode + " resizable=" + resizable + " borderless=" + borderless + " focusable=" + focusable + " onTop=" + onTop + " transparent=" + transparent + " rendering=" + rendering); // Initialize variables + this.name = name; this.title = title; this.size = size; + this.minimumSize = minimumSize; + this.maximumSize = maximumSize; this.position = position; this.windowMode = windowMode; this.vsyncMode = vsyncMode; @@ -442,6 +574,34 @@ public abstract class Window { */ public abstract boolean isClosureRequested(); + /** + * Returns if the window is currently focused. + * + * @return {@code true} if focused, {@code false} otherwise + * @since v1-alpha2 + */ + public abstract boolean isFocused(); + + /** + * Will cause the window to be focused immediately, even + * without any user input. + * + * @since v1-alpha2 + */ + public abstract void focus(); + + /** + * Will request user attention. + *

+ * What the window manager or compositor does + * with this request is uncertain. It may be + * ignored, or will cause the icon in some bar + * or dock flash or blink. + * + * @since v1-alpha2 + */ + public abstract void requestAttention(); + /** * Provides an API for building {@link Window} classes more easily. * @@ -450,6 +610,22 @@ public abstract class Window { @SuppressWarnings({ "unused", "JavadocDeclaration", "JavadocBlankLines" }) @Getter public static class Builder { + /** + * Contains the window name. + * + * @see Window#name + * @since v1-alpha2 + * + * -- GETTER -- + * Returns the window name. + * + * @return window name + * @see Window#name + * @since v1-alpha2 + */ + @Nullable + private String name = null; + /** * Contains the window title. * @@ -482,6 +658,38 @@ public abstract class Window { @Nullable private Vec2i size = null; + /** + * Contains the minimum window size. + * + * @see Window#minimumSize + * @since v1-alpha2 + * + * -- GETTER -- + * Returns the minimum window size. + * + * @return minimum window size + * @see Window#minimumSize + * @since v1-alpha2 + */ + @Nullable + private Vec2i minimumSize = null; + + /** + * Contains the maximum window size. + * + * @see Window#maximumSize + * @since v1-alpha2 + * + * -- GETTER -- + * Returns the maximum window size. + * + * @return maximum window size + * @see Window#maximumSize + * @since v1-alpha2 + */ + @Nullable + private Vec2i maximumSize = null; + /** * Contains the window position. * @@ -650,14 +858,20 @@ public abstract class Window { boolean renderingBoolean = true; // Check for required fields - if (title == null) + if (name == null) throw new IllegalStateException("The window name is unset"); + if (title == null) + throw new IllegalStateException("The window title is unset"); if (size == null) throw new IllegalStateException("The window size is unset"); if (position == null) throw new IllegalStateException("The window position is unset"); - // Set default + // Set defaults + if (minimumSize == null) + minimumSize = new Vec2i(0, 0); + if (maximumSize == null) + maximumSize = new Vec2i(0, 0); if (windowMode == null) windowMode = WindowMode.WINDOWED; if (vsyncMode == null) @@ -680,13 +894,26 @@ public abstract class Window { // Create new Window instance try { return GraphicsSubsystem.getInstance().getApi().getInternalApi().getWindowClass() - .getDeclaredConstructor(String.class, Vec2i.class, Vec2i.class, WindowMode.class, VsyncMode.class, Boolean.TYPE, Boolean.TYPE, Boolean.TYPE, Boolean.TYPE, Boolean.TYPE, Boolean.TYPE) - .newInstance(title, size, position, windowMode, vsyncMode, resizableBoolean, borderlessBoolean, focusableBoolean, onTopBoolean, transparentBoolean, renderingBoolean); + .getDeclaredConstructor(String.class, String.class, Vec2i.class, Vec2i.class, Vec2i.class, Vec2i.class, WindowMode.class, VsyncMode.class, Boolean.TYPE, Boolean.TYPE, Boolean.TYPE, Boolean.TYPE, Boolean.TYPE, Boolean.TYPE) + .newInstance(name, title, size, minimumSize, maximumSize, position, windowMode, vsyncMode, resizableBoolean, borderlessBoolean, focusableBoolean, onTopBoolean, transparentBoolean, renderingBoolean); } catch (Throwable throwable) { throw new UnexpectedThrowableException(throwable, "Window.Builder was unable to create new Window instance"); } } + /** + * Sets the window name. + * + * @param name new window name + * @return builder instance + * @since v1-alpha2 + */ + @NotNull + public synchronized Builder setName(@Nullable String name) { + this.name = name; + return this; + } + /** * Sets the window title. * @@ -713,6 +940,32 @@ public abstract class Window { return this; } + /** + * Sets the minimum window size. + * + * @param minimumSize new minimum window size + * @return builder instance + * @since v1-alpha2 + */ + @NotNull + public synchronized Builder setMinimumSize(@Nullable Vec2i minimumSize) { + this.minimumSize = minimumSize; + return this; + } + + /** + * Sets the maximum window size. + * + * @param maximumSize new maximum window size + * @return builder instance + * @since v1-alpha2 + */ + @NotNull + public synchronized Builder setMaximumSize(@Nullable Vec2i maximumSize) { + this.maximumSize = maximumSize; + return this; + } + /** * Sets the window position. * diff --git a/graphics/src/main/java/de/staropensource/sosengine/graphics/types/WindowMode.java b/graphics/src/main/java/de/staropensource/sosengine/graphics/types/WindowMode.java index 08c6af1..267a436 100644 --- a/graphics/src/main/java/de/staropensource/sosengine/graphics/types/WindowMode.java +++ b/graphics/src/main/java/de/staropensource/sosengine/graphics/types/WindowMode.java @@ -27,22 +27,40 @@ package de.staropensource.sosengine.graphics.types; @SuppressWarnings({ "unused" }) public enum WindowMode { /** - * Makes the window invisible and unable to be interacted with. + * Marks the window as {@code hidden}, making the window invisible and unable to be interacted with. * * @since v1-alpha2 */ HIDDEN, /** - * Makes the window able to be dragged around. + * Marks the window as {@code windowed}, which + * will allow the user to drag around the window freely. * * @since v1-alpha1 */ WINDOWED, /** - * Same as {@code WINDOWED} mode, but the window will have - * the same size as the monitor it is currently on. + * Same as {@link #HIDDEN} mode, but the window can + * be summoned back into {@link #WINDOWED} mode by the user. + * + * @since v1-alpha2 + */ + MINIMIZED, + + /** + * Same as {@link #WINDOWED}, but will make the window occupy + * most of the screen space, except for window manager/compositor + * windows/bars/docks. + * + * @since v1-alpha2 + */ + MAXIMIZED, + + /** + * Makes the window will have the same + * size as the monitor it is currently on. * * @since v1-alpha1 */ @@ -51,6 +69,10 @@ public enum WindowMode { /** * Makes the window occupy the entire monitor it is currently on * without allowing other windows to occupy the same space. + *

+ * This will increase rendering throughput as the window manager + * or compositor does not need to care about other windows occupying + * the same monitor. * * @since v1-alpha1 */ diff --git a/testapp/src/main/java/de/staropensource/sosengine/testapp/Main.java b/testapp/src/main/java/de/staropensource/sosengine/testapp/Main.java index a01f09f..11f7957 100644 --- a/testapp/src/main/java/de/staropensource/sosengine/testapp/Main.java +++ b/testapp/src/main/java/de/staropensource/sosengine/testapp/Main.java @@ -114,6 +114,7 @@ public class Main { // Create window try { Window window = new Window.Builder() + .setName("sosengine-testapp") .setTitle("test application window") .setSize(new Vec2i(960, 540)) .setPosition(new Vec2i(10, 10))