diff --git a/rendering/src/main/java/de/staropensource/engine/rendering/RenderingSubsystem.java b/rendering/src/main/java/de/staropensource/engine/rendering/RenderingSubsystem.java index 90e9692..3ad044c 100644 --- a/rendering/src/main/java/de/staropensource/engine/rendering/RenderingSubsystem.java +++ b/rendering/src/main/java/de/staropensource/engine/rendering/RenderingSubsystem.java @@ -21,25 +21,30 @@ package de.staropensource.engine.rendering; import de.staropensource.engine.base.annotation.EngineSubsystem; import de.staropensource.engine.base.annotation.EventListener; +import de.staropensource.engine.base.implementable.Event; import de.staropensource.engine.base.implementable.SubsystemClass; import de.staropensource.engine.base.implementable.helper.EventHelper; import de.staropensource.engine.base.logging.Logger; -import de.staropensource.engine.base.type.EventPriority; -import de.staropensource.engine.base.utility.Math; +import de.staropensource.engine.base.utility.misc.NumberUtil; import de.staropensource.engine.base.utility.information.EngineInformation; import de.staropensource.engine.base.implementation.versioning.StarOpenSourceVersioningSystem; import de.staropensource.engine.base.event.InternalEngineShutdownEvent; import de.staropensource.engine.base.type.DependencyVector; -import de.staropensource.engine.base.utility.Miscellaneous; +import de.staropensource.engine.base.utility.misc.Miscellaneous; import de.staropensource.engine.rendering.event.InputEvent; import de.staropensource.engine.rendering.event.RenderingErrorEvent; import de.staropensource.engine.rendering.exception.NotOnMainThreadException; +import de.staropensource.engine.rendering.renderer.Renderer; import de.staropensource.engine.rendering.type.Window; +import de.staropensource.engine.rendering.type.window.RenderingPlatform; import de.staropensource.engine.rendering.type.window.VsyncMode; import lombok.Getter; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.lwjgl.glfw.*; +import java.util.ArrayList; +import java.util.Collections; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.concurrent.atomic.AtomicReference; @@ -117,8 +122,13 @@ public final class RenderingSubsystem extends SubsystemClass { // Precompute event listeners cacheEvents(); + + // Initialize GLFW initGlfw(); + // Initialize renderer + Renderer.initialize(); + // Warn about subsystem and API instability Logger.warn("The rendering subsystem is experimental. Subsystem and API stability are not guaranteed."); } @@ -150,10 +160,10 @@ public final class RenderingSubsystem extends SubsystemClass { Logger.diag("Setting initialization hints"); switch (RenderingSubsystemConfiguration.getInstance().getInitialPlatform()) { case ANY -> glfwInitHint(GLFW_PLATFORM, GLFW_ANY_PLATFORM); - case WAYLAND -> tryPlatform(GLFW_PLATFORM_WAYLAND); - case X11 -> tryPlatform(GLFW_PLATFORM_X11); - case WIN32 -> tryPlatform(GLFW_PLATFORM_WIN32); - case COCOA -> tryPlatform(GLFW_PLATFORM_COCOA); + case WAYLAND -> tryPlatform(GLFW_PLATFORM_WAYLAND, RenderingPlatform.WAYLAND); + case X11 -> tryPlatform(GLFW_PLATFORM_X11, RenderingPlatform.X11); + case WIN32 -> tryPlatform(GLFW_PLATFORM_WIN32, RenderingPlatform.WIN32); + case COCOA -> tryPlatform(GLFW_PLATFORM_COCOA, RenderingPlatform.COCOA); case NONE -> glfwInitHint(GLFW_PLATFORM, GLFW_PLATFORM_NULL); } glfwInitHint(GLFW_WAYLAND_LIBDECOR, RenderingSubsystemConfiguration.getInstance().isInitialDisableLibdecor() ? GLFW_WAYLAND_DISABLE_LIBDECOR : GLFW_WAYLAND_PREFER_LIBDECOR); @@ -182,7 +192,7 @@ public final class RenderingSubsystem extends SubsystemClass { long shutdownTime = Miscellaneous.measureExecutionTime(() -> { // Close all windows - for (Window window : Window.getWindows()) + for (Window window : new ArrayList<>(Window.getWindows())) window.close(); instance.errorCallback.free(); @@ -198,7 +208,7 @@ public final class RenderingSubsystem extends SubsystemClass { * @see RenderingSubsystemConfiguration#errorRenderingFailures * @since v1-alpha9 */ - @EventListener(event = RenderingErrorEvent.class, priority = EventPriority.EXCLUSIVELY_IMPORTANT) + @EventListener(event = RenderingErrorEvent.class, priority = Event.Priority.EXCLUSIVELY_IMPORTANT) private static void logRenderingError(@NotNull String error) { Logger.error("Rendering error occurred: " + error); } @@ -220,6 +230,9 @@ public final class RenderingSubsystem extends SubsystemClass { LinkedHashMap<@NotNull Window, @NotNull Throwable> throwables = new LinkedHashMap<>(); + // Poll for events + glfwPollEvents(); + // Update and render all windows for (Window window : Window.getWindows()) { if (!window.isRendering()) @@ -232,14 +245,14 @@ public final class RenderingSubsystem extends SubsystemClass { Logger.error("Rendering window " + window + " failed: Threw throwable " + throwable.getClass().getName() + (throwable.getMessage() == null ? "" : ": " + throwable.getMessage())); throwables.put(window, throwable); } - } - // Poll for events - glfwPollEvents(); + //bgfx_frame(false); + } return throwables; } /** + * * Renders all windows continuously. * To render all windows just once, invoke * {@link #renderWindows()} instead. @@ -270,6 +283,8 @@ public final class RenderingSubsystem extends SubsystemClass { if (!RenderingSubsystemConfiguration.getInstance().isDebugFrames()) reportDuration = Long.MAX_VALUE; + Logger.info("Entering render loop"); + // Run while the 'output' is empty while (output.get().isEmpty()) { renderTime = Miscellaneous.measureExecutionTime(() -> { @@ -293,11 +308,33 @@ public final class RenderingSubsystem extends SubsystemClass { Thread.onSpinWait(); } + // Calculate delta time and frame count every second if (System.currentTimeMillis() >= reportDuration) { - deltaTime = Math.getMeanLong(splitDeltaTime); // Calculate delta time + deltaTime = NumberUtil.calculateMeanLong(splitDeltaTime); // Calculate delta time Logger.diag("Delta time average: " + deltaTime + " | Frames/s: " + 1000 / deltaTime); // Print delta time and frame count to console + if (RenderingSubsystemConfiguration.getInstance().isDebugWindowStates()) + for (Window window : Window.getWindows()) + Logger.diag( + "Window state for " + window.getUniqueIdentifier() + "\n" + + "-> Terminated: " + window.isTerminated() + "\n" + + "-> Name: " + window.getName() + "\n" + + "-> Title: " + window.getTitle() + "\n" + + "-> Size: " + window.getSize() + "\n" + + " -> Minimum: " + window.getMinimumSize() + "\n" + + " -> Maximum: " + window.getMaximumSize() + "\n" + + "-> Position: " + window.getPosition() + "\n" + + "-> Mode: " + window.getMode() + "\n" + + "-> Monitor: " + window.getMonitor() + "\n" + + "-> Resizable: " + window.isResizable() + "\n" + + "-> Borderless: " + window.isBorderless() + "\n" + + "-> Focusable: " + window.isFocusable() + "\n" + + "-> On top: " + window.isOnTop() + "\n" + + "-> Transparent: " + window.isTransparent() + "\n" + + "-> Rendering: " + window.isRendering() + ); + reportDuration = System.currentTimeMillis() + 1000; // Update 'reportDuration' splitDeltaTime.clear(); // Clear 'splitDeltaTime' list } @@ -312,12 +349,21 @@ public final class RenderingSubsystem extends SubsystemClass { * and if so, specifies it as the platform to use. * * @param platform platform to try + * @param renderingPlatform {@link RenderingPlatform} used to log that the platform is unsupported (set to {@code null} to disable) * @since v1-alpha9 */ - private void tryPlatform(int platform) { + private void tryPlatform(int platform, @Nullable RenderingPlatform renderingPlatform) { if (glfwPlatformSupported(platform)) - glfwInitHint(GLFW_PLATFORM, platform); - else + if (platform != GLFW_PLATFORM_WAYLAND) + glfwInitHint(GLFW_PLATFORM, platform); + else { + Logger.warn("Wayland is not supported by the StarOpenSource Engine due to various issues with it, sorry."); + tryPlatform(GLFW_PLATFORM_X11, RenderingPlatform.X11); + } + else { + if (renderingPlatform != null) + Logger.warn("Platform RenderingPlatform." + renderingPlatform.name() + " is not supported GLFW. Using RenderingPlatform.ANY instead"); glfwInitHint(GLFW_PLATFORM, GLFW_ANY_PLATFORM); + } } } diff --git a/rendering/src/main/java/de/staropensource/engine/rendering/RenderingSubsystemConfiguration.java b/rendering/src/main/java/de/staropensource/engine/rendering/RenderingSubsystemConfiguration.java index 32ed27c..9d02290 100644 --- a/rendering/src/main/java/de/staropensource/engine/rendering/RenderingSubsystemConfiguration.java +++ b/rendering/src/main/java/de/staropensource/engine/rendering/RenderingSubsystemConfiguration.java @@ -23,6 +23,7 @@ import de.staropensource.engine.base.implementable.Configuration; import de.staropensource.engine.base.logging.Logger; import de.staropensource.engine.base.utility.PropertiesReader; import de.staropensource.engine.rendering.event.RenderingErrorEvent; +import de.staropensource.engine.rendering.type.window.RenderingAdapter; import de.staropensource.engine.rendering.type.window.RenderingPlatform; import de.staropensource.engine.rendering.type.window.VsyncMode; import lombok.Getter; @@ -97,24 +98,48 @@ public final class RenderingSubsystemConfiguration extends Configuration { * Contains whether or not the delta time and * FPS count should be logged to the console * every second. - *
- * Changes will no longer be picked up as - * soon as the rendering loop is running. * * @since v1-alpha9 * -- GETTER -- * Returns whether or not the delta time and * FPS count should be logged to the console * every second. - *
- * Changes will no longer be picked up as - * soon as the rendering loop is running. * * @return print delta time and FPS count? * @since v1-alpha9 */ private boolean debugFrames; + /** + * Contains if to log the state of all + * windows every second. + * + * @since v1-alpha9 + * -- GETTER -- + * Returns if to log the state of all + * windows every second. + * + * @return log states of all windows? + * @since v1-alpha9 + */ + private boolean debugWindowStates; + + /** + * Contains if to allow updates to a window's + * position. May cause errors and crashes to + * appear, we do not know why. + * + * @since v1-alpha9 + * -- GETTER -- + * Returns if to allow updates to a window's + * position. May cause errors and crashes to + * appear, we do not know why. + * + * @return allow window position updates? + * @since v1-alpha9 + */ + private boolean debugAllowPositionUpdates; + /** * Contains the platform GLFW shall try initialising. @@ -172,6 +197,18 @@ public final class RenderingSubsystemConfiguration extends Configuration { private boolean errorRenderingFailures; + /** + * Contains the adapter bgfx shall use. + * + * @since v1-alpha9 + * -- GETTER -- + * Returns the adapter bgfx shall use. + * + * @return bgfx adapter + * @since v1-alpha9 + */ + private RenderingAdapter renderingAdapter; + /** * Contains which {@link VsyncMode} to use. *
@@ -241,18 +278,27 @@ public final class RenderingSubsystemConfiguration extends Configuration {
case "debug" -> debug = parser.getBoolean(group + property);
case "debugInput" -> debugInput = parser.getBoolean(group + property);
case "debugFrames" -> debugFrames = parser.getBoolean(group + property);
+ case "debugWindowStates" -> debugWindowStates = parser.getBoolean(group + property);
+ case "debugAllowPositionUpdates" -> debugAllowPositionUpdates = parser.getBoolean(group + property);
case "initialPlatform" -> {
try {
initialPlatform = RenderingPlatform.valueOf(parser.getString(group + property).toUpperCase());
} catch (IllegalArgumentException ignored) {
- Logger.error("Platform " + parser.getString(group + property) + " is not valid");
+ Logger.error("Rendering platform " + parser.getString(group + property) + " is not valid");
}
}
case "initialDisableLibdecor" -> initialDisableLibdecor = parser.getBoolean(group + property);
case "errorRenderingFailures" -> errorRenderingFailures = parser.getBoolean(group + property);
+ case "renderingAdapter" -> {
+ try {
+ renderingAdapter = RenderingAdapter.valueOf(parser.getString(group + property).toUpperCase());
+ } catch (IllegalArgumentException exception) {
+ Logger.error("Rendering adapter " + parser.getString(group + property) + " is not valid");
+ }
+ }
case "vsyncMode" -> {
try {
vsyncMode = VsyncMode.valueOf(parser.getString(group + property).toUpperCase());
@@ -271,21 +317,26 @@ public final class RenderingSubsystemConfiguration extends Configuration {
if (!debug) {
debugInput = false;
debugFrames = false;
+ debugWindowStates = false;
+ debugAllowPositionUpdates = false;
}
}
/** {@inheritDoc} */
@Override
public void loadDefaultConfiguration() {
- debug = false;
+ debug = true;
debugInput = false;
- debugFrames = false;
+ debugFrames = true;
+ debugWindowStates = true;
+ debugAllowPositionUpdates = true;
initialPlatform = RenderingPlatform.ANY;
initialDisableLibdecor = false;
errorRenderingFailures = true;
+ renderingAdapter = RenderingAdapter.ANY;
vsyncMode = VsyncMode.ON;
maximumFramesPerSecond = 60;
}
@@ -297,12 +348,15 @@ public final class RenderingSubsystemConfiguration extends Configuration {
case "debug" -> { return debug; }
case "debugInput" -> { return debugInput; }
case "debugFrames" -> { return debugFrames; }
+ case "debugWindowStates" -> { return debugWindowStates; }
+ case "debugAllowPositionUpdates" -> { return debugAllowPositionUpdates; }
case "initialPlatform" -> { return initialPlatform; }
case "disableLibdecor" -> { return initialDisableLibdecor; }
case "errorRenderingFailures" -> { return errorRenderingFailures; }
+ case "renderingAdapter" -> { return renderingAdapter; }
case "vsyncMode" -> { return vsyncMode; }
case "maximumFramesPerSecond" -> { return maximumFramesPerSecond; }
default -> { return null; }
diff --git a/rendering/src/main/java/de/staropensource/engine/rendering/callback/KeyCallback.java b/rendering/src/main/java/de/staropensource/engine/rendering/callback/KeyCallback.java
index 28fe6aa..985161d 100644
--- a/rendering/src/main/java/de/staropensource/engine/rendering/callback/KeyCallback.java
+++ b/rendering/src/main/java/de/staropensource/engine/rendering/callback/KeyCallback.java
@@ -21,7 +21,6 @@ package de.staropensource.engine.rendering.callback;
import de.staropensource.engine.rendering.type.Window;
import de.staropensource.engine.rendering.event.InputEvent;
-import de.staropensource.engine.rendering.callback.WindowCallback;
import de.staropensource.engine.rendering.type.input.Key;
import de.staropensource.engine.rendering.type.input.KeyState;
import org.jetbrains.annotations.NotNull;
diff --git a/rendering/src/main/java/de/staropensource/engine/rendering/event/RenderingThreadThrowableEvent.java b/rendering/src/main/java/de/staropensource/engine/rendering/event/RenderingThreadThrowableEvent.java
new file mode 100644
index 0000000..3ca7e8b
--- /dev/null
+++ b/rendering/src/main/java/de/staropensource/engine/rendering/event/RenderingThreadThrowableEvent.java
@@ -0,0 +1,58 @@
+/*
+ * STAROPENSOURCE ENGINE SOURCE FILE
+ * Copyright (c) 2024 The StarOpenSource Engine Authors
+ * 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
+ * Frame handlers are invoked before + * all windows are rendered, allowing + * the application or game to respond + * to frame renders. + * + * @since v1-alpha9 + */ + private static final @NotNull List<@NotNull FrameHandler> frameHandlers = Collections.synchronizedList(new ArrayList<>()); + + /** + * Contains if the renderer has been initialized. + * + * @since v1-alpha9 + * -- GETTER -- + * Returns if the renderer has been initialized. + * + * @return renderer initialized? + * @since v1-alpha9 + */ + @Getter + private static boolean initialized = false; + + /** + * Contains if the renderer is running. + * + * @since v1-alpha9 + * -- GETTER -- + * Returns if the renderer is running. + * + * @return renderer running? + * @since v1-alpha9 + */ + @Getter + private static boolean running = false; + + /** + * Contains the frame count aka. + * the amount of frames rendered. + *
+ * Updated every frame. + * + * @since v1-alpha9 + * -- GETTER -- + * Returns the frame count aka. + * the amount of frames rendered. + *
+ * Updated every frame. + * + * @return amount of frames rendered + * @since v1-alpha9 + */ + @Getter + private static long frameCount = 0L; + + /** + * Contains the delta time, also + * known as the render time. + *
+ * Updated every second. + * + * @since v1-alpha9 + * -- GETTER -- + * Returns the delta time, also + * known as the render time. + *
+ * Updated every second. + * + * @return delta time + * @since v1-alpha9 + */ + @Getter + private static double deltaTime = 0d; + + /** + * Contains the frames per second (FPS) count. + *
+ * Updated every second. + * + * @since v1-alpha9 + * -- GETTER -- + * Returns the frames per second (FPS) count. + *
+ * Updated every second. + * + * @return frames per second + * @since v1-alpha9 + */ + @Getter + private static double framesPerSecond = 0d; + + /** + * Contains the time it took + * to calculate the last frame. + *
+ * Updated every frame. + * + * @since v1-alpha9 + * -- GETTER -- + * Contains the time it took + * to calculate the last frame. + *
+ * Updated every frame.
+ *
+ * @return last frame time
+ * @since v1-alpha9
+ */
+ @Getter
+ private static Map<@NotNull String, @NotNull Long> lastFrameTime = Collections.unmodifiableMap(new HashMap<>());
+
+
+ // ----> Initialization
+ /**
+ * Initializes the renderer.
+ *
+ * @since v1-alpha9
+ */
+ public static void initialize() {
+ if (initialized)
+ return;
+
+ addFrameHandler(new FrameHandler() {
+ @Override
+ public @NotNull FrameHandler.Priority getPriority() {
+ return Priority.VERY_IMPORTANT;
+ }
+
+ @Override
+ public void run() {
+ bgfx_set_view_clear(0, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x000000, 1.0f, 0);
+ }
+ });
+ addFrameHandler(new FrameHandler() {
+ /** {@inheritDoc} */
+ @Override
+ public @NotNull FrameHandler.Priority getPriority() {
+ return Priority.VERY_UNIMPORTANT;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void run() {
+ int offset = 2;
+
+ bgfx_dbg_text_clear(0, false);
+ bgfx_dbg_text_printf(0, 0, 0x0f, "It's " + NumberUtil.padNumbers(LocalTime.now().getHour(), 2) + ":" + NumberUtil.padNumbers(LocalTime.now().getMinute(), 2) + ":" + NumberUtil.padNumbers(LocalTime.now().getSecond(), 2));
+ bgfx_dbg_text_printf(0, 1, 0x0f, "LFT.size(): " + lastFrameTime.size());
+ for (String item : lastFrameTime.keySet()) {
+ bgfx_dbg_text_printf(0, offset, 0x0f, item + ": " + lastFrameTime.get(item) + "ms");
+ offset += 1;
+ }
+ }
+ });
+
+ initialized = true;
+ }
+
+
+ // -----> Frame handler management
+ /**
+ * Adds the specified frame handler.
+ *
+ * @param frameHandler {@link FrameHandler} to add
+ * @since v1-alpha9
+ */
+ public static void addFrameHandler(@NotNull FrameHandler frameHandler) {
+ frameHandlers.add(frameHandler);
+ frameHandlers.sort(Comparator.comparing(FrameHandler::getPriority));
+ }
+
+ /**
+ * Removes the specified frame handler.
+ *
+ * @param frameHandler {@link FrameHandler} to remove
+ * @since v1-alpha9
+ */
+ public static void removeFrameHandler(@NotNull FrameHandler frameHandler) {
+ frameHandlers.remove(frameHandler);
+ }
+
+
+ // -----> Rendering logic
+ /**
+ * Starts the renderer.
+ *
+ * @throws NotOnMainThreadException if not running on the main thread
+ * @throws RuntimeException on major rendering error
+ * @since v1-alpha9
+ */
+ public static void start() throws RuntimeException {
+ // Check if running on main thread
+ if (!Miscellaneous.onMainThread())
+ throw new NotOnMainThreadException();
+
+ String threadName = Thread.currentThread().getName();
+ int threadPriority = Thread.currentThread().getPriority();
+ RuntimeException exception = null;
+
+ // Update thread
+ Thread.currentThread().setName("Rendering thread");
+ Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
+
+ // Start renderer
+ running = true;
+ try {
+ render();
+ } catch (Throwable throwable) {
+ exception = new RuntimeException("Renderer failed", throwable);
+ }
+
+ // Revert thread changes
+ Thread.currentThread().setName(threadName);
+ Thread.currentThread().setPriority(threadPriority);
+
+ // Throw if necessary
+ if (exception != null)
+ throw exception;
+ }
+
+ /**
+ * Renders all windows.
+ *
+ * @since v1-alpha9
+ */
+ @SuppressWarnings({ "InfiniteLoopStatement" })
+ private static void render() throws Throwable {
+ long previousFrameCount = 0L; // Frame count one second ago
+ LinkedList
@@ -99,8 +90,39 @@ public final class Window implements AutoCloseable {
* @return fresh flag state
* @since v1-alpha9
*/
- private boolean fresh = true;
+ @Getter(value = AccessLevel.NONE)
+ @Setter(value = AccessLevel.NONE)
+ private boolean fresh;
+ /**
+ * Contains the internal GLFW window identifier.
+ *
+ * @since v1-alpha9
+ * -- GETTER --
+ * Returns the internal GLFW window identifier.
+ *
+ * @return GLFW window identifier
+ * @since v1-alpha9
+ */
+ @Getter(value = AccessLevel.NONE)
+ @Setter(value = AccessLevel.NONE)
+ private long internalWindowIdentifier;
+
+ /**
+ * Contains the internal bgfx view identifier.
+ *
+ * @since v1-alpha9
+ * -- GETTER --
+ * Returns the internal bgfx view identifier.
+ *
+ * @return bgfx view identifier
+ * @since v1-alpha9
+ */
+ @Getter(value = AccessLevel.NONE)
+ @Setter(value = AccessLevel.NONE)
+ private int internalViewIdentifier;
+
+ // -----> Window properties
/**
* Contains if this window can be interacted with or not.
*
@@ -258,7 +280,7 @@ public final class Window implements AutoCloseable {
private @NotNull Vec2i position;
/**
- * Contains in which {@link WindowMode} this window is in.
+ * Contains in which {@link Mode} this window is in.
*
* @since v1-alpha9
* -- GETTER --
@@ -267,7 +289,7 @@ public final class Window implements AutoCloseable {
* @return window mode
* @since v1-alpha9
*/
- private @NotNull WindowMode windowMode;
+ private @NotNull Window.Mode mode;
/**
* Contains on which {@link Monitor} the window is displayed on.
@@ -287,24 +309,6 @@ public final class Window implements AutoCloseable {
@Setter
private @NotNull Monitor monitor;
- /**
- * Contains how fast the window may update it's contents.
- *
- * @since v1-alpha9
- * -- GETTER --
- * Returns how fast the window may update it's contents.
- *
- * @return new window frame limit
- * @since v1-alpha9
- * -- SETTER --
- * Sets how fast the window may update it's contents.
- *
- * @param framerate new frame limit
- * @since v1-alpha9
- */
- @Setter
- private int framerate;
-
/**
* Contains if this window can be resized by the user.
*
@@ -403,16 +407,20 @@ public final class Window implements AutoCloseable {
*/
private GLFWMouseButtonCallback mouseButtonCallback;
+
+ // -----> Static methods
/**
* Returns a set of active windows.
*
* @return active windows
* @since v1-alpha9
*/
- public static @NotNull HashSet<@NotNull Window> getWindows() {
- return new HashSet<>(windows);
+ public static @NotNull List<@NotNull Window> getWindows() {
+ return Collections.unmodifiableList(windows);
}
+
+ // -----> Initialization
/**
* Creates and initializes an instance of this abstract class.
*
@@ -423,7 +431,7 @@ public final class Window implements AutoCloseable {
* @param minimumSize minimum size
* @param maximumSize maximum size
* @param position position
- * @param windowMode window mode
+ * @param mode window mode
* @param monitor monitor
* @param resizable resizable flag
* @param borderless borderless flag
@@ -441,7 +449,7 @@ public final class Window implements AutoCloseable {
@NotNull Vec2i minimumSize,
@NotNull Vec2i maximumSize,
@NotNull Vec2i position,
- @NotNull WindowMode windowMode,
+ @NotNull Window.Mode mode,
@NotNull Monitor monitor,
boolean resizable,
boolean borderless,
@@ -450,7 +458,11 @@ public final class Window implements AutoCloseable {
boolean transparent,
boolean rendering) throws NotOnMainThreadException {
// Initialize variables
+ this.fresh = true;
+ this.internalWindowIdentifier = 0L;
+ this.internalViewIdentifier = 0;
this.uniqueIdentifier = UUID.randomUUID();
+ this.terminated = false;
this.name = name;
this.title = title;
this.icons = icons;
@@ -458,7 +470,7 @@ public final class Window implements AutoCloseable {
this.minimumSize = minimumSize;
this.maximumSize = maximumSize;
this.position = position;
- this.windowMode = windowMode;
+ this.mode = mode;
this.monitor = monitor;
this.resizable = resizable;
this.borderless = borderless;
@@ -468,25 +480,45 @@ public final class Window implements AutoCloseable {
this.rendering = rendering;
// Log about window creation
- Logger.diag("Creating new window with properties: uniqueIdentifier=" + uniqueIdentifier + " name=\"" + name + "\" title=\"" + title + "\" icons=" + Arrays.toString(icons) + " 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);
+ Logger.verb("Creating new window " + this.uniqueIdentifier + "\n" +
+ "-> Name: " + this.name + "\n" +
+ "-> Title: " + this.title + "\n" +
+ "-> Size: " + this.size + "\n" +
+ " -> Minimum: " + this.minimumSize + "\n" +
+ " -> Maximum: " + this.maximumSize + "\n" +
+ "-> Position: " + this.position + "\n" +
+ "-> Mode: " + this.mode + "\n" +
+ "-> Monitor: " + this.monitor + "\n" +
+ "-> Resizable: " + this.resizable + "\n" +
+ "-> Borderless: " + this.borderless + "\n" +
+ "-> Focusable: " + this.focusable + "\n" +
+ "-> On top: " + this.onTop + "\n" +
+ "-> Transparent: " + this.transparent + "\n" +
+ "-> Rendering: " + this.rendering
+ );
- // Allow windowing API to initialize window
+ // Check if another window already exists
+ if (!Window.getWindows().isEmpty())
+ Logger.crash("Window already present\nThe StarOpenSource Engine is unable to initialize more than one window at the moment, sorry.");
+
+ // Initialize window
initializeWindow();
// Update state
updateState();
+ // Initialize bgfx
+ if (glfwGetPlatform() != GLFW_PLATFORM_NULL)
+ initBgfx();
+
// Add to window set
windows.add(this);
fresh = false;
}
+
/**
- * Allows the windowing 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.
+ * Initializes this window.
*
* @throws NotOnMainThreadException if not running on the main thread
* @since v1-alpha9
@@ -504,12 +536,13 @@ public final class Window implements AutoCloseable {
}
// Set window hints
- glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); // The window's visibility is later changed in setWindowState, this is just for setting up the window
- glfwWindowHint(GLFW_POSITION_X, getPosition().getX());
- glfwWindowHint(GLFW_POSITION_Y, getPosition().getY());
+ if (RenderingSubsystemConfiguration.getInstance().isDebugAllowPositionUpdates()) {
+ 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_FOCUSED, TypeConversion.booleanToInteger(focused));
+ glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, TypeConversion.booleanToInteger(transparent));
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_FALSE);
glfwWindowHintString(GLFW_WAYLAND_APP_ID, getName());
@@ -517,8 +550,8 @@ public final class Window implements AutoCloseable {
glfwWindowHintString(GLFW_X11_INSTANCE_NAME, getName());
// Create window
- identifier = glfwCreateWindow(getSize().getX(), getSize().getY(), getTitle(), NULL, NULL);
- if (identifier == NULL)
+ internalWindowIdentifier = glfwCreateWindow(getSize().getX(), getSize().getY(), getTitle(), NULL, NULL);
+ if (internalWindowIdentifier == NULL)
throw new WindowCreationFailureException();
// Own context
@@ -532,18 +565,15 @@ public final class Window implements AutoCloseable {
mouseButtonCallback = GLFWMouseButtonCallback.create(new MouseButtonCallback(this));
// Set callback
- glfwSetKeyCallback(identifier, keyCallback);
- glfwSetMouseButtonCallback(identifier, mouseButtonCallback);
+ glfwSetKeyCallback(internalWindowIdentifier, keyCallback);
+ glfwSetMouseButtonCallback(internalWindowIdentifier, mouseButtonCallback);
// Update the window state
setIcons(getIcons());
setSize(getSize());
setMinimumSize(getMinimumSize());
setMaximumSize(getMaximumSize());
- setWindowMode(getWindowMode());
-
- // Initialize bgfx
- initBgfx();
+ setMode(getMode());
}
/**
@@ -552,6 +582,10 @@ public final class Window implements AutoCloseable {
* @since v1-alpha9
*/
private void initBgfx() {
+ // Ensure the window is not terminated
+ if (terminated)
+ return;
+
try (MemoryStack stack = stackPush()) {
Logger.verb("Initializing bgfx");
@@ -560,13 +594,29 @@ public final class Window implements AutoCloseable {
BGFXInit init = BGFXInit.calloc(stack);
bgfx_init_ctor(init);
+ // Set adapter
+ Logger.diag("Setting adapter");
+ init.vendorId(switch (RenderingSubsystemConfiguration.getInstance().getRenderingAdapter()) {
+ case ANY -> BGFX_PCI_ID_NONE;
+ case SOFTWARE -> BGFX_PCI_ID_SOFTWARE_RASTERIZER;
+ case AMD -> BGFX_PCI_ID_AMD;
+ case APPLE -> BGFX_PCI_ID_APPLE;
+ case INTEL -> BGFX_PCI_ID_INTEL;
+ case NVIDIA -> BGFX_PCI_ID_NVIDIA;
+ case MICROSOFT -> BGFX_PCI_ID_MICROSOFT;
+ });
+
// Set initial resolution
Logger.diag("Setting initial resolution");
init
- .resolution(it -> it
- .width(size.getX())
- .height(size.getY())
- .reset(BGFX_RESET_VSYNC));
+ .resolution(
+ it -> it
+ .width(size.getX())
+ .height(size.getY())
+ .reset(
+ BGFX_RESET_VSYNC
+ )
+ );
// Determine platform to render for
Logger.diag("Setting platform");
@@ -574,18 +624,17 @@ public final class Window implements AutoCloseable {
case GLFW_PLATFORM_X11 -> init
.platformData()
.ndt(GLFWNativeX11.glfwGetX11Display())
- .nwh(GLFWNativeX11.glfwGetX11Window(identifier));
+ .nwh(GLFWNativeX11.glfwGetX11Window(internalWindowIdentifier));
case GLFW_PLATFORM_WAYLAND -> init
.platformData()
.ndt(GLFWNativeWayland.glfwGetWaylandDisplay())
- .nwh(GLFWNativeWayland.glfwGetWaylandWindow(identifier));
+ .nwh(GLFWNativeWayland.glfwGetWaylandWindow(internalWindowIdentifier));
case GLFW_PLATFORM_WIN32 -> init
.platformData()
- .nwh(GLFWNativeWin32.glfwGetWin32Window(identifier));
+ .nwh(GLFWNativeWin32.glfwGetWin32Window(internalWindowIdentifier));
case GLFW_PLATFORM_COCOA -> init
.platformData()
- .nwh(GLFWNativeCocoa.glfwGetCocoaWindow(identifier));
- case GLFW_PLATFORM_NULL -> {}
+ .nwh(GLFWNativeCocoa.glfwGetCocoaWindow(internalWindowIdentifier));
default -> Logger.crash("Invalid GLFW platform \"" + glfwGetPlatform() + "\"");
}
@@ -595,8 +644,6 @@ public final class Window implements AutoCloseable {
Logger.crash("Unable to initialize bgfx");
bgfx_set_debug(BGFX_DEBUG_TEXT);
- bgfx_set_view_rect(0, 0, 0, size.getX(), size.getY());
- bgfx_touch(0);
} catch (UnsatisfiedLinkError error) {
Logger.crash("Failed to load LWJGL native libraries", error);
}
@@ -613,7 +660,7 @@ public final class Window implements AutoCloseable {
*/
public void updateState() throws NotOnMainThreadException {
// Ensure the window is not terminated
- if (isTerminated())
+ if (terminated)
return;
// Ensure running on the main thread
@@ -621,14 +668,14 @@ public final class Window implements AutoCloseable {
throw new NotOnMainThreadException();
// Update window mode
- if (Miscellaneous.getBooleanizedInteger(glfwGetWindowAttrib(identifier, GLFW_ICONIFIED)))
- setWindowMode(WindowMode.MINIMIZED);
- else if (Miscellaneous.getBooleanizedInteger(glfwGetWindowAttrib(identifier, GLFW_MAXIMIZED)))
- setWindowMode(WindowMode.MAXIMIZED);
- else if (Miscellaneous.getBooleanizedInteger(glfwGetWindowAttrib(identifier, GLFW_VISIBLE)))
- setWindowMode(WindowMode.WINDOWED);
- else if (Miscellaneous.getBooleanizedInteger(glfwGetWindowAttrib(identifier, GLFW_VISIBLE)))
- setWindowMode(WindowMode.HIDDEN);
+ if (TypeConversion.integerToBoolean(glfwGetWindowAttrib(internalWindowIdentifier, GLFW_ICONIFIED)))
+ mode = Mode.MINIMIZED;
+ else if (TypeConversion.integerToBoolean(glfwGetWindowAttrib(internalWindowIdentifier, GLFW_MAXIMIZED)))
+ mode = Mode.MAXIMIZED;
+ else if (TypeConversion.integerToBoolean(glfwGetWindowAttrib(internalWindowIdentifier, GLFW_VISIBLE)))
+ mode = Mode.WINDOWED;
+ else if (TypeConversion.integerToBoolean(glfwGetWindowAttrib(internalWindowIdentifier, GLFW_VISIBLE)))
+ mode = Mode.HIDDEN;
// Update monitor
if (!getMonitor().isConnected()) {
@@ -638,10 +685,12 @@ public final class Window implements AutoCloseable {
if (monitor.isConnected())
newMonitor = monitor;
- if (newMonitor == null)
+ if (newMonitor == null) {
Logger.crash("Unable to set a new target monitor for window " + getUniqueIdentifier() + " as no monitors are connected to the system");
+ return;
+ }
- setMonitor(Objects.requireNonNull(newMonitor));
+ monitor = newMonitor;
}
// Update vectors
@@ -649,17 +698,17 @@ public final class Window implements AutoCloseable {
IntBuffer width = stack.mallocInt(2);
IntBuffer height = stack.mallocInt(2);
- glfwGetWindowSize(identifier, width, height);
- setSize(new Vec2i(width.get(), height.get()));
+ glfwGetWindowSize(internalWindowIdentifier, width, height);
+ size = new Vec2i(width.get(), height.get());
- glfwGetWindowPos(identifier, width, height);
- setPosition(new Vec2i(width.get(), height.get()));
+ glfwGetWindowPos(internalWindowIdentifier, width, height);
+ position = new Vec2i(width.get(), height.get());
}
// Update booleans
- setResizable(Miscellaneous.getBooleanizedInteger(glfwGetWindowAttrib(identifier, GLFW_RESIZABLE)));
- setOnTop(Miscellaneous.getBooleanizedInteger(glfwGetWindowAttrib(identifier, GLFW_FLOATING)));
- setTransparent(Miscellaneous.getBooleanizedInteger(glfwGetWindowAttrib(identifier, GLFW_TRANSPARENT_FRAMEBUFFER)));
+ resizable = TypeConversion.integerToBoolean(glfwGetWindowAttrib(internalWindowIdentifier, GLFW_RESIZABLE));
+ onTop = TypeConversion.integerToBoolean(glfwGetWindowAttrib(internalWindowIdentifier, GLFW_FLOATING));
+ transparent = TypeConversion.integerToBoolean(glfwGetWindowAttrib(internalWindowIdentifier, GLFW_TRANSPARENT_FRAMEBUFFER));
}
/**
@@ -672,18 +721,15 @@ public final class Window implements AutoCloseable {
* @since v1-alpha9
*/
public void render() throws NotOnMainThreadException {
- // Ensure running on the main thread
- if (!Miscellaneous.onMainThread())
- throw new NotOnMainThreadException();
-
// Ensure the window is not terminated
- if (isTerminated())
+ if (terminated)
return;
+
// Ensure rendering is enabled
if (!isRendering())
return;
- glfwSwapBuffers(identifier);
+ bgfx_set_view_rect(0, 0, 0, size.getX(), size.getY());
}
/**
@@ -696,8 +742,13 @@ public final class Window implements AutoCloseable {
if (!Miscellaneous.onMainThread())
throw new NotOnMainThreadException();
- closeInternal();
+ // Ensure the window is not terminated
+ if (terminated)
+ return;
+
+ windows.remove(this);
terminated = true;
+ closeInternal();
}
/**
@@ -709,11 +760,12 @@ public final class Window implements AutoCloseable {
*/
private void closeInternal() {
// Terminate bgfx
- bgfx_shutdown();
+ if (glfwGetPlatform() != GLFW_PLATFORM_NULL)
+ bgfx_shutdown();
// Destroy the window
- Callbacks.glfwFreeCallbacks(identifier);
- glfwDestroyWindow(identifier);
+ Callbacks.glfwFreeCallbacks(internalWindowIdentifier);
+ glfwDestroyWindow(internalWindowIdentifier);
}
/**
@@ -724,11 +776,15 @@ public final class Window implements AutoCloseable {
* @since v1-alpha9
*/
public boolean isClosureRequested() {
+ // Ensure running on the main thread
+ if (!Miscellaneous.onMainThread())
+ throw new NotOnMainThreadException();
+
// Ensure the window is not terminated
- if (isTerminated())
+ if (terminated)
return false;
- return glfwWindowShouldClose(identifier);
+ return glfwWindowShouldClose(internalWindowIdentifier);
}
/**
@@ -738,11 +794,15 @@ public final class Window implements AutoCloseable {
* @since v1-alpha9
*/
public boolean isFocused() {
+ // Ensure running on the main thread
+ if (!Miscellaneous.onMainThread())
+ throw new NotOnMainThreadException();
+
// Ensure the window is not terminated
- if (isTerminated())
+ if (terminated)
return false;
- return Miscellaneous.getTristatedInteger(glfwGetWindowAttrib(identifier, GLFW_FOCUSED)).toBoolean();
+ return TypeConversion.integerToBoolean(glfwGetWindowAttrib(internalWindowIdentifier, GLFW_FOCUSED));
}
/**
@@ -752,11 +812,15 @@ public final class Window implements AutoCloseable {
* @since v1-alpha9
*/
public void focus() {
+ // Ensure running on the main thread
+ if (!Miscellaneous.onMainThread())
+ throw new NotOnMainThreadException();
+
// Ensure the window is not terminated
- if (isTerminated())
+ if (terminated)
return;
- glfwFocusWindow(identifier);
+ glfwFocusWindow(internalWindowIdentifier);
}
/**
@@ -770,11 +834,15 @@ public final class Window implements AutoCloseable {
* @since v1-alpha9
*/
public void requestAttention() {
+ // Ensure running on the main thread
+ if (!Miscellaneous.onMainThread())
+ throw new NotOnMainThreadException();
+
// Ensure the window is not terminated
- if (isTerminated())
+ if (terminated)
return;
- glfwRequestWindowAttention(identifier);
+ glfwRequestWindowAttention(internalWindowIdentifier);
}
// -----> Setters & getters
@@ -801,7 +869,7 @@ public final class Window implements AutoCloseable {
*/
public void setName(@NotNull String name) {
// Ensure the window is not terminated
- if (isTerminated())
+ if (terminated)
return;
this.name = name;
@@ -816,11 +884,11 @@ public final class Window implements AutoCloseable {
*/
public void setTitle(@NotNull String title) {
// Ensure the window is not terminated
- if (isTerminated())
+ if (terminated)
return;
this.title = title;
- glfwSetWindowTitle(identifier, title);
+ glfwSetWindowTitle(internalWindowIdentifier, title);
}
/**
@@ -833,7 +901,7 @@ public final class Window implements AutoCloseable {
@ApiStatus.Experimental
public void setIcons(@NotNull Path @Nullable [] icons) {
// Ensure the window is not terminated
- if (isTerminated())
+ if (terminated)
return;
this.icons = icons;
@@ -873,7 +941,7 @@ public final class Window implements AutoCloseable {
iconsBuffer.position(0);
Logger.diag("setting icons");
Logger.flush();
- glfwSetWindowIcon(identifier, iconsBuffer);
+ glfwSetWindowIcon(internalWindowIdentifier, iconsBuffer);
// Free icons
Logger.diag("freeing icons");
@@ -894,11 +962,11 @@ public final class Window implements AutoCloseable {
*/
public void setSize(@NotNull Vec2i size) {
// Ensure the window is not terminated
- if (isTerminated())
+ if (terminated)
return;
this.size = size;
- glfwSetWindowSize(identifier, size.getX(), size.getY());
+ glfwSetWindowSize(internalWindowIdentifier, size.getX(), size.getY());
}
/**
@@ -911,11 +979,11 @@ public final class Window implements AutoCloseable {
*/
public void setMinimumSize(@NotNull Vec2i minimumSize) {
// Ensure the window is not terminated
- if (isTerminated())
+ if (terminated)
return;
this.minimumSize = minimumSize;
- glfwSetWindowSizeLimits(identifier, minimumSize.getX(), minimumSize.getY(), getMaximumSize().getX(), getMaximumSize().getY());
+ glfwSetWindowSizeLimits(internalWindowIdentifier, minimumSize.getX(), minimumSize.getY(), getMaximumSize().getX(), getMaximumSize().getY());
}
/**
@@ -928,11 +996,11 @@ public final class Window implements AutoCloseable {
*/
public void setMaximumSize(@NotNull Vec2i maximumSize) {
// Ensure the window is not terminated
- if (isTerminated())
+ if (terminated)
return;
this.maximumSize = maximumSize;
- glfwSetWindowSizeLimits(identifier, getMinimumSize().getX(), getMinimumSize().getY(), maximumSize.getX(), maximumSize.getY());
+ glfwSetWindowSizeLimits(internalWindowIdentifier, getMinimumSize().getX(), getMinimumSize().getY(), maximumSize.getX(), maximumSize.getY());
}
/**
@@ -943,49 +1011,50 @@ public final class Window implements AutoCloseable {
*/
public void setPosition(@NotNull Vec2i position) {
// Ensure the window is not terminated
- if (isTerminated())
+ if (isTerminated() || !RenderingSubsystemConfiguration.getInstance().isDebugAllowPositionUpdates())
return;
this.position = position;
- glfwSetWindowSize(identifier, position.getX(), position.getY());
+ glfwSetWindowSize(internalWindowIdentifier, position.getX(), position.getY());
}
/**
* Sets the window mode.
*
- * @param windowMode new mode
+ * @param mode new mode
* @since v1-alpha9
*/
- public void setWindowMode(@NotNull WindowMode windowMode) {
+ public void setMode(@NotNull Window.Mode mode) {
// Ensure the window is not terminated
- if (isTerminated())
+ if (terminated)
return;
- this.windowMode = windowMode;
- switch (windowMode) {
- case HIDDEN -> glfwHideWindow(identifier);
+ this.mode = mode;
+ switch (mode) {
+ case HIDDEN -> glfwHideWindow(internalWindowIdentifier);
case WINDOWED -> {
- glfwShowWindow(identifier);
- glfwRestoreWindow(identifier);
+ glfwShowWindow(internalWindowIdentifier);
+ glfwRestoreWindow(internalWindowIdentifier);
}
case MINIMIZED -> {
- glfwShowWindow(identifier);
- glfwIconifyWindow(identifier);
+ glfwShowWindow(internalWindowIdentifier);
+ glfwIconifyWindow(internalWindowIdentifier);
}
case MAXIMIZED -> {
- glfwShowWindow(identifier);
- glfwRestoreWindow(identifier);
- glfwMaximizeWindow(identifier);
+ glfwShowWindow(internalWindowIdentifier);
+ glfwRestoreWindow(internalWindowIdentifier);
+ glfwMaximizeWindow(internalWindowIdentifier);
}
case BORDERLESS_FULLSCREEN -> {
- glfwShowWindow(identifier);
- glfwRestoreWindow(identifier);
+ glfwShowWindow(internalWindowIdentifier);
+ glfwRestoreWindow(internalWindowIdentifier);
+ glfwSetWindowPos(internalWindowIdentifier, 0, 0);
// TODO
}
case EXCLUSIVE_FULLSCREEN -> {
- glfwShowWindow(identifier);
- glfwRestoreWindow(identifier);
- // TODO
+ glfwShowWindow(internalWindowIdentifier);
+ glfwRestoreWindow(internalWindowIdentifier);
+ glfwSetWindowPos(internalWindowIdentifier, 0, 0);
}
}
}
@@ -998,7 +1067,7 @@ public final class Window implements AutoCloseable {
*/
public void setResizable(boolean resizable) {
// Ensure the window is not terminated
- if (isTerminated())
+ if (terminated)
return;
this.resizable = resizable;
@@ -1012,7 +1081,7 @@ public final class Window implements AutoCloseable {
*/
public void setBorderless(boolean borderless) {
// Ensure the window is not terminated
- if (isTerminated())
+ if (terminated)
return;
this.borderless = borderless;
@@ -1026,7 +1095,7 @@ public final class Window implements AutoCloseable {
*/
public void setFocusable(boolean focusable) {
// Ensure the window is not terminated
- if (isTerminated())
+ if (terminated)
return;
this.focusable = focusable;
@@ -1040,7 +1109,7 @@ public final class Window implements AutoCloseable {
*/
public void setOnTop(boolean onTop) {
// Ensure the window is not terminated
- if (isTerminated())
+ if (terminated)
return;
this.onTop = onTop;
@@ -1057,14 +1126,79 @@ public final class Window implements AutoCloseable {
*/
public void setTransparent(boolean transparent) {
// Ensure the window is not terminated
- if (isTerminated())
+ if (terminated)
return;
this.transparent = transparent;
initializeWindow();
}
- // -----> Builder inner class
+ // -----> Inner classes
+ /**
+ * How a window can be displayed.
+ *
+ * @since v1-alpha9
+ */
+ public enum Mode {
+ /**
+ * Marks the window as hidden, making it invisible and unable to be interacted with.
+ *
+ * @since v1-alpha9
+ */
+ HIDDEN,
+
+ /**
+ * Marks the window as windowed, which
+ * will allow the user to drag around the window freely.
+ *
+ * @since v1-alpha9
+ */
+ WINDOWED,
+
+ /**
+ * Same as {@link #HIDDEN} mode, but the window can be
+ * summoned back into {@link #WINDOWED} mode by the user
+ * by (for example) clicking an icon or {@code ALT+TAB}-ing.
+ *
+ * @since v1-alpha9
+ */
+ MINIMIZED,
+
+ /**
+ * Same as {@link #WINDOWED}, but will make the window occupy
+ * most of the screen space, except for windows/bars/docks.
+ *
+ * @since v1-alpha9
+ */
+ MAXIMIZED,
+
+ /**
+ * Makes the window will have the same
+ * size as the monitor it is currently on.
+ *
+ * @since v1-alpha9
+ */
+ BORDERLESS_FULLSCREEN,
+
+ /**
+ * 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. Use (and recommend)
+ * this mode if you/your users
+ * want more frames per second.
+ *
+ * @since v1-alpha9
+ */
+ EXCLUSIVE_FULLSCREEN
+ }
+
/**
* Provides an API for building {@link Window}s more easily.
*
@@ -1131,10 +1265,10 @@ public final class Window implements AutoCloseable {
/**
* Contains the window mode.
*
- * @see Window#windowMode
+ * @see Window#mode
* @since v1-alpha9
*/
- private @Nullable WindowMode windowMode = null;
+ private @Nullable Window.Mode mode = null;
/**
* Contains the target monitor.
@@ -1235,8 +1369,8 @@ public final class Window implements AutoCloseable {
minimumSize = new Vec2i(-1, -1);
if (maximumSize == null)
maximumSize = new Vec2i(-1, -1);
- if (windowMode == null)
- windowMode = WindowMode.WINDOWED;
+ if (mode == null)
+ mode = Mode.WINDOWED;
if (monitor == null)
monitor = Monitor.getMonitors().getFirst();
@@ -1255,7 +1389,7 @@ public final class Window implements AutoCloseable {
renderingBoolean = false;
// Create new Window instance
- return new Window(name, title, icons, size, minimumSize, maximumSize, position, windowMode, monitor, resizableBoolean, borderlessBoolean, focusableBoolean, onTopBoolean, transparentBoolean, renderingBoolean);
+ return new Window(name, title, icons, size, minimumSize, maximumSize, position, mode, monitor, resizableBoolean, borderlessBoolean, focusableBoolean, onTopBoolean, transparentBoolean, renderingBoolean);
}
/**
@@ -1340,11 +1474,11 @@ public final class Window implements AutoCloseable {
* Returns the window mode.
*
* @return window mode
- * @see Window#windowMode
+ * @see Window#mode
* @since v1-alpha9
*/
- public @Nullable WindowMode getWindowMode() {
- return windowMode;
+ public @Nullable Window.Mode getWindowMode() {
+ return mode;
}
/**
@@ -1519,13 +1653,13 @@ public final class Window implements AutoCloseable {
/**
* Sets the window mode.
*
- * @param windowMode new window mode
+ * @param mode new window mode
* @return builder instance
- * @see Window#windowMode
+ * @see Window#mode
* @since v1-alpha9
*/
- public @NotNull Builder setWindowMode(@Nullable WindowMode windowMode) {
- this.windowMode = windowMode;
+ public @NotNull Builder setWindowMode(@Nullable Window.Mode mode) {
+ this.mode = mode;
return this;
}
diff --git a/rendering/src/main/java/de/staropensource/engine/rendering/type/window/WindowMode.java b/rendering/src/main/java/de/staropensource/engine/rendering/type/window/RenderingAdapter.java
similarity index 50%
rename from rendering/src/main/java/de/staropensource/engine/rendering/type/window/WindowMode.java
rename to rendering/src/main/java/de/staropensource/engine/rendering/type/window/RenderingAdapter.java
index 5276ccd..00ae02a 100644
--- a/rendering/src/main/java/de/staropensource/engine/rendering/type/window/WindowMode.java
+++ b/rendering/src/main/java/de/staropensource/engine/rendering/type/window/RenderingAdapter.java
@@ -20,66 +20,57 @@
package de.staropensource.engine.rendering.type.window;
/**
- * Contains how a window should be displayed.
+ * Represents all available rendering adapters.
*
* @since v1-alpha9
*/
-public enum WindowMode {
+public enum RenderingAdapter {
/**
- * Marks the window as hidden, making it invisible and unable to be interacted with.
+ * Allows the bgfx to autodetect the adapter to use.
*
* @since v1-alpha9
*/
- HIDDEN,
+ ANY,
/**
- * Marks the window as windowed, which
- * will allow the user to drag around the window freely.
+ * Tells bgfx to use the CPU for rendering.
*
* @since v1-alpha9
*/
- WINDOWED,
+ SOFTWARE,
/**
- * Same as {@link #HIDDEN} mode, but the window can be
- * summoned back into {@link #WINDOWED} mode by the user
- * by (for example) clicking an icon or {@code ALT+TAB}-ing.
+ * Tells bgfx to use AMD graphics cards for rendering.
*
* @since v1-alpha9
*/
- MINIMIZED,
+ AMD,
/**
- * Same as {@link #WINDOWED}, but will make the window occupy
- * most of the screen space, except for windows/bars/docks.
+ * Tells bgfx to use Apple's SOC for rendering.
*
* @since v1-alpha9
*/
- MAXIMIZED,
+ APPLE,
/**
- * Makes the window will have the same
- * size as the monitor it is currently on.
+ * Tells bgfx to use Intel graphics cards for rendering.
*
* @since v1-alpha9
*/
- BORDERLESS_FULLSCREEN,
+ INTEL,
/**
- * 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. Use (and recommend)
- * this mode if you/your users
- * want more frames per second.
+ * Tells bgfx to use NVIDIA graphics cards for rendering.
*
* @since v1-alpha9
*/
- EXCLUSIVE_FULLSCREEN
+ NVIDIA,
+
+ /**
+ * Tells bgfx to use Windows' integrated graphics driver for rendering.
+ *
+ * @since v1-alpha9
+ */
+ MICROSOFT,
}
diff --git a/rendering/src/main/java/de/staropensource/engine/rendering/type/window/RenderingPlatform.java b/rendering/src/main/java/de/staropensource/engine/rendering/type/window/RenderingPlatform.java
index 529ff57..15bada0 100644
--- a/rendering/src/main/java/de/staropensource/engine/rendering/type/window/RenderingPlatform.java
+++ b/rendering/src/main/java/de/staropensource/engine/rendering/type/window/RenderingPlatform.java
@@ -20,13 +20,13 @@
package de.staropensource.engine.rendering.type.window;
/**
- * Represents all available platforms.
+ * Represents all available rendering platforms.
*
* @since v1-alpha9
*/
public enum RenderingPlatform {
/**
- * Allows the subsystem to autodetect the platform to use.
+ * Allows GLFW to autodetect the platform to use.
*
* @since v1-alpha9
*/
@@ -61,7 +61,7 @@ public enum RenderingPlatform {
COCOA,
/**
- * Prefer initializing without any platform.
+ * Prefer initializing headless.
*
* @since v1-alpha9
*/
diff --git a/rendering/src/main/java/de/staropensource/engine/rendering/type/window/VsyncMode.java b/rendering/src/main/java/de/staropensource/engine/rendering/type/window/VsyncMode.java
index 9c09c9e..0bb7854 100644
--- a/rendering/src/main/java/de/staropensource/engine/rendering/type/window/VsyncMode.java
+++ b/rendering/src/main/java/de/staropensource/engine/rendering/type/window/VsyncMode.java
@@ -42,5 +42,10 @@ public enum VsyncMode {
*
* @since v1-alpha9
*/
- ON
+ ON,
+
+ /**
+ * Party
+ */
+ PARTY
}
diff --git a/rendering/src/main/java/module-info.java b/rendering/src/main/java/module-info.java
index 63fb1c7..8967a86 100644
--- a/rendering/src/main/java/module-info.java
+++ b/rendering/src/main/java/module-info.java
@@ -14,11 +14,13 @@ module sosengine.rendering {
requires org.lwjgl.stb;
requires org.lwjgl.glfw;
requires org.lwjgl.bgfx;
+ requires java.desktop;
// API access
exports de.staropensource.engine.rendering;
exports de.staropensource.engine.rendering.event;
exports de.staropensource.engine.rendering.exception;
+ exports de.staropensource.engine.rendering.renderer;
exports de.staropensource.engine.rendering.type;
exports de.staropensource.engine.rendering.type.input;
exports de.staropensource.engine.rendering.type.window;
@@ -27,6 +29,7 @@ module sosengine.rendering {
opens de.staropensource.engine.rendering;
opens de.staropensource.engine.rendering.event;
opens de.staropensource.engine.rendering.exception;
+ opens de.staropensource.engine.rendering.renderer;
opens de.staropensource.engine.rendering.type;
opens de.staropensource.engine.rendering.type.input;
opens de.staropensource.engine.rendering.type.window;
diff --git a/testapp/src/main/java/de/staropensource/engine/testapp/Main.java b/testapp/src/main/java/de/staropensource/engine/testapp/Main.java
index 8ae3103..5ca6461 100644
--- a/testapp/src/main/java/de/staropensource/engine/testapp/Main.java
+++ b/testapp/src/main/java/de/staropensource/engine/testapp/Main.java
@@ -25,9 +25,9 @@ import de.staropensource.engine.base.implementable.EventListenerCode;
import de.staropensource.engine.base.implementable.helper.EventHelper;
import de.staropensource.engine.base.logging.Logger;
import de.staropensource.engine.base.type.vector.Vec2i;
-import de.staropensource.engine.base.utility.misc.Miscellaneous;
-import de.staropensource.engine.rendering.RenderingSubsystem;
import de.staropensource.engine.rendering.event.InputEvent;
+import de.staropensource.engine.rendering.renderer.Renderer;
+import de.staropensource.engine.rendering.type.FrameHandler;
import de.staropensource.engine.rendering.type.Window;
import de.staropensource.engine.rendering.type.input.Key;
import de.staropensource.engine.rendering.type.input.KeyState;
@@ -35,8 +35,6 @@ import lombok.Getter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import java.util.LinkedHashMap;
-
/**
* The main class of the sos!engine development application.
*
@@ -140,14 +138,23 @@ public final class Main {
return;
}
- // Render loop
- LinkedHashMap<@NotNull Window, @NotNull Throwable> renderLoopFailures = RenderingSubsystem
- .getInstance()
- .runRenderLoop(() -> {
- if (shutdown || window.isClosureRequested())
- Engine.getInstance().shutdown();
- });
+ // Add frame handlers
+ Renderer.addFrameHandler(new FrameHandler() {
+ @Override
+ public @NotNull FrameHandler.Priority getPriority() {
+ return Priority.DEFAULT;
+ }
+ @Override
+ public void run() {
+ if (shutdown || window.isClosureRequested())
+ Engine.getInstance().shutdown();
+ //window.setPosition(new Vec2i((int) Renderer.getFrameCount() / 10, (int) Renderer.getFrameCount() / 10));
+ }
+ });
+
+ // Start renderer
+ Renderer.start();
} catch (Exception exception) {
Logger.crash("Caught throwable in main thread:", exception);
}