Update Window classes

This commit is contained in:
JeremyStar™ 2024-07-22 13:40:03 +02:00
parent 260464d727
commit 42d0feb574
Signed by: JeremyStarTM
GPG key ID: E366BAEF67E4704D
9 changed files with 705 additions and 171 deletions

View file

@ -130,7 +130,6 @@ public class GlfwSubsystem implements SubsystemMainClass {
glfwSetErrorCallback(null).free(); glfwSetErrorCallback(null).free();
} }
/** /**
* Called when the engine shuts down. * Called when the engine shuts down.
* *

View file

@ -0,0 +1,359 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Contributors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.sosengine.graphics.glfw.classes;
import de.staropensource.sosengine.base.exceptions.UnexpectedThrowableException;
import de.staropensource.sosengine.base.types.Tristate;
import de.staropensource.sosengine.base.types.vectors.Vec2i;
import de.staropensource.sosengine.base.utility.Miscellaneous;
import de.staropensource.sosengine.graphics.GraphicsSubsystemConfiguration;
import de.staropensource.sosengine.graphics.classes.Window;
import de.staropensource.sosengine.graphics.events.GraphicsApiErrorEvent;
import de.staropensource.sosengine.graphics.glfw.exceptions.NotOnMainThreadException;
import de.staropensource.sosengine.graphics.glfw.exceptions.WindowCreationFailureException;
import de.staropensource.sosengine.graphics.types.VsyncMode;
import de.staropensource.sosengine.graphics.types.WindowMode;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
import org.lwjgl.system.MemoryUtil;
import static org.lwjgl.glfw.GLFW.*;
/**
* A window on your screen.
*
* @since v1-alpha0
*/
@Getter
@SuppressWarnings({ "unused", "JavadocDeclaration", "JavadocBlankLines" })
public abstract class GlfwWindow extends Window {
/**
* Contains the {@link #identifier} as a long.
*
* @since v1-alpha2
*
* -- GETTER --
* Returns the window identifier as a long.
*
* @return window identifier as a long
* @since v1-alpha2
*/
private long identifierLong;
/**
* Creates a new window.
*
* @param name name
* @param title title
* @param size size
* @param minimumSize minimum size
* @param maximumSize maximum size
* @param position position
* @param windowMode window mode
* @param vsyncMode V-Sync mode
* @param resizable resizable flag
* @param borderless borderless flag
* @param focusable focusable flag
* @param onTop on top flag
* @param transparent transparency flag
* @param rendering rendering flag
* @throws UnexpectedThrowableException stuff thrown by the {@link #initializeWindow()} and {@link #render()} methods of the implementing Graphics API
* @since v1-alpha2
*/
public GlfwWindow(@NotNull String name, @NotNull String title, @NotNull Vec2i size, @NotNull Vec2i minimumSize, @NotNull Vec2i maximumSize, @NotNull Vec2i position, @NotNull WindowMode windowMode, @NotNull VsyncMode vsyncMode, boolean resizable, boolean borderless, boolean focusable, boolean onTop, boolean transparent, boolean rendering) throws UnexpectedThrowableException {
super(name, title, size, minimumSize, maximumSize, position, windowMode, vsyncMode, resizable, borderless, focusable, onTop, transparent, rendering);
}
/** {@inheritDoc} */
@Override
protected void initializeWindow() throws Throwable {
// Ensure running on the main thread
if (!Miscellaneous.onMainThread())
throw new NotOnMainThreadException();
createGlfwWindow(); // Create the GLFW window
initializeGlfwWindow(); // Call GLFW window initialization method
}
/**
* Initializes the GLFW window.
*
* @throws Throwable throwable
* @since v1-alpha2
*/
protected abstract void initializeGlfwWindow() throws Throwable;
/**
* Updates the window state.
*
* @since v1-alpha2
*/
@Override
public void updateState() {
// Ensure running on the main thread
if (!Miscellaneous.onMainThread())
throw new NotOnMainThreadException();
// Own context
ownContext();
// Set swap interval based on isDisallowTearing setting
glfwSwapInterval(Miscellaneous.getIntegerizedBoolean(GraphicsSubsystemConfiguration.getInstance().isDisallowTearing()));
// Integer arrays, used for 'size' and 'position'
int[] width = new int[0];
int[] height = new int[0];
// Set window size
glfwGetWindowSize(identifierLong, width, height);
super.setSize(new Vec2i(width[0], height[0]));
// Set window position
glfwGetWindowPos(identifierLong, width, height);
super.setPosition(new Vec2i(width[0], height[0]));
// Set window mode
if (Miscellaneous.getBooleanizedInteger(glfwGetWindowAttrib(identifierLong, GLFW_ICONIFIED)))
super.setWindowMode(WindowMode.MINIMIZED);
else if (Miscellaneous.getBooleanizedInteger(glfwGetWindowAttrib(identifierLong, GLFW_MAXIMIZED)))
super.setWindowMode(WindowMode.MAXIMIZED);
else if (Miscellaneous.getBooleanizedInteger(glfwGetWindowAttrib(identifierLong, GLFW_VISIBLE)))
super.setWindowMode(WindowMode.WINDOWED);
else if (Miscellaneous.getBooleanizedInteger(glfwGetWindowAttrib(identifierLong, GLFW_VISIBLE)))
super.setWindowMode(WindowMode.HIDDEN);
// Set booleans
super.setResizable(Miscellaneous.getBooleanizedInteger(glfwGetWindowAttrib(identifierLong, GLFW_RESIZABLE)));
super.setOnTop(Miscellaneous.getBooleanizedInteger(glfwGetWindowAttrib(identifierLong, GLFW_FLOATING)));
super.setTransparent(Miscellaneous.getBooleanizedInteger(glfwGetWindowAttrib(identifierLong, GLFW_TRANSPARENT_FRAMEBUFFER)));
// Make Graphics API update it's state
updateGlfwState();
}
/**
* Updates the state of the GLFW window.
*
* @throws Throwable throwable
* @since v1-alpha2
*/
protected abstract void updateGlfwState();
/** {@inheritDoc} */
@Override
public void render() throws NotOnMainThreadException {
// Ensure running on the main thread
if (!Miscellaneous.onMainThread())
throw new NotOnMainThreadException();
glfwSwapBuffers(identifierLong);
glfwPollEvents();
}
/** {@inheritDoc} */
@Override
public boolean isClosureRequested() {
return glfwWindowShouldClose(identifierLong);
}
/** {@inheritDoc} */
@Override
public boolean isFocused() {
return Tristate.toBoolean(Miscellaneous.getTristatedInteger(glfwGetWindowAttrib(identifierLong, GLFW_FOCUSED)));
}
/** {@inheritDoc} */
public void focus() {
glfwFocusWindow(identifierLong);
}
/** {@inheritDoc} */
public void requestAttention() {
glfwRequestWindowAttention(identifierLong);
}
/**
* Updates the OpenGL context.
*
* @since v1-alpha2
*/
public void ownContext() {
glfwMakeContextCurrent(identifierLong);
}
/**
* (Re-)Creates the GLFW window.
*
* @since v1-alpha2
*/
public void createGlfwWindow() throws WindowCreationFailureException {
// Get current focus
boolean focused = true;
// Destroy existing window
if (getIdentifier() != null) {
focused = isFocused();
glfwDestroyWindow(identifierLong);
}
// Set window hints
setWindowHints();
glfwWindowHint(GLFW_POSITION_X, getPosition().getX());
glfwWindowHint(GLFW_POSITION_Y, getPosition().getY());
glfwWindowHint(GLFW_CENTER_CURSOR, 0);
glfwWindowHint(GLFW_FOCUSED, Miscellaneous.getIntegerizedBoolean(focused));
glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, Miscellaneous.getIntegerizedBoolean(isTransparent()));
glfwWindowHint(GLFW_COCOA_GRAPHICS_SWITCHING, Miscellaneous.getIntegerizedBoolean(GraphicsSubsystemConfiguration.getInstance().isDisallowIntegratedGraphics()));
glfwWindowHintString(GLFW_WAYLAND_APP_ID, getName());
glfwWindowHintString(GLFW_X11_CLASS_NAME, getName());
glfwWindowHintString(GLFW_X11_INSTANCE_NAME, getName());
// Create window
long identifier = glfwCreateWindow(getSize().getX(), getSize().getY(), getTitle(), MemoryUtil.NULL, MemoryUtil.NULL);
if (identifier == MemoryUtil.NULL) {
new GraphicsApiErrorEvent().callEvent("Unable to create window: Identifier is null");
throw new WindowCreationFailureException();
}
// Set identifier
identifierLong = identifier;
setIdentifier(String.valueOf(identifier));
// Update the window state
setTitle(getTitle());
setSize(getSize());
setMinimumSize(getMinimumSize());
setMaximumSize(getMaximumSize());
setPosition(getPosition());
setWindowMode(getWindowMode());
}
/**
* Sets window hints.
*
* @since v1-alpha2
*/
public abstract void setWindowHints();
/** {@inheritDoc} */
@Override
public void setName(@NotNull String name) {
super.setName(name);
createGlfwWindow();
}
/** {@inheritDoc} */
@Override
public void setTitle(@NotNull String title) {
super.setTitle(title);
glfwSetWindowTitle(identifierLong, title);
}
/** {@inheritDoc} */
@Override
public void setSize(@NotNull Vec2i size) {
super.setSize(size);
glfwSetWindowSize(identifierLong, size.getX(), size.getY());
}
/** {@inheritDoc} */
@Override
public void setMinimumSize(@NotNull Vec2i minimumSize) {
super.setMinimumSize(minimumSize);
glfwSetWindowSizeLimits(identifierLong, minimumSize.getX(), minimumSize.getY(), getMaximumSize().getX(), getMaximumSize().getY());
}
/** {@inheritDoc} */
@Override
public void setMaximumSize(@NotNull Vec2i maximumSize) {
super.setMaximumSize(maximumSize);
glfwSetWindowSizeLimits(identifierLong, getMinimumSize().getX(), getMinimumSize().getY(), maximumSize.getX(), maximumSize.getY());
}
/** {@inheritDoc} */
@Override
public void setPosition(@NotNull Vec2i position) {
super.setPosition(position);
glfwSetWindowSize(identifierLong, position.getX(), position.getY());
}
/** {@inheritDoc} */
@Override
public void setWindowMode(@NotNull WindowMode windowMode) {
super.setWindowMode(windowMode);
switch (windowMode) {
case HIDDEN -> glfwHideWindow(identifierLong);
case WINDOWED -> {
glfwShowWindow(identifierLong);
glfwRestoreWindow(identifierLong);
}
case MINIMIZED -> {
glfwShowWindow(identifierLong);
glfwIconifyWindow(identifierLong);
}
case MAXIMIZED -> {
glfwShowWindow(identifierLong);
glfwRestoreWindow(identifierLong);
glfwMaximizeWindow(identifierLong);
}
case BORDERLESS_FULLSCREEN -> {
glfwShowWindow(identifierLong);
glfwRestoreWindow(identifierLong);
// TODO
}
case EXCLUSIVE_FULLSCREEN -> {
glfwShowWindow(identifierLong);
glfwRestoreWindow(identifierLong);
// TODO
}
}
}
/** {@inheritDoc} */
@Override
public void setResizable(boolean resizable) {
super.setResizable(resizable);
}
/** {@inheritDoc} */
@Override
public void setBorderless(boolean borderless) {
super.setBorderless(borderless);
}
/** {@inheritDoc} */
@Override
public void setFocusable(boolean focusable) {
super.setFocusable(focusable);
}
/** {@inheritDoc} */
@Override
public void setOnTop(boolean onTop) {
super.setOnTop(onTop);
}
/** {@inheritDoc} */
@Override
public void setTransparent(boolean transparent) {
super.setTransparent(transparent);
createGlfwWindow();
}
}

View file

@ -1,154 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Contributors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.sosengine.graphics.glfw.classes;
import de.staropensource.sosengine.base.exceptions.UnexpectedThrowableException;
import de.staropensource.sosengine.base.types.vectors.Vec2i;
import de.staropensource.sosengine.base.utility.Miscellaneous;
import de.staropensource.sosengine.graphics.events.GraphicsApiErrorEvent;
import de.staropensource.sosengine.graphics.glfw.exceptions.NotOnMainThreadException;
import de.staropensource.sosengine.graphics.glfw.exceptions.WindowCreationFailureException;
import de.staropensource.sosengine.graphics.types.VsyncMode;
import de.staropensource.sosengine.graphics.types.WindowMode;
import org.jetbrains.annotations.NotNull;
import org.lwjgl.system.MemoryUtil;
import static org.lwjgl.glfw.GLFW.*;
/**
* A window on your screen.
*
* @since v1-alpha0
*/
@SuppressWarnings({ "unused" })
public abstract class Window extends de.staropensource.sosengine.graphics.classes.Window {
/**
* Creates a new window.
*
* @param title title
* @param size size
* @param position position
* @param windowMode window mode
* @param vsyncMode V-Sync mode
* @param resizable resizable flag
* @param borderless borderless flag
* @param focusable focusable flag
* @param onTop on top flag
* @param transparent transparency flag
* @param rendering rendering flag
* @throws UnexpectedThrowableException stuff thrown by the {@link #initializeWindow()} of the Graphics API
* @since v1-alpha2
*/
public Window(@NotNull String title, @NotNull Vec2i size, @NotNull Vec2i position, @NotNull WindowMode windowMode, @NotNull VsyncMode vsyncMode, boolean resizable, boolean borderless, boolean focusable, boolean onTop, boolean transparent, boolean rendering) throws UnexpectedThrowableException {
super(title, size, position, windowMode, vsyncMode, resizable, borderless, focusable, onTop, transparent, rendering);
}
/** {@inheritDoc} */
@Override
protected void initializeWindow() throws Throwable {
// Ensure running on the main thread
if (!Miscellaneous.onMainThread())
throw new NotOnMainThreadException();
// Create window
long identifier = glfwCreateWindow(getSize().getX(), getSize().getY(), getTitle(), MemoryUtil.NULL, MemoryUtil.NULL);
if (identifier == MemoryUtil.NULL) {
new GraphicsApiErrorEvent().callEvent("Unable to create window: Identifier is null");
throw new WindowCreationFailureException();
}
// Set identifier
setIdentifier(String.valueOf(identifier));
// Call GLFW window initialization method
initializeGlfwWindow();
}
/**
* Initializes the GLFW window.
*
* @throws Throwable throwable
* @since v1-alpha2
*/
protected abstract void initializeGlfwWindow() throws Throwable;
/** {@inheritDoc} */
@Override
public void updateState() throws Throwable {
// Ensure running on the main thread
if (!Miscellaneous.onMainThread())
throw new NotOnMainThreadException();
ownContext(getIdentifierAsLong());
// Update window visibility
if (getWindowMode() == WindowMode.HIDDEN)
glfwHideWindow(getIdentifierAsLong());
else
glfwShowWindow(getIdentifierAsLong());
updateGlfwState();
}
/**
* Updates the state of the GLFW window.
*
* @throws Throwable throwable
* @since v1-alpha2
*/
protected abstract void updateGlfwState() throws Throwable;
/** {@inheritDoc} */
@Override
public void render() throws NotOnMainThreadException {
// Ensure running on the main thread
if (!Miscellaneous.onMainThread())
throw new NotOnMainThreadException();
glfwSwapBuffers(getIdentifierAsLong());
glfwPollEvents();
}
/** {@inheritDoc} */
@Override
public boolean isClosureRequested() {
return glfwWindowShouldClose(getIdentifierAsLong());
}
/**
* Returns the window identifier as a long.
*
* @return window identifier as a long
* @since v1-alpha2
*/
public long getIdentifierAsLong() {
return Long.parseLong(getIdentifier());
}
/**
* Updates the OpenGL context.
*
* @param identifier window to own the context of
* @since v1-alpha2
*/
public void ownContext(long identifier) {
glfwMakeContextCurrent(identifier);
}
}

View file

@ -21,6 +21,7 @@ package de.staropensource.sosengine.graphics.opengl;
import de.staropensource.sosengine.graphics.classes.ApiInternalClass; import de.staropensource.sosengine.graphics.classes.ApiInternalClass;
import de.staropensource.sosengine.graphics.classes.Window; import de.staropensource.sosengine.graphics.classes.Window;
import de.staropensource.sosengine.graphics.opengl.classes.OpenGlWindow;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public class OpenGlInternalApi implements ApiInternalClass { public class OpenGlInternalApi implements ApiInternalClass {
@ -28,6 +29,6 @@ public class OpenGlInternalApi implements ApiInternalClass {
@Override @Override
@NotNull @NotNull
public Class<? extends Window> getWindowClass() { public Class<? extends Window> getWindowClass() {
return de.staropensource.sosengine.graphics.opengl.classes.Window.class; return OpenGlWindow.class;
} }
} }

View file

@ -21,6 +21,7 @@ package de.staropensource.sosengine.graphics.opengl.classes;
import de.staropensource.sosengine.base.exceptions.UnexpectedThrowableException; import de.staropensource.sosengine.base.exceptions.UnexpectedThrowableException;
import de.staropensource.sosengine.base.types.vectors.Vec2i; import de.staropensource.sosengine.base.types.vectors.Vec2i;
import de.staropensource.sosengine.graphics.glfw.classes.GlfwWindow;
import de.staropensource.sosengine.graphics.glfw.exceptions.NotOnMainThreadException; import de.staropensource.sosengine.graphics.glfw.exceptions.NotOnMainThreadException;
import de.staropensource.sosengine.graphics.glfw.exceptions.WindowCreationFailureException; import de.staropensource.sosengine.graphics.glfw.exceptions.WindowCreationFailureException;
import de.staropensource.sosengine.graphics.types.VsyncMode; import de.staropensource.sosengine.graphics.types.VsyncMode;
@ -28,18 +29,23 @@ import de.staropensource.sosengine.graphics.types.WindowMode;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.lwjgl.opengl.GL; import org.lwjgl.opengl.GL;
import static org.lwjgl.glfw.GLFW.*;
/** /**
* A window on your screen. * A window on your screen.
* *
* @since v1-alpha0 * @since v1-alpha0
*/ */
@SuppressWarnings({ "unused" }) @SuppressWarnings({ "unused" })
public class Window extends de.staropensource.sosengine.graphics.glfw.classes.Window { public class OpenGlWindow extends GlfwWindow {
/** /**
* Creates a new window. * Creates a new window.
* *
* @param name name
* @param title title * @param title title
* @param size size * @param size size
* @param minimumSize minimum size
* @param maximumSize maximum size
* @param position position * @param position position
* @param windowMode window mode * @param windowMode window mode
* @param vsyncMode V-Sync mode * @param vsyncMode V-Sync mode
@ -49,17 +55,17 @@ public class Window extends de.staropensource.sosengine.graphics.glfw.classes.Wi
* @param onTop on top flag * @param onTop on top flag
* @param transparent transparency flag * @param transparent transparency flag
* @param rendering rendering flag * @param rendering rendering flag
* @throws UnexpectedThrowableException stuff thrown by the {@link #initializeWindow()} of the Graphics API * @throws UnexpectedThrowableException stuff thrown by the {@link #initializeWindow()} and {@link #render()} methods of the implementing Graphics API
* @since v1-alpha2 * @since v1-alpha2
*/ */
public Window(@NotNull String title, @NotNull Vec2i size, @NotNull Vec2i position, @NotNull WindowMode windowMode, @NotNull VsyncMode vsyncMode, boolean resizable, boolean borderless, boolean focusable, boolean onTop, boolean transparent, boolean rendering) throws UnexpectedThrowableException { public OpenGlWindow(@NotNull String name, @NotNull String title, @NotNull Vec2i size, @NotNull Vec2i minimumSize, @NotNull Vec2i maximumSize, @NotNull Vec2i position, @NotNull WindowMode windowMode, @NotNull VsyncMode vsyncMode, boolean resizable, boolean borderless, boolean focusable, boolean onTop, boolean transparent, boolean rendering) throws UnexpectedThrowableException {
super(title, size, position, windowMode, vsyncMode, resizable, borderless, focusable, onTop, transparent, rendering); super(name, title, size, minimumSize, maximumSize, position, windowMode, vsyncMode, resizable, borderless, focusable, onTop, transparent, rendering);
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public void initializeGlfwWindow() throws WindowCreationFailureException, NotOnMainThreadException { public void initializeGlfwWindow() throws WindowCreationFailureException, NotOnMainThreadException {
ownContext(getIdentifierAsLong()); // Own context ownContext(); // Own the context
GL.createCapabilities(); // Create OpenGL capabilities GL.createCapabilities(); // Create OpenGL capabilities
} }
@ -67,6 +73,16 @@ public class Window extends de.staropensource.sosengine.graphics.glfw.classes.Wi
@Override @Override
public void updateGlfwState() throws NotOnMainThreadException {} public void updateGlfwState() throws NotOnMainThreadException {}
/** {@inheritDoc} */
@Override
public void setWindowHints() {
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API);
glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API);
}
/** {@inheritDoc} */ /** {@inheritDoc} */
@NotNull @NotNull
@Override @Override

View file

@ -98,6 +98,36 @@ public final class GraphicsSubsystemConfiguration implements SubsystemConfigurat
*/ */
private boolean errorGraphicsError; private boolean errorGraphicsError;
/**
* If enabled, will make the Graphics API try to prevent tearing from happening.
*
* @since v1-alph2
*
* -- GETTER --
* Gets the value for {@link #disallowTearing}.
*
* @return variable value
* @see GraphicsSubsystemConfiguration#disallowTearing
* @since v1-alpha2
*/
private boolean disallowTearing;
/**
* If enabled, will make the Graphics API try to prevent using the integrated graphics card in your computer.
* <p>
* Will have no effect if no integrated or discrete graphics card is installed in the system.
*
* @since v1-alph2
*
* -- GETTER --
* Gets the value for {@link #disallowIntegratedGraphics}.
*
* @return variable value
* @see GraphicsSubsystemConfiguration#disallowIntegratedGraphics
* @since v1-alpha2
*/
private boolean disallowIntegratedGraphics;
/** /**
* Constructs this class. * Constructs this class.
* *
@ -132,6 +162,8 @@ public final class GraphicsSubsystemConfiguration implements SubsystemConfigurat
case "debug" -> debug = parser.getBoolean(group + property); case "debug" -> debug = parser.getBoolean(group + property);
case "errorGraphicsError" -> errorGraphicsError = parser.getBoolean(group + property); case "errorGraphicsError" -> errorGraphicsError = parser.getBoolean(group + property);
case "disallowTearing" -> disallowTearing = parser.getBoolean(group + property);
} }
} catch (NullPointerException ignored) {} } catch (NullPointerException ignored) {}
} }
@ -150,6 +182,8 @@ public final class GraphicsSubsystemConfiguration implements SubsystemConfigurat
debug = false; debug = false;
errorGraphicsError = true; errorGraphicsError = true;
disallowTearing = false;
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@ -162,6 +196,9 @@ public final class GraphicsSubsystemConfiguration implements SubsystemConfigurat
case "errorGraphicsError" -> { case "errorGraphicsError" -> {
return errorGraphicsError; return errorGraphicsError;
} }
case "disallowTearing" -> {
return disallowTearing;
}
default -> { default -> {
return null; return null;
} }

View file

@ -48,6 +48,7 @@ import java.util.Set;
* *
* @since v1-alpha0 * @since v1-alpha0
*/ */
// TODO monitors
@Getter @Getter
@SuppressWarnings({ "unused", "JavadocDeclaration", "JavadocBlankLines" }) @SuppressWarnings({ "unused", "JavadocDeclaration", "JavadocBlankLines" })
public abstract class Window { public abstract class Window {
@ -97,6 +98,69 @@ public abstract class Window {
@Setter(AccessLevel.PROTECTED) @Setter(AccessLevel.PROTECTED)
private String identifier = null; private String identifier = null;
/**
* Determines the name of this window.
* <p>
* Window names should:
* <ul>
* <li>be lowercase,</li>
* <li>be simple,</li>
* <li>be not very long,</li>
* <li>only contain letters, numbers, hyphens and dots, and</li>
* <li>represent the name of your application and window purpose (if your application supports multiple windows)</li>
* </ul>
* <p>
* On some platforms this may be used for window identification.
* A prime example of this is X11 and Wayland, where window
* managers and compositors can use this information to identify
* windows and customize them.
*
* @since v1-alpha1
*
* -- GETTER --
* Returns the name of this window.
* <p>
* Window names should:
* <ul>
* <li>be lowercase,</li>
* <li>be simple,</li>
* <li>be not very long,</li>
* <li>only contain letters, numbers, hyphens and dots, and</li>
* <li>represent the name of your application and window purpose (if your application supports multiple windows)</li>
* </ul>
* <p>
* On some platforms this may be used for window identification.
* A prime example of this is X11 and Wayland, where window
* managers and compositors can use this information to identify
* windows and customize them.
*
* @return window title
* @since v1-alpha2
*
* -- SETTER --
* Sets the name of this window.
* <p>
* Window names should:
* <ul>
* <li>be lowercase,</li>
* <li>be simple,</li>
* <li>be not very long,</li>
* <li>only contain letters, numbers, hyphens and dots, and</li>
* <li>represent the name of your application and window purpose (if your application supports multiple windows)</li>
* </ul>
* <p>
* On some platforms this may be used for window identification.
* A prime example of this is X11 and Wayland, where window
* managers and compositors can use this information to identify
* windows and customize them.
*
* @param name new window name
* @since v1-alpha2
*/
@NotNull
@Setter
private String name;
/** /**
* Determines the title of this window. * Determines the title of this window.
* *
@ -139,6 +203,48 @@ public abstract class Window {
@Setter @Setter
private Vec2i size; private Vec2i size;
/**
* Determines the minimum size of this window.
*
* @since v1-alpha1
*
* -- GETTER --
* Returns the minimum window size.
*
* @return minimum window size
* @since v1-alpha2
*
* -- SETTER --
* Sets the minimum window size.
*
* @param size new minimum window size
* @since v1-alpha2
*/
@NotNull
@Setter
private Vec2i minimumSize;
/**
* Determines the maximum size of this window.
*
* @since v1-alpha1
*
* -- GETTER --
* Returns the maximum window size.
*
* @return maximum window size
* @since v1-alpha2
*
* -- SETTER --
* Sets the maximum window size.
*
* @param size new maximum window size
* @since v1-alpha2
*/
@NotNull
@Setter
private Vec2i maximumSize;
/** /**
* Determines the position of this window. * Determines the position of this window.
* *
@ -202,6 +308,26 @@ public abstract class Window {
@Setter @Setter
private VsyncMode vsyncMode; private VsyncMode vsyncMode;
/**
* Determines how fast the window may update it's contents.
*
* @since v1-alpha1
*
* -- GETTER --
* Returns how fast the window may update it's contents.
*
* @return new window frame limit
* @since v1-alpha2
*
* -- SETTER --
* Sets how fast the window may update it's contents.
*
* @param framerate new window frame limit
* @since v1-alpha2
*/
@Setter
private int framerate;
/** /**
* Determines if this window can be resized by the user. * Determines if this window can be resized by the user.
* *
@ -343,8 +469,11 @@ public abstract class Window {
/** /**
* Creates a new window. * Creates a new window.
* *
* @param name name
* @param title title * @param title title
* @param size size * @param size size
* @param minimumSize minimum size
* @param maximumSize maximum size
* @param position position * @param position position
* @param windowMode window mode * @param windowMode window mode
* @param vsyncMode V-Sync mode * @param vsyncMode V-Sync mode
@ -354,15 +483,18 @@ public abstract class Window {
* @param onTop on top flag * @param onTop on top flag
* @param transparent transparency flag * @param transparent transparency flag
* @param rendering rendering flag * @param rendering rendering flag
* @throws UnexpectedThrowableException stuff thrown by the {@link #initializeWindow()}, {@link #updateState()} and {@link #render()} methods of the implementing Graphics API * @throws UnexpectedThrowableException stuff thrown by the {@link #initializeWindow()} and {@link #render()} methods of the implementing Graphics API
* @since v1-alpha2 * @since v1-alpha2
*/ */
public Window(@NotNull String title, @NotNull Vec2i size, @NotNull Vec2i position, @NotNull WindowMode windowMode, @NotNull VsyncMode vsyncMode, boolean resizable, boolean borderless, boolean focusable, boolean onTop, boolean transparent, boolean rendering) throws UnexpectedThrowableException { public Window(@NotNull String name, @NotNull String title, @NotNull Vec2i size, @NotNull Vec2i minimumSize, @NotNull Vec2i maximumSize, @NotNull Vec2i position, @NotNull WindowMode windowMode, @NotNull VsyncMode vsyncMode, boolean resizable, boolean borderless, boolean focusable, boolean onTop, boolean transparent, boolean rendering) throws UnexpectedThrowableException {
logger.diag("Creating new window with properties: title=\"" + title + "\" size=" + size + " position=" + position + " windowMode=" + windowMode + " vsyncMode=" + vsyncMode + " resizable=" + resizable + " borderless=" + borderless + " focusable=" + focusable + " onTop=" + onTop + " transparent=" + transparent + " rendering=" + rendering); 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 // Initialize variables
this.name = name;
this.title = title; this.title = title;
this.size = size; this.size = size;
this.minimumSize = minimumSize;
this.maximumSize = maximumSize;
this.position = position; this.position = position;
this.windowMode = windowMode; this.windowMode = windowMode;
this.vsyncMode = vsyncMode; this.vsyncMode = vsyncMode;
@ -442,6 +574,34 @@ public abstract class Window {
*/ */
public abstract boolean isClosureRequested(); public abstract boolean isClosureRequested();
/**
* Returns if the window is currently focused.
*
* @return {@code true} if focused, {@code false} otherwise
* @since v1-alpha2
*/
public abstract boolean isFocused();
/**
* Will cause the window to be focused immediately, even
* without any user input.
*
* @since v1-alpha2
*/
public abstract void focus();
/**
* Will request user attention.
* <p>
* What the window manager or compositor does
* with this request is uncertain. It may be
* ignored, or will cause the icon in some bar
* or dock flash or blink.
*
* @since v1-alpha2
*/
public abstract void requestAttention();
/** /**
* Provides an API for building {@link Window} classes more easily. * Provides an API for building {@link Window} classes more easily.
* *
@ -450,6 +610,22 @@ public abstract class Window {
@SuppressWarnings({ "unused", "JavadocDeclaration", "JavadocBlankLines" }) @SuppressWarnings({ "unused", "JavadocDeclaration", "JavadocBlankLines" })
@Getter @Getter
public static class Builder { public static class Builder {
/**
* Contains the window name.
*
* @see Window#name
* @since v1-alpha2
*
* -- GETTER --
* Returns the window name.
*
* @return window name
* @see Window#name
* @since v1-alpha2
*/
@Nullable
private String name = null;
/** /**
* Contains the window title. * Contains the window title.
* *
@ -482,6 +658,38 @@ public abstract class Window {
@Nullable @Nullable
private Vec2i size = null; private Vec2i size = null;
/**
* Contains the minimum window size.
*
* @see Window#minimumSize
* @since v1-alpha2
*
* -- GETTER --
* Returns the minimum window size.
*
* @return minimum window size
* @see Window#minimumSize
* @since v1-alpha2
*/
@Nullable
private Vec2i minimumSize = null;
/**
* Contains the maximum window size.
*
* @see Window#maximumSize
* @since v1-alpha2
*
* -- GETTER --
* Returns the maximum window size.
*
* @return maximum window size
* @see Window#maximumSize
* @since v1-alpha2
*/
@Nullable
private Vec2i maximumSize = null;
/** /**
* Contains the window position. * Contains the window position.
* *
@ -650,14 +858,20 @@ public abstract class Window {
boolean renderingBoolean = true; boolean renderingBoolean = true;
// Check for required fields // Check for required fields
if (title == null) if (name == null)
throw new IllegalStateException("The window name is unset"); throw new IllegalStateException("The window name is unset");
if (title == null)
throw new IllegalStateException("The window title is unset");
if (size == null) if (size == null)
throw new IllegalStateException("The window size is unset"); throw new IllegalStateException("The window size is unset");
if (position == null) if (position == null)
throw new IllegalStateException("The window position is unset"); throw new IllegalStateException("The window position is unset");
// Set default // Set defaults
if (minimumSize == null)
minimumSize = new Vec2i(0, 0);
if (maximumSize == null)
maximumSize = new Vec2i(0, 0);
if (windowMode == null) if (windowMode == null)
windowMode = WindowMode.WINDOWED; windowMode = WindowMode.WINDOWED;
if (vsyncMode == null) if (vsyncMode == null)
@ -680,13 +894,26 @@ public abstract class Window {
// Create new Window instance // Create new Window instance
try { try {
return GraphicsSubsystem.getInstance().getApi().getInternalApi().getWindowClass() 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) .getDeclaredConstructor(String.class, String.class, Vec2i.class, Vec2i.class, Vec2i.class, Vec2i.class, WindowMode.class, VsyncMode.class, Boolean.TYPE, Boolean.TYPE, Boolean.TYPE, Boolean.TYPE, Boolean.TYPE, Boolean.TYPE)
.newInstance(title, size, position, windowMode, vsyncMode, resizableBoolean, borderlessBoolean, focusableBoolean, onTopBoolean, transparentBoolean, renderingBoolean); .newInstance(name, title, size, minimumSize, maximumSize, position, windowMode, vsyncMode, resizableBoolean, borderlessBoolean, focusableBoolean, onTopBoolean, transparentBoolean, renderingBoolean);
} catch (Throwable throwable) { } catch (Throwable throwable) {
throw new UnexpectedThrowableException(throwable, "Window.Builder was unable to create new Window instance"); throw new UnexpectedThrowableException(throwable, "Window.Builder was unable to create new Window instance");
} }
} }
/**
* Sets the window name.
*
* @param name new window name
* @return builder instance
* @since v1-alpha2
*/
@NotNull
public synchronized Builder setName(@Nullable String name) {
this.name = name;
return this;
}
/** /**
* Sets the window title. * Sets the window title.
* *
@ -713,6 +940,32 @@ public abstract class Window {
return this; return this;
} }
/**
* Sets the minimum window size.
*
* @param minimumSize new minimum window size
* @return builder instance
* @since v1-alpha2
*/
@NotNull
public synchronized Builder setMinimumSize(@Nullable Vec2i minimumSize) {
this.minimumSize = minimumSize;
return this;
}
/**
* Sets the maximum window size.
*
* @param maximumSize new maximum window size
* @return builder instance
* @since v1-alpha2
*/
@NotNull
public synchronized Builder setMaximumSize(@Nullable Vec2i maximumSize) {
this.maximumSize = maximumSize;
return this;
}
/** /**
* Sets the window position. * Sets the window position.
* *

View file

@ -27,22 +27,40 @@ package de.staropensource.sosengine.graphics.types;
@SuppressWarnings({ "unused" }) @SuppressWarnings({ "unused" })
public enum WindowMode { public enum WindowMode {
/** /**
* Makes the window invisible and unable to be interacted with. * Marks the window as {@code hidden}, making the window invisible and unable to be interacted with.
* *
* @since v1-alpha2 * @since v1-alpha2
*/ */
HIDDEN, HIDDEN,
/** /**
* Makes the window able to be dragged around. * Marks the window as {@code windowed}, which
* will allow the user to drag around the window freely.
* *
* @since v1-alpha1 * @since v1-alpha1
*/ */
WINDOWED, WINDOWED,
/** /**
* Same as {@code WINDOWED} mode, but the window will have * Same as {@link #HIDDEN} mode, but the window can
* the same size as the monitor it is currently on. * be summoned back into {@link #WINDOWED} mode by the user.
*
* @since v1-alpha2
*/
MINIMIZED,
/**
* Same as {@link #WINDOWED}, but will make the window occupy
* most of the screen space, except for window manager/compositor
* windows/bars/docks.
*
* @since v1-alpha2
*/
MAXIMIZED,
/**
* Makes the window will have the same
* size as the monitor it is currently on.
* *
* @since v1-alpha1 * @since v1-alpha1
*/ */
@ -51,6 +69,10 @@ public enum WindowMode {
/** /**
* Makes the window occupy the entire monitor it is currently on * Makes the window occupy the entire monitor it is currently on
* without allowing other windows to occupy the same space. * without allowing other windows to occupy the same space.
* <p>
* This will increase rendering throughput as the window manager
* or compositor does not need to care about other windows occupying
* the same monitor.
* *
* @since v1-alpha1 * @since v1-alpha1
*/ */

View file

@ -114,6 +114,7 @@ public class Main {
// Create window // Create window
try { try {
Window window = new Window.Builder() Window window = new Window.Builder()
.setName("sosengine-testapp")
.setTitle("test application window") .setTitle("test application window")
.setSize(new Vec2i(960, 540)) .setSize(new Vec2i(960, 540))
.setPosition(new Vec2i(10, 10)) .setPosition(new Vec2i(10, 10))