From b1a56ea6a4d17493474d64bedbde79c623851d42 Mon Sep 17 00:00:00 2001 From: JeremyStarTM Date: Sun, 21 Jul 2024 16:45:46 +0200 Subject: [PATCH] Update Window class heavily --- .../graphics/opengl/classes/Window.java | 176 ++-- .../exceptions/NotOnMainThreadException.java | 27 + .../WindowCreationFailureException.java | 47 ++ .../opengl/src/main/java/module-info.java | 2 + .../sosengine/graphics/classes/Window.java | 767 +++++++++++++++++- .../sosengine/testapp/Main.java | 11 + 6 files changed, 938 insertions(+), 92 deletions(-) create mode 100644 graphics/opengl/src/main/java/de/staropensource/sosengine/graphics/opengl/exceptions/NotOnMainThreadException.java create mode 100644 graphics/opengl/src/main/java/de/staropensource/sosengine/graphics/opengl/exceptions/WindowCreationFailureException.java 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/Window.java index f0ff7a0..0d39d52 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/Window.java @@ -19,98 +19,128 @@ package de.staropensource.sosengine.graphics.opengl.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.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 lombok.Getter; +import de.staropensource.sosengine.graphics.opengl.exceptions.NotOnMainThreadException; +import de.staropensource.sosengine.graphics.opengl.exceptions.WindowCreationFailureException; +import de.staropensource.sosengine.graphics.types.VsyncMode; +import de.staropensource.sosengine.graphics.types.WindowMode; import org.jetbrains.annotations.NotNull; import org.lwjgl.opengl.GL; - -import java.util.HashSet; -import java.util.Set; +import org.lwjgl.system.MemoryUtil; import static org.lwjgl.glfw.GLFW.*; -import static org.lwjgl.system.MemoryUtil.NULL; /** * A window on your screen. * * @since v1-alpha0 */ -@SuppressWarnings({ "unused", "JavadocDeclaration", "JavadocBlankLines" }) -public class Window implements de.staropensource.sosengine.graphics.classes.Window { - /** - * A set of all active windows. - * - * @since v1-alpha0 - * - * -- GETTER -- - * Returns a set of all active windows. - * - * @return set of all windows - * @since v1-alpha0 - */ - @Getter - public static Set<@NotNull Window> windows = new HashSet<>(); - - /** - * Logger instance. - * - * @see LoggerInstance - * @since v1-alpha0 - */ - private final LoggerInstance logger = new LoggerInstance(new LogIssuer(getClass(), CodePart.ENGINE)); - - /** - * The window name. - * - * @since v1-alpha0 - * - * -- GETTER -- - * Returns the window name. - * - * @return window name - * @since v1-alpha0 - */ - @Getter - private String windowName; - - /** - * The window size. - * - * @since v1-alpha0 - * -- GETTER -- - * Returns the window size. - * - * @return window size - * @since v1-alpha0 - */ - @Getter - private Vec2i windowSize; - +@SuppressWarnings({ "unused" }) +public class Window extends de.staropensource.sosengine.graphics.classes.Window { /** * Creates a new window. * - * @param title window title - * @param size window size + * @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(String title, Vec2i size) { - logger.diag("Creating new Window with title \"" + title + "\""); + 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); + } - windows.add(this); - windowName = title; - windowSize = size; + /** {@inheritDoc} */ + @Override + public void initializeWindow() throws WindowCreationFailureException, NotOnMainThreadException { + // Ensure running on the main thread + if (!Miscellaneous.onMainThread()) + throw new NotOnMainThreadException(); - long windowId = glfwCreateWindow(windowSize.getX(), windowSize.getY(), windowName, NULL, NULL); - if (windowId == NULL) - new GraphicsApiErrorEvent().callEvent("Unable to create window: ID is null"); + 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 de.staropensource.sosengine.graphics.opengl.exceptions.WindowCreationFailureException(); + } - glfwMakeContextCurrent(windowId); - glfwShowWindow(windowId); - GL.createCapabilities(); - glfwSwapBuffers(windowId); + setIdentifier(String.valueOf(identifier)); + + ownContext(identifier); // Own context + GL.createCapabilities(); // Create OpenGL capabilities + } + + /** {@inheritDoc} */ + @Override + public void updateState() throws NotOnMainThreadException { + // Ensure running on the main thread + if (!Miscellaneous.onMainThread()) + throw new NotOnMainThreadException(); + + long identifier = getIdentifierAsLong(); + ownContext(identifier); + + // Update window visibility + if (getWindowMode() == WindowMode.HIDDEN) + glfwHideWindow(identifier); + else + glfwShowWindow(identifier); + } + + /** {@inheritDoc} */ + @Override + public void render() throws NotOnMainThreadException { + // Ensure running on the main thread + if (!Miscellaneous.onMainThread()) + throw new NotOnMainThreadException(); + + long identifier = getIdentifierAsLong(); + + glfwSwapBuffers(identifier); glfwPollEvents(); } + + /** {@inheritDoc} */ + @NotNull + @Override + public Vec2i getSizeWithDecorations() { + return getSize(); + } + + /** {@inheritDoc} */ + @NotNull + @Override + public Vec2i getPositionWithDecorations() { + return getPosition(); + } + + /** + * Returns the window identifier as a long. + * + * @return window identifier as a long + * @since v1-alpha2 + */ + public long getIdentifierAsLong() { + return Long.getLong(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/exceptions/NotOnMainThreadException.java b/graphics/opengl/src/main/java/de/staropensource/sosengine/graphics/opengl/exceptions/NotOnMainThreadException.java new file mode 100644 index 0000000..938bd52 --- /dev/null +++ b/graphics/opengl/src/main/java/de/staropensource/sosengine/graphics/opengl/exceptions/NotOnMainThreadException.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.opengl.exceptions; + +/** + * Thrown when trying to communicate with the Graphics API over a non-main thread. + * + * @since v1-alpha2 + */ +public class NotOnMainThreadException extends Throwable {} diff --git a/graphics/opengl/src/main/java/de/staropensource/sosengine/graphics/opengl/exceptions/WindowCreationFailureException.java b/graphics/opengl/src/main/java/de/staropensource/sosengine/graphics/opengl/exceptions/WindowCreationFailureException.java new file mode 100644 index 0000000..3fb8f83 --- /dev/null +++ b/graphics/opengl/src/main/java/de/staropensource/sosengine/graphics/opengl/exceptions/WindowCreationFailureException.java @@ -0,0 +1,47 @@ +/* + * 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.exceptions; + +import org.jetbrains.annotations.NotNull; + +/** + * Thrown when a Window cannot be created. + * + * @since v1-alpha2 + */ +@SuppressWarnings({ "unused" }) +public class WindowCreationFailureException extends RuntimeException { + /** + * Constructs this exception. + * + * @since v1-alpha2 + */ + public WindowCreationFailureException() {} + + /** + * Constructs this exception. + * + * @param message error message + * @since v1-alpha2 + */ + public WindowCreationFailureException(@NotNull String message) { + super(message); + } +} diff --git a/graphics/opengl/src/main/java/module-info.java b/graphics/opengl/src/main/java/module-info.java index 58633d1..614bc31 100644 --- a/graphics/opengl/src/main/java/module-info.java +++ b/graphics/opengl/src/main/java/module-info.java @@ -18,10 +18,12 @@ module sosengine.graphics.opengl { // API access exports de.staropensource.sosengine.graphics.opengl; exports de.staropensource.sosengine.graphics.opengl.classes; + exports de.staropensource.sosengine.graphics.opengl.exceptions; exports de.staropensource.sosengine.graphics.opengl.events; // Reflection access opens de.staropensource.sosengine.graphics.opengl; opens de.staropensource.sosengine.graphics.opengl.classes; + opens de.staropensource.sosengine.graphics.opengl.exceptions; opens de.staropensource.sosengine.graphics.opengl.events; } 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 f99187c..5b74171 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 @@ -19,77 +19,806 @@ package de.staropensource.sosengine.graphics.classes; +import de.staropensource.sosengine.base.exceptions.UnexpectedThrowableException; +import de.staropensource.sosengine.base.logging.LoggerInstance; +import de.staropensource.sosengine.base.types.CodePart; +import de.staropensource.sosengine.base.types.Tristate; +import de.staropensource.sosengine.base.types.immutable.ImmutableHashSet; +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.types.VsyncMode; import de.staropensource.sosengine.graphics.types.WindowMode; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.Setter; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.HashSet; import java.util.Set; /** - * Interface for implementing windows. + * Abstract class for implementing windows in a Graphics API. + *

+ * Note that many window properties may be overridden by any + * window manager or compositor. In almost all cases, that won't happen + * though (except for window size & position in tiling wms/compositors) + * except the user asks for that change directly. * * @since v1-alpha0 */ -@SuppressWarnings({ "unused" }) -public interface Window { +@Getter +@SuppressWarnings({ "unused", "JavadocDeclaration", "JavadocBlankLines" }) +public abstract class Window { /** * A set of all active windows. * * @since v1-alpha0 */ @NotNull - Set windows = new HashSet<>(); + private static final Set<@NotNull Window> windows = new HashSet<>(); + + /** + * 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 window identifier. * * @since v1-alpha1 + * + * -- GETTER -- + * Returns the window identifier. + * + * @return window identifier + * @since v1-alpha2 + * + * -- SETTER -- + * Sets the window identifier. + *

+ * Recommended to be called only once. + * + * @param identifier new window identifier + * @since v1-alpha2 */ - @NotNull - String identifier = ""; + @Setter(AccessLevel.PROTECTED) + private String identifier = null; /** * Determines the title of this window. * * @since v1-alpha1 + * + * -- GETTER -- + * Returns the window title. + * + * @return window title + * @since v1-alpha2 + * + * -- SETTER -- + * Sets the window title. + * + * @param title new window title + * @since v1-alpha2 */ @NotNull - String title = "sos!engine window (update this title)"; + @Setter + private String title; /** * Determines the size of this window. * * @since v1-alpha1 + * + * -- GETTER -- + * Returns the window size. + * + * @return window size + * @since v1-alpha2 + * + * -- SETTER -- + * Sets the window size. + * + * @param size new window size + * @since v1-alpha2 */ @NotNull - Vec2i size = new Vec2i(200, 200); + @Setter + private Vec2i size; + + /** + * Determines the position of this window. + * + * @since v1-alpha2 + * + * -- GETTER -- + * Returns the window position. + * + * @return window position + * @since v1-alpha2 + * + * -- SETTER -- + * Sets the window position. + * + * @param position new window position + * @since v1-alpha2 + */ + @NotNull + @Setter + private Vec2i position; /** * Determines in which {@link WindowMode} this window is in. * * @since v1-alpha1 + * + * -- GETTER -- + * Returns the window mode. + * + * @return window mode + * @since v1-alpha2 + * + * -- SETTER -- + * Sets the window mode. + * + * @param windowMode new window mode + * @since v1-alpha2 */ - WindowMode mode = WindowMode.WINDOWED; + @NotNull + @Setter + private WindowMode windowMode; /** - * Determines if this window should have a border and decorations. + * Determines the V-Sync mode this window targets. * - * @since v1-alpha1 - */ - boolean borderless = false; - - /** - * Determines if this window should be displayed on top of all other windows. + * @since v1-alpha2 * - * @since v1-alpha1 + * -- GETTER -- + * Returns the V-Sync mode. + * + * @return V-Sync mode + * @since v1-alpha2 + * + * -- SETTER -- + * Sets the V-Sync mode. + * + * @param vsyncMode new vsync mode + * @since v1-alpha2 */ - boolean onTop = false; + @NotNull + @Setter + private VsyncMode vsyncMode; /** * Determines if this window can be resized by the user. * * @since v1-alpha1 + * + * -- GETTER -- + * Returns if the window is resizable. + * + * @return resizable flag state + * @since v1-alpha2 + * + * -- SETTER -- + * Sets if the window is resizable. + * + * @param resizable new resizable flag state + * @since v1-alpha2 */ - boolean resizable = false; + @Setter + private boolean resizable; + + /** + * Determines if this window should have a border and decorations. + * + * @since v1-alpha1 + * + * -- GETTER -- + * Returns if the window should be rendered without any decorations. + * + * @return borderless flag state + * @since v1-alpha2 + * + * -- SETTER -- + * Sets if the window should be rendered without any decorations. + * + * @param borderless new borderless flag state + * @since v1-alpha2 + */ + @Setter + private boolean borderless; + + /** + * Determines if the window can be focused. + * + * -- GETTER -- + * Returns if the window can be focused. + * + * @return focusable flag state + * @since v1-alpha2 + * + * -- SETTER -- + * Sets if the window can be focused. + * + * @param focusable new focusable flag state + * @since v1-alpha2 + */ + @Setter + private boolean focusable; + + /** + * Determines if this window should be displayed on top of all other windows. + * + * @since v1-alpha1 + * + * -- GETTER -- + * Returns if the window is displayed over regular windows. + * + * @return on top flag state + * @since v1-alpha2 + * + * -- SETTER -- + * Sets if the window is displayed over regular windows. + * + * @param onTop new on top flag state + * @since v1-alpha2 + */ + @Setter + private boolean onTop; + + /** + * Enables or disables transparency support for this window. + *

+ * Availability depends on the Graphics API, compositor or + * window manager and potentially system settings. + * + * @since v1-alpha2 + * + * -- GETTER -- + * Returns if the window can be transparent. + *

+ * Availability depends on the Graphics API, compositor or + * window manager and potentially system settings. + * + * @return transparency flag state + * @since v1-alpha2 + * + * -- SETTER -- + * Sets if the window can be transparent. + *

+ * Availability depends on the Graphics API, compositor or + * window manager and potentially system settings. + * + * @param transparent new transparency flag state + * @since v1-alpha2 + */ + @Setter + private boolean transparent; + + /** + * Determines if this window should be rendered. + * + * @since v1-alpha2 + * + * -- GETTER -- + * Returns if the window should be rendered. + * + * @return rendering flag state + * @since v1-alpha2 + * + * -- SETTER -- + * Sets if the window should be rendered. + * + * @param rendering new rendering flag state + * @since v1-alpha2 + */ + @Setter + private boolean rendering; + + /** + * 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()}, {@link #updateState()} 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 { + 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.title = title; + this.size = size; + this.position = position; + this.windowMode = windowMode; + this.vsyncMode = vsyncMode; + this.resizable = resizable; + this.borderless = borderless; + this.focusable = focusable; + this.onTop = onTop; + this.transparent = transparent; + this.rendering = rendering; + + try { + // Allow Graphics API to initialize window + initializeWindow(); + + // Update state and render first image + updateState(); + render(); + } catch (Throwable throwable) { + throw new UnexpectedThrowableException(throwable); + } + + // Add to window set + windows.add(this); + } + + /** + * Returns a set of active windows. + * + * @return active windows + * @since v1-alpha2 + */ + @NotNull + public static ImmutableHashSet<@NotNull Window> getWindows() { + return new ImmutableHashSet<>(windows); + } + + /** + * Allows the Graphics API to initialize the window. + *

+ * NEVER place any code in the constructor. Instead, write + * API-specific window initialization code in here + * or stuff may break unexpectedly. + * + * @since v1-alpha2 + */ + protected abstract void initializeWindow() throws Throwable; + + /** + * Updates the state of this window. + *

+ * Do not call this method manually or you + * may cause unintended side effects. + */ + public abstract void updateState() throws Throwable; + + /** + * Renders this window. + *

+ * Do not call this method manually or you + * may cause unintended side effects. + */ + public abstract void render() throws Throwable; + + /** + * Returns the window size including decorations (e.g. title bar). + * + * @return window size including decorations + * @since v1-alpha2 + */ + @NotNull + public abstract Vec2i getSizeWithDecorations(); + + /** + * Returns the window position including decorations (e.g. title bar). + * + * @return window position including decorations + * @since v1-alpha2 + */ + @NotNull + public abstract Vec2i getPositionWithDecorations(); + + /** + * Provides an API for building {@link Window} classes more easily. + * + * @since v1-alpha2 + */ + @SuppressWarnings({ "unused", "JavadocDeclaration", "JavadocBlankLines" }) + @Getter + public static class Builder { + /** + * Contains the window title. + * + * @see Window#title + * @since v1-alpha2 + * + * -- GETTER -- + * Returns the window title. + * + * @return window title + * @see Window#title + * @since v1-alpha2 + */ + @Nullable + private String title = null; + + /** + * Contains the window size. + * + * @see Window#size + * @since v1-alpha2 + * + * -- GETTER -- + * Returns the window size. + * + * @return window size + * @see Window#size + * @since v1-alpha2 + */ + @Nullable + private Vec2i size = null; + + /** + * Contains the window position. + * + * @see Window#position + * @since v1-alpha2 + * + * -- GETTER -- + * Returns the window position. + * + * @return window position + * @see Window#position + * @since v1-alpha2 + */ + @Nullable + private Vec2i position = null; + + /** + * Contains the window mode. + * + * @see Window#windowMode + * @since v1-alpha2 + * + * -- GETTER -- + * Returns the window mode. + * + * @return window mode + * @see Window#windowMode + * @since v1-alpha2 + */ + @Nullable + private WindowMode windowMode = null; + + /** + * Contains the V-Sync mode. + * + * @see Window#vsyncMode + * @since v1-alpha2 + * + * -- GETTER -- + * Returns the V-Sync mode. + * + * @return V-Sync mode + * @see Window#vsyncMode + * @since v1-alpha2 + */ + @Nullable + private VsyncMode vsyncMode = null; + + /** + * Contains the resizable flag. + * + * @see Window#resizable + * @since v1-alpha2 + * + * -- GETTER -- + * Returns the resizable flag state. + * + * @return resizable flag state + * @see Window#resizable + * @since v1-alpha2 + */ + @NotNull + private Tristate resizable = Tristate.UNSET; + + /** + * Contains the borderless flag. + * + * @see Window#borderless + * @since v1-alpha2 + * + * -- GETTER -- + * Returns the borderless flag state. + * + * @return borderless flag state + * @see Window#borderless + * @since v1-alpha2 + */ + @NotNull + private Tristate borderless = Tristate.UNSET; + + /** + * Contains the focusable flag. + * + * @see Window#focusable + * @since v1-alpha2 + * + * -- GETTER -- + * Returns the focusable flag state. + * + * @return focusable flag state + * @see Window#focusable + * @since v1-alpha2 + */ + @NotNull + private Tristate focusable = Tristate.UNSET; + + /** + * Contains the on top flag. + * + * @see Window#onTop + * @since v1-alpha2 + * + * -- GETTER -- + * Returns the on top flag state. + * + * @return on top flag state + * @see Window#onTop + * @since v1-alpha2 + */ + @NotNull + private Tristate onTop = Tristate.UNSET; + + /** + * Contains the transparency flag. + * + * @see Window#transparent + * @since v1-alpha2 + * + * -- GETTER -- + * Returns the transparency flag state. + * + * @return transparency flag state + * @see Window#transparent + * @since v1-alpha2 + */ + @NotNull + private Tristate transparent = Tristate.UNSET; + + /** + * Contains the rendering flag. + * + * @see Window#rendering + * @since v1-alpha2 + * + * -- GETTER -- + * Returns the rendering flag state. + * + * @return rendering flag state + * @see Window#rendering + * @since v1-alpha2 + */ + @NotNull + private Tristate rendering = Tristate.UNSET; + + /** + * Constructs this class. + * + * @since v1-alpha2 + */ + public Builder() {} + + /** + * Builds a new {@link Window} class. + * + * @throws IllegalStateException if the window title, size or position is unset + * @throws UnexpectedThrowableException thrown when creating a new {@link Window} instance fails + * @since v1-alpha2 + */ + public Window build() throws IllegalStateException, UnexpectedThrowableException { + // Booleanized tristates with default values + boolean resizableBoolean = true; + boolean borderlessBoolean = false; + boolean focusableBoolean = true; + boolean onTopBoolean = false; + boolean transparentBoolean = false; + boolean renderingBoolean = true; + + // Check for required fields + if (title == null) + throw new IllegalStateException("The window name 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 + if (windowMode == null) + windowMode = WindowMode.WINDOWED; + if (vsyncMode == null) + vsyncMode = VsyncMode.ON; + + // Override booleanized tristate defaults + if (resizable == Tristate.FALSE) + resizableBoolean = false; + if (borderless == Tristate.TRUE) + borderlessBoolean = true; + if (focusable == Tristate.FALSE) + focusableBoolean = false; + if (onTop == Tristate.TRUE) + onTopBoolean = true; + if (transparent == Tristate.TRUE) + transparentBoolean = true; + if (rendering == Tristate.FALSE) + renderingBoolean = false; + + // 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); + } catch (Throwable throwable) { + throw new UnexpectedThrowableException(throwable, "Window.Builder was unable to create new Window instance"); + } + } + + /** + * Sets the window title. + * + * @param title new window title + * @return builder instance + * @since v1-alpha2 + */ + @NotNull + public synchronized Builder setTitle(@Nullable String title) { + this.title = title; + return this; + } + + /** + * Sets the window size. + * + * @param size new window size + * @return builder instance + * @since v1-alpha2 + */ + @NotNull + public synchronized Builder setSize(@Nullable Vec2i size) { + this.size = size; + return this; + } + + /** + * Sets the window position. + * + * @param position new window position + * @return builder instance + * @since v1-alpha2 + */ + @NotNull + public synchronized Builder setPosition(@Nullable Vec2i position) { + this.position = position; + return this; + } + + /** + * Sets the window mode. + * + * @param windowMode new window mode + * @return builder instance + * @since v1-alpha2 + */ + @NotNull + public synchronized Builder setWindowMode(@Nullable WindowMode windowMode) { + this.windowMode = windowMode; + return this; + } + + /** + * Sets the V-Sync mode. + * + * @param vsyncMode new V-Sync mode + * @return builder instance + * @since v1-alpha2 + */ + @NotNull + public synchronized Builder setVsyncMode(@Nullable VsyncMode vsyncMode) { + this.vsyncMode = vsyncMode; + return this; + } + + /** + * Sets the resizable flag. + * + * @param resizable new resizable flag state + * @return builder instance + * @since v1-alpha2 + */ + @NotNull + public synchronized Builder setResizable(@NotNull Tristate resizable) { + this.resizable = resizable; + return this; + } + + /** + * Sets the borderless flag. + * + * @param borderless new borderless flag state + * @return builder instance + * @since v1-alpha2 + */ + @NotNull + public synchronized Builder setBorderless(@NotNull Tristate borderless) { + this.borderless = borderless; + return this; + } + + /** + * Sets the focusable flag. + * + * @param focusable new focusable flag state + * @return builder instance + * @since v1-alpha2 + */ + @NotNull + public synchronized Builder setFocusable(@NotNull Tristate focusable) { + this.focusable = focusable; + return this; + } + + /** + * Sets the on top flag. + * + * @param onTop new on top flag state + * @return builder instance + * @since v1-alpha2 + */ + @NotNull + public synchronized Builder setOnTop(@NotNull Tristate onTop) { + this.onTop = onTop; + return this; + } + + /** + * Sets the transparency flag. + * + * @param transparent new transparency flag state + * @return builder instance + * @since v1-alpha2 + */ + @NotNull + public synchronized Builder setTransparent(@NotNull Tristate transparent) { + this.transparent = transparent; + return this; + } + + /** + * Sets the rendering flag. + * + * @param rendering new rendering flag state + * @return builder instance + * @since v1-alpha2 + */ + @NotNull + public synchronized Builder setRendering(@NotNull Tristate rendering) { + this.rendering = rendering; + return this; + } + } } 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 6f31bd1..bde2a5f 100644 --- a/testapp/src/main/java/de/staropensource/sosengine/testapp/Main.java +++ b/testapp/src/main/java/de/staropensource/sosengine/testapp/Main.java @@ -20,6 +20,7 @@ package de.staropensource.sosengine.testapp; import de.staropensource.sosengine.base.Engine; +import de.staropensource.sosengine.base.exceptions.UnexpectedThrowableException; import de.staropensource.sosengine.base.logging.LoggerInstance; import de.staropensource.sosengine.base.types.CodePart; import de.staropensource.sosengine.base.types.logging.LogIssuer; @@ -27,6 +28,7 @@ import de.staropensource.sosengine.base.types.vectors.Vec2i; import de.staropensource.sosengine.graphics.GraphicsSubsystem; import de.staropensource.sosengine.graphics.classes.ApiMainClass; import de.staropensource.sosengine.graphics.classes.ApiManagementClass; +import de.staropensource.sosengine.graphics.classes.Window; import lombok.Getter; import lombok.SneakyThrows; @@ -111,6 +113,15 @@ public class Main { ApiManagementClass management = api.getManagement(); // Create window + try { + Window window = new Window.Builder() + .setTitle("test application window") + .setSize(new Vec2i(960, 540)) + .setPosition(new Vec2i(10, 10)) + .build(); + } catch (UnexpectedThrowableException exception) { + logger.crash("build() throw an UnexpectedThrowableException", exception.getThrowable()); + } // Sleep for five seconds Thread.sleep(5000);