Make GLFW subsystem standalone + remove unnecessary fluff

This commit is contained in:
JeremyStar™ 2024-08-20 22:07:49 +02:00
parent ae790dbd18
commit c90406dac9
Signed by: JeremyStarTM
GPG key ID: E366BAEF67E4704D
12 changed files with 139 additions and 186 deletions

View file

@ -43,6 +43,7 @@ dependencies {
implementation(project(":ansi"))
implementation(project(":slf4j-compat"))
implementation(project(":windowing"))
implementation(project(":windowing:glfw"))
}
// Fix delombok task

View file

@ -20,21 +20,26 @@
package de.staropensource.sosengine.windowing.glfw;
import de.staropensource.sosengine.base.annotations.EngineSubsystem;
import de.staropensource.sosengine.base.classes.SubsystemClass;
import de.staropensource.sosengine.base.data.information.EngineInformation;
import de.staropensource.sosengine.base.data.versioning.StarOpenSourceVersioningSystem;
import de.staropensource.sosengine.base.logging.LoggerInstance;
import de.staropensource.sosengine.base.types.DependencyVector;
import de.staropensource.sosengine.base.utility.Miscellaneous;
import de.staropensource.sosengine.windowing.WindowingSubsystem;
import de.staropensource.sosengine.windowing.classes.api.ApiClass;
import de.staropensource.sosengine.windowing.classes.api.ApiInternalClass;
import de.staropensource.sosengine.windowing.classes.api.ApiManagementClass;
import de.staropensource.sosengine.windowing.events.WindowingErrorEvent;
import de.staropensource.sosengine.windowing.exceptions.NotOnMainThreadException;
import de.staropensource.sosengine.windowing.glfw.exceptions.GlfwInitializationException;
import de.staropensource.sosengine.windowing.glfw.classes.GlfwInternalClass;
import de.staropensource.sosengine.windowing.glfw.classes.GlfwManagementClass;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.glfw.GLFWErrorCallbackI;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import static org.lwjgl.glfw.GLFW.*;
@ -46,7 +51,7 @@ import static org.lwjgl.glfw.GLFW.*;
*/
@EngineSubsystem
@SuppressWarnings({ "JavadocDeclaration" })
public final class GlfwSubsystem extends SubsystemClass {
public final class GlfwSubsystem extends ApiClass {
/**
* Contains the class instance.
*
@ -68,6 +73,28 @@ public final class GlfwSubsystem extends SubsystemClass {
*/
private final LoggerInstance logger = new LoggerInstance.Builder().setClazz(getClass()).setOrigin("ENGINE").build();
/**
* Contains the internal API class.
*
* @see ApiInternalClass
* @since v1-alpha4
* -- GETTER --
* {@inheritDoc}
*/
@Getter
private ApiInternalClass internalApi;
/**
* Contains the management class.
*
* @see ApiManagementClass
* @since v1-alpha4
* -- GETTER --
* {@inheritDoc}
*/
@Getter
private ApiManagementClass management;
/**
* The {@link GLFWErrorCallback} to use.
* <p>
@ -96,39 +123,19 @@ public final class GlfwSubsystem extends SubsystemClass {
instance.logger.crash("The subsystem tried to initialize twice");
}
/** {@inheritDoc} */
@Override
public @NotNull String getName() {
return "glfw";
}
/** {@inheritDoc} */
@Override
public void initializeSubsystem() {
// Initialize configuration
new GlfwSubsystemConfiguration();
// Register API
WindowingSubsystem.getInstance().registerApi(this);
}
/** {@inheritDoc} */
@Override
public @NotNull DependencyVector getDependencyVector() {
Set<@NotNull String> dependencies = new HashSet<>();
dependencies.add("windowing");
return new DependencyVector.Builder()
.setIdentifier(getName())
.setVersioningSystem(StarOpenSourceVersioningSystem.class)
.setVersion(EngineInformation.getVersioningString())
.setDependencies(dependencies)
.build();
}
/**
* Initializes GLFW.
*
* @since v1-alpha2
*/
public void initializeGlfw() {
public void initializeApi() {
logger.verb("Initializing GLFW");
if (!Miscellaneous.onMainThread()) {
@ -152,24 +159,50 @@ public final class GlfwSubsystem extends SubsystemClass {
// Initialize GLFW
if (!glfwInit())
throw new GlfwInitializationException();
logger.crash("Failed to initialize GLFW");
// Initialize classes
internalApi = new GlfwInternalClass();
management = new GlfwManagementClass();
}
/**
* Terminates GLFW.
*
* @since v1-alpha2
*/
public void terminateGlfw() {
/** {@inheritDoc} */
@Override
public void shutdownApi() {
logger.verb("Terminating GLFW");
if (!Miscellaneous.onMainThread()) {
logger.crash("Unable to terminate GLFW on a non-main thread. Did you call Engine#shutdown or Logger#crash from another thread?", new NotOnMainThreadException(), true);
return;
}
glfwTerminate();
errorCallback.free();
if (Miscellaneous.onMainThread())
glfwTerminate();
else
logger.crash("Unable to terminate GLFW on a non-main thread. Did you call Engine#shutdown or Logger#crash from another thread?", new NotOnMainThreadException(), true);
}
/** {@inheritDoc} */
@Override
public @NotNull String getName() {
return getApiName().toLowerCase(Locale.ROOT);
}
/** {@inheritDoc} */
@Override
public String getApiName() {
return "GLFW";
}
/** {@inheritDoc} */
@Override
public @NotNull DependencyVector getDependencyVector() {
Set<@NotNull String> dependencies = new HashSet<>();
dependencies.add("windowing");
return new DependencyVector.Builder()
.setIdentifier(getName())
.setVersioningSystem(StarOpenSourceVersioningSystem.class)
.setVersion(EngineInformation.getVersioningString())
.setDependencies(dependencies)
.build();
}
/**

View file

@ -24,10 +24,10 @@ import de.staropensource.sosengine.windowing.classes.Monitor;
import de.staropensource.sosengine.windowing.classes.api.ApiInternalClass;
import de.staropensource.sosengine.windowing.exceptions.NoMonitorsFoundException;
import lombok.Getter;
import lombok.Setter;
import org.jetbrains.annotations.NotNull;
import org.lwjgl.PointerBuffer;
import java.lang.reflect.InvocationTargetException;
import java.util.LinkedHashSet;
import static org.lwjgl.glfw.GLFW.glfwGetMonitors;
@ -39,7 +39,7 @@ import static org.lwjgl.glfw.GLFW.glfwGetMonitors;
*/
@Getter
@SuppressWarnings({ "JavadocDeclaration" })
public abstract class GlfwInternalClass implements ApiInternalClass {
public final class GlfwInternalClass implements ApiInternalClass {
/**
* Contains the {@link LoggerInstance} for this instance.
*
@ -54,6 +54,22 @@ public abstract class GlfwInternalClass implements ApiInternalClass {
*/
private final LoggerInstance logger = new LoggerInstance.Builder().setClazz(getClass()).setOrigin("ENGINE").build();
/**
* Contains a class which extends the {@link GlfwWindow} class.
*
* @since v1-alpha4
* -- GETTER --
* {@inheritDoc}
* -- SETTER --
* Sets a class which extends the {@link GlfwWindow} class.
*
* @param windowClass new window class
* @since v1-alpha4
*/
@Getter
@Setter
private @NotNull Class<? extends GlfwWindow> windowClass = GlfwWindow.class;
/**
* Constructs this class.
*
@ -61,14 +77,6 @@ public abstract class GlfwInternalClass implements ApiInternalClass {
*/
public GlfwInternalClass() {}
/**
* Returns the {@link Monitor} class.
*
* @return {@link Monitor} class
* @since v1-alpha2
*/
public abstract @NotNull Class<? extends Monitor> getMonitorClass();
/**
* Returns all connected monitors.
*
@ -83,11 +91,7 @@ public abstract class GlfwInternalClass implements ApiInternalClass {
throw new NoMonitorsFoundException();
while (monitors.hasRemaining())
try {
output.add(getMonitorClass().getDeclaredConstructor(Long.TYPE).newInstance(monitors.get()));
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException exception) {
logger.crash("Unable to create new Monitor instance: Threw an exception", exception);
}
output.add(new GlfwMonitor(monitors.get()));
return output;
}

View file

@ -37,7 +37,7 @@ import static org.lwjgl.glfw.GLFW.*;
* @since v1-alpha2
*/
@Getter
public abstract class GlfwManagementClass extends ApiManagementClass {
public final class GlfwManagementClass extends ApiManagementClass {
/**
* Contains the {@link LoggerInstance} for this class.
*

View file

@ -36,7 +36,7 @@ import static org.lwjgl.glfw.GLFW.*;
* @since v1-alpha2
*/
@SuppressWarnings({ "JavadocDeclaration" })
public class GlfwMonitor extends Monitor {
public final class GlfwMonitor extends Monitor {
/**
* Contains the {@link #identifier} as a long.
*

View file

@ -52,7 +52,7 @@ import static org.lwjgl.glfw.GLFW.*;
* @since v1-alpha2
*/
@SuppressWarnings({ "JavadocDeclaration" })
public abstract class GlfwWindow extends Window {
public class GlfwWindow extends Window {
/**
* Contains the {@link #identifier} used by GLFW.
*
@ -101,13 +101,13 @@ public abstract class GlfwWindow extends Window {
* @throws UnexpectedThrowableException stuff thrown by the {@link #initializeWindow()} and {@link #render()} methods of the implementing windowing API
* @since v1-alpha2
*/
protected GlfwWindow(@NotNull String name, @NotNull String title, @NotNull Vec2i size, @NotNull Vec2i minimumSize, @NotNull Vec2i maximumSize, @NotNull Vec2i position, @NotNull WindowMode windowMode, @NotNull Monitor monitor, boolean resizable, boolean borderless, boolean focusable, boolean onTop, boolean transparent, boolean rendering) throws UnexpectedThrowableException {
public GlfwWindow(@NotNull String name, @NotNull String title, @NotNull Vec2i size, @NotNull Vec2i minimumSize, @NotNull Vec2i maximumSize, @NotNull Vec2i position, @NotNull WindowMode windowMode, @NotNull Monitor monitor, boolean resizable, boolean borderless, boolean focusable, boolean onTop, boolean transparent, boolean rendering) throws UnexpectedThrowableException {
super(name, title, size, minimumSize, maximumSize, position, windowMode, monitor, resizable, borderless, focusable, onTop, transparent, rendering);
}
/** {@inheritDoc} */
@Override
protected void initializeWindow() throws Throwable {
protected final void initializeWindow() throws Throwable {
createGlfwWindow(); // Create the GLFW window
initializeGlfwWindow(); // Call GLFW window initialization method
}
@ -118,14 +118,15 @@ public abstract class GlfwWindow extends Window {
* @throws Throwable throwable
* @since v1-alpha2
*/
protected abstract void initializeGlfwWindow() throws Throwable;
@SuppressWarnings("RedundantThrows") // done on purpose
protected void initializeGlfwWindow() throws Throwable {}
/**
* (Re-)Creates the associated GLFW window.
*
* @since v1-alpha2
*/
public void createGlfwWindow() throws WindowCreationFailureException {
public final void createGlfwWindow() throws WindowCreationFailureException {
// Ensure running on the main thread
if (!Miscellaneous.onMainThread())
throw new NotOnMainThreadException();
@ -187,14 +188,14 @@ public abstract class GlfwWindow extends Window {
*
* @since v1-alpha2
*/
protected abstract void setWindowHints();
protected void setWindowHints() {}
/**
* Closes the associated GLFW window.
*
* @since v1-alpha2
*/
public void closeGlfwWindow() throws WindowCreationFailureException {
public final void closeGlfwWindow() throws WindowCreationFailureException {
// Ensure running on the main thread
if (!Miscellaneous.onMainThread())
throw new NotOnMainThreadException();
@ -208,7 +209,7 @@ public abstract class GlfwWindow extends Window {
}
/** {@inheritDoc} */
public void terminate() {
public final void terminate() {
setTerminated(true);
closeGlfwWindow();
}
@ -220,7 +221,7 @@ public abstract class GlfwWindow extends Window {
* @since v1-alpha2
*/
@Override
public void updateState() {
public final void updateState() {
// Ensure the window is not terminated
if (isTerminated())
return;
@ -280,12 +281,12 @@ public abstract class GlfwWindow extends Window {
* @throws Throwable throwable
* @since v1-alpha2
*/
protected abstract void updateGlfwState();
protected void updateGlfwState() {}
// ------------------------------------------------ [ Rendering ] ------------------------------------------------ //
/** {@inheritDoc} */
@Override
public void render() throws NotOnMainThreadException {
public final void render() throws NotOnMainThreadException {
// Ensure the window is not terminated
if (isTerminated())
return;
@ -306,14 +307,14 @@ public abstract class GlfwWindow extends Window {
*
* @since v1-alpha2
*/
public void ownContext() {
public final void ownContext() {
glfwMakeContextCurrent(identifierLong);
}
// ------------------------------------------------ [ Information/Action methods ] ------------------------------------------------ //
/** {@inheritDoc} */
@Override
public boolean isClosureRequested() {
public final boolean isClosureRequested() {
// Ensure the window is not terminated
if (isTerminated())
return false;
@ -323,7 +324,7 @@ public abstract class GlfwWindow extends Window {
/** {@inheritDoc} */
@Override
public boolean isFocused() {
public final boolean isFocused() {
// Ensure the window is not terminated
if (isTerminated())
return false;
@ -332,7 +333,7 @@ public abstract class GlfwWindow extends Window {
}
/** {@inheritDoc} */
public void focus() {
public final void focus() {
// Ensure the window is not terminated
if (isTerminated())
return;
@ -341,7 +342,7 @@ public abstract class GlfwWindow extends Window {
}
/** {@inheritDoc} */
public void requestAttention() {
public final void requestAttention() {
// Ensure the window is not terminated
if (isTerminated())
return;
@ -353,7 +354,7 @@ public abstract class GlfwWindow extends Window {
/** {@inheritDoc} */
@Override
public void setName(@NotNull String name) {
public final void setName(@NotNull String name) {
// Ensure the window is not terminated
if (isTerminated())
return;
@ -364,7 +365,7 @@ public abstract class GlfwWindow extends Window {
/** {@inheritDoc} */
@Override
public void setTitle(@NotNull String title) {
public final void setTitle(@NotNull String title) {
// Ensure the window is not terminated
if (isTerminated())
return;
@ -375,7 +376,7 @@ public abstract class GlfwWindow extends Window {
/** {@inheritDoc} */
@Override
public void setSize(@NotNull Vec2i size) {
public final void setSize(@NotNull Vec2i size) {
// Ensure the window is not terminated
if (isTerminated())
return;
@ -386,7 +387,7 @@ public abstract class GlfwWindow extends Window {
/** {@inheritDoc} */
@Override
public void setMinimumSize(@NotNull Vec2i minimumSize) {
public final void setMinimumSize(@NotNull Vec2i minimumSize) {
// Ensure the window is not terminated
if (isTerminated())
return;
@ -397,7 +398,7 @@ public abstract class GlfwWindow extends Window {
/** {@inheritDoc} */
@Override
public void setMaximumSize(@NotNull Vec2i maximumSize) {
public final void setMaximumSize(@NotNull Vec2i maximumSize) {
// Ensure the window is not terminated
if (isTerminated())
return;
@ -408,7 +409,7 @@ public abstract class GlfwWindow extends Window {
/** {@inheritDoc} */
@Override
public void setPosition(@NotNull Vec2i position) {
public final void setPosition(@NotNull Vec2i position) {
// Ensure the window is not terminated
if (isTerminated())
return;
@ -419,7 +420,7 @@ public abstract class GlfwWindow extends Window {
/** {@inheritDoc} */
@Override
public void setWindowMode(@NotNull WindowMode windowMode) {
public final void setWindowMode(@NotNull WindowMode windowMode) {
// Ensure the window is not terminated
if (isTerminated())
return;
@ -455,7 +456,7 @@ public abstract class GlfwWindow extends Window {
/** {@inheritDoc} */
@Override
public void setResizable(boolean resizable) {
public final void setResizable(boolean resizable) {
// Ensure the window is not terminated
if (isTerminated())
return;
@ -465,7 +466,7 @@ public abstract class GlfwWindow extends Window {
/** {@inheritDoc} */
@Override
public void setBorderless(boolean borderless) {
public final void setBorderless(boolean borderless) {
// Ensure the window is not terminated
if (isTerminated())
return;
@ -475,7 +476,7 @@ public abstract class GlfwWindow extends Window {
/** {@inheritDoc} */
@Override
public void setFocusable(boolean focusable) {
public final void setFocusable(boolean focusable) {
// Ensure the window is not terminated
if (isTerminated())
return;
@ -485,7 +486,7 @@ public abstract class GlfwWindow extends Window {
/** {@inheritDoc} */
@Override
public void setOnTop(boolean onTop) {
public final void setOnTop(boolean onTop) {
// Ensure the window is not terminated
if (isTerminated())
return;
@ -495,7 +496,7 @@ public abstract class GlfwWindow extends Window {
/** {@inheritDoc} */
@Override
public void setTransparent(boolean transparent) {
public final void setTransparent(boolean transparent) {
// Ensure the window is not terminated
if (isTerminated())
return;

View file

@ -31,7 +31,7 @@ import org.jetbrains.annotations.NotNull;
*/
@Getter
@SuppressWarnings({ "JavadocDeclaration" })
public abstract class WindowCallback {
public class WindowCallback {
/**
* Refers to the {@link Window} instance
* this callback is tied to.

View file

@ -1,34 +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 <https://www.gnu.org/licenses/>.
*/
package de.staropensource.sosengine.windowing.glfw.exceptions;
/**
* Thrown when GLFW fails to initialize.
*
* @since v1-alpha2
*/
public final class GlfwInitializationException extends RuntimeException {
/**
* Constructs this exception.
*
* @since v1-alpha2
*/
public GlfwInitializationException() {}
}

View file

@ -1,25 +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 <https://www.gnu.org/licenses/>.
*/
/**
* Exceptions thrown by the GLFW subsystem.
*
* @since v1-alpha2
*/
package de.staropensource.sosengine.windowing.glfw.exceptions;

View file

@ -20,10 +20,8 @@ module sosengine.windowing.glfw {
// API access
exports de.staropensource.sosengine.windowing.glfw;
exports de.staropensource.sosengine.windowing.glfw.classes;
exports de.staropensource.sosengine.windowing.glfw.exceptions;
// Reflection access
opens de.staropensource.sosengine.windowing.glfw;
opens de.staropensource.sosengine.windowing.glfw.classes;
opens de.staropensource.sosengine.windowing.glfw.exceptions;
}

View file

@ -28,19 +28,16 @@ import de.staropensource.sosengine.base.data.versioning.StarOpenSourceVersioning
import de.staropensource.sosengine.base.internal.events.InternalEngineShutdownEvent;
import de.staropensource.sosengine.base.logging.LoggerInstance;
import de.staropensource.sosengine.base.types.DependencyVector;
import de.staropensource.sosengine.base.utility.ListFormatter;
import de.staropensource.sosengine.base.utility.Miscellaneous;
import de.staropensource.sosengine.windowing.classes.api.ApiClass;
import de.staropensource.sosengine.windowing.events.RenderingErrorEvent;
import de.staropensource.sosengine.windowing.events.WindowingShutdownEvent;
import de.staropensource.sosengine.windowing.events.WindowingErrorEvent;
import de.staropensource.sosengine.windowing.events.InputEvent;
import de.staropensource.sosengine.windowing.events.RenderingErrorEvent;
import de.staropensource.sosengine.windowing.events.WindowingErrorEvent;
import de.staropensource.sosengine.windowing.events.WindowingShutdownEvent;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
@ -173,7 +170,7 @@ public final class WindowingSubsystem extends SubsystemClass {
* Registers a windowing API.
*
* @param mainClass main class of the windowing API
* @since v1-alpha0
* @since v1-alpha4
*/
public void registerApi(@NotNull ApiClass mainClass) {
logger.verb("Registering windowing API " + mainClass.getApiName() + " (" + mainClass.getClass().getName() + ")");
@ -189,36 +186,21 @@ public final class WindowingSubsystem extends SubsystemClass {
*
* @return if a compatible windowing API has been chosen
* @see #setApi(String)
* @since v1-alpha0
* @since v1-alpha4
*/
public boolean setApi() {
logger.verb("Choosing a compatible windowing API");
logger.verb("Choosing a windowing API");
List<@NotNull String> compatibleApis = new ArrayList<>();
// Check if registered apis are compatible
for (String apiName : registeredApis.keySet())
if (registeredApis.get(apiName).isCompatible()) {
logger.diag(apiName + " is compatible with this system");
compatibleApis.add(apiName);
} else
logger.diag(apiName + " is incompatible with this system");
if (compatibleApis.isEmpty()) {
logger.error("No compatible windowing API was found");
if (registeredApis.isEmpty())
return false;
} else if (compatibleApis.size() == 1)
logger.diag("Compatible is " + compatibleApis.getFirst());
else
logger.diag("Compatible are " + ListFormatter.formatList(compatibleApis));
// Choose last item in list.
api = registeredApis.get(compatibleApis.getLast());
// Initialize first API in list.
api = registeredApis.get(registeredApis.keySet().toArray(new String[0])[0]);
try {
logger.diag("Initializing windowing API");
logger.diag("Initialized windowing API in " + Miscellaneous.measureExecutionTime(() -> api.initializeApi()) + "ms");
logger.diag("Initializing windowing API \"" + api.getApiName() + "\"");
logger.diag("Initialized windowing API \"" + api.getApiName() + "\" in " + Miscellaneous.measureExecutionTime(() -> api.initializeApi()) + "ms");
} catch (Throwable throwable) {
logger.crash("windowing API failed to initialize", throwable, true);
logger.crash("Windowing API \"" + api.getApiName() + "\" failed to initialize", throwable, true);
throw throwable;
}
@ -231,8 +213,9 @@ public final class WindowingSubsystem extends SubsystemClass {
* @param name name of the windowing API
* @return if the windowing API has been found
* @see #setApi()
* @since v1-alpha0
* @since v1-alpha4
*/
@SuppressWarnings({ "unused" })
public boolean setApi(@NotNull String name) {
if (!registeredApis.containsKey(name))
return false;

View file

@ -81,12 +81,4 @@ public abstract class ApiClass extends SubsystemClass {
*/
@NotNull
public abstract ApiManagementClass getManagement();
/**
* Checks if the windowing API is compatible with the underlying hardware.
*
* @return if the windowing API is compatible
* @since v1-alpha0
*/
public abstract boolean isCompatible();
}