diff --git a/UPDATE_NOTES.md b/UPDATE_NOTES.md index f4591a3..95c0ad9 100644 --- a/UPDATE_NOTES.md +++ b/UPDATE_NOTES.md @@ -13,6 +13,9 @@ * Renamed `VertexArray#getVertexAttribs` to `VertexArray#getVertexAttributes` * `[PlutoCore]` Made `PlutoApplication.StartupConfig` fields private, options can now only be modified only through public setters +* `[PlutoLib]` Added the `ThreadSensitive` annotation +* `[PlutoCore]` Refactored `InputBus` and added several convenience methods + * `[PlutoCore]` Refactored input callbacks ## 20.2.0.0-alpha.1 * `[PlutoLib#cz.tefek.pluto.io.logger]` Refactored the Logger subsystem diff --git a/plutocore/src/main/java/cz/tefek/pluto/engine/input/InputBus.java b/plutocore/src/main/java/cz/tefek/pluto/engine/input/InputBus.java index b6e98dd..d555550 100644 --- a/plutocore/src/main/java/cz/tefek/pluto/engine/input/InputBus.java +++ b/plutocore/src/main/java/cz/tefek/pluto/engine/input/InputBus.java @@ -2,156 +2,157 @@ package cz.tefek.pluto.engine.input; import org.lwjgl.glfw.GLFW; -import javax.annotation.concurrent.ThreadSafe; - +import cz.tefek.pluto.annotation.ThreadSensitive; import cz.tefek.pluto.engine.display.Display; -@ThreadSafe +@ThreadSensitive(localContexts = true) public class InputBus { - private static ThreadLocal keyboard = new ThreadLocal<>(); - private static ThreadLocal mouseButton = new ThreadLocal<>(); - private static ThreadLocal cursorPosition = new ThreadLocal<>(); - private static ThreadLocal scroll = new ThreadLocal<>(); - private static ThreadLocal charInput = new ThreadLocal<>(); + private static final ThreadLocal INSTANCE = new ThreadLocal<>(); + + private final KeyboardInputCallback keyboard = new KeyboardInputCallback(); + private final MouseButtonCallback mouseButton = new MouseButtonCallback(); + private final CursorPositionCallback cursorPosition = new CursorPositionCallback(); + private final ScrollInputCallback scroll = new ScrollInputCallback(); + private final KeyboardCharInput charInput = new KeyboardCharInput(); + + private InputBus() + { + } public static void init(Display display) { - keyboard.set(new KeyboardInputCallback()); - GLFW.glfwSetKeyCallback(display.getWindowPointer(), keyboard.get()); - - mouseButton.set(new MouseButtonCallback()); - GLFW.glfwSetMouseButtonCallback(display.getWindowPointer(), mouseButton.get()); - - cursorPosition.set(new CursorPositionCallback()); - GLFW.glfwSetCursorPosCallback(display.getWindowPointer(), cursorPosition.get()); - - scroll.set(new ScrollInputCallback()); - GLFW.glfwSetScrollCallback(display.getWindowPointer(), scroll.get()); - - charInput.set(new KeyboardCharInput()); - GLFW.glfwSetCharCallback(display.getWindowPointer(), charInput.get()); + var instance = new InputBus(); + GLFW.glfwSetKeyCallback(display.getWindowPointer(), instance.keyboard); + GLFW.glfwSetMouseButtonCallback(display.getWindowPointer(), instance.mouseButton); + GLFW.glfwSetCursorPosCallback(display.getWindowPointer(), instance.cursorPosition); + GLFW.glfwSetScrollCallback(display.getWindowPointer(), instance.scroll); + GLFW.glfwSetCharCallback(display.getWindowPointer(), instance.charInput); } public static void destroy() { - scroll.get().free(); - scroll.remove(); + var instance = INSTANCE.get(); - mouseButton.get().free(); - mouseButton.remove(); - - keyboard.get().free(); - keyboard.remove(); - - cursorPosition.get().free(); - cursorPosition.remove(); - - charInput.get().free(); - charInput.remove(); + instance.scroll.free(); + instance.mouseButton.free(); + instance.keyboard.free(); + instance.cursorPosition.free(); + instance.charInput.free(); } public static KeyboardInputCallback keyboard() { - return keyboard.get(); + return INSTANCE.get().keyboard; } public static MouseButtonCallback mouseButtons() { - return mouseButton.get(); + return INSTANCE.get().mouseButton; } public static ScrollInputCallback scroll() { - return scroll.get(); + return INSTANCE.get().scroll; } public static CursorPositionCallback cursorPosition() { - return cursorPosition.get(); + return INSTANCE.get().cursorPosition; + } + + public static KeyboardCharInput charInput() + { + return INSTANCE.get().charInput; } public static void resetStates() { - keyboard.get().resetPressed(); - mouseButton.get().reset(); - scroll.get().reset(); - cursorPosition.get().reset(); - charInput.get().reset(); + var instance = INSTANCE.get(); + + instance.keyboard.resetPressed(); + instance.mouseButton.reset(); + instance.scroll.reset(); + instance.cursorPosition.reset(); + instance.charInput.reset(); } + @ThreadSensitive(localContexts = true) public static class Mouse { public static boolean clicked(int button) { - var mb = mouseButton.get(); - return mb.buttonClicked[button]; + return INSTANCE.get().mouseButton.buttonClicked[button]; } public static boolean released(int button) { - var mb = mouseButton.get(); - return mb.buttonReleased[button]; + return INSTANCE.get().mouseButton.buttonReleased[button]; } public static boolean isButtonDown(int button) { - var mb = mouseButton.get(); - return mb.buttonDown[button]; + return INSTANCE.get().mouseButton.buttonDown[button]; } public static double getX() { - return cursorPosition.get().getX(); + return INSTANCE.get().cursorPosition.getX(); } public static double getY() { - return cursorPosition.get().getY(); + return INSTANCE.get().cursorPosition.getY(); + } + + public static boolean isInside(int x1, int y1, int x2, int y2) + { + return INSTANCE.get().cursorPosition.isInside(x1, y1, x2, y2); } public static double getDX() { - return cursorPosition.get().getDeltaX(); + return INSTANCE.get().cursorPosition.getDeltaX(); } public static double getDY() { - return cursorPosition.get().getDeltaY(); + return INSTANCE.get().cursorPosition.getDeltaY(); } public static double getScrollX() { - return scroll.get().getXScroll(); + return INSTANCE.get().scroll.getXScroll(); } public static double getScrollY() { - return scroll.get().getYScroll(); + return INSTANCE.get().scroll.getYScroll(); } } + @ThreadSensitive(localContexts = true) public static class Keyboard { public static boolean pressed(int key) { - return keyboard.get().hasBeenPressed(key); + return INSTANCE.get().keyboard.hasBeenPressed(key); } public static boolean released(int key) { - return keyboard.get().hasBeenReleased(key); + return INSTANCE.get().keyboard.hasBeenReleased(key); } public static boolean isKeyDown(int key) { - return keyboard.get().isKeyDown(key); + return INSTANCE.get().keyboard.isKeyDown(key); } public static String getTypedText() { - return charInput.get().getTypedText(); + return INSTANCE.get().charInput.getTypedText(); } } } diff --git a/plutocore/src/main/java/cz/tefek/pluto/engine/input/KeyboardCharInput.java b/plutocore/src/main/java/cz/tefek/pluto/engine/input/KeyboardCharInput.java index 707df5a..1a849ca 100644 --- a/plutocore/src/main/java/cz/tefek/pluto/engine/input/KeyboardCharInput.java +++ b/plutocore/src/main/java/cz/tefek/pluto/engine/input/KeyboardCharInput.java @@ -4,7 +4,7 @@ import org.lwjgl.glfw.GLFWCharCallback; public class KeyboardCharInput extends GLFWCharCallback { - private StringBuilder typedText = new StringBuilder(); + private final StringBuilder typedText = new StringBuilder(); @Override public void invoke(long window, int codepoint) diff --git a/plutocore/src/main/java/cz/tefek/pluto/engine/input/KeyboardInputCallback.java b/plutocore/src/main/java/cz/tefek/pluto/engine/input/KeyboardInputCallback.java index d64a62d..4c65fa8 100644 --- a/plutocore/src/main/java/cz/tefek/pluto/engine/input/KeyboardInputCallback.java +++ b/plutocore/src/main/java/cz/tefek/pluto/engine/input/KeyboardInputCallback.java @@ -1,16 +1,16 @@ package cz.tefek.pluto.engine.input; -import static org.lwjgl.glfw.GLFW.GLFW_PRESS; -import static org.lwjgl.glfw.GLFW.GLFW_RELEASE; +import org.lwjgl.glfw.GLFWKeyCallback; import java.util.HashSet; import java.util.Set; -import org.lwjgl.glfw.GLFWKeyCallback; +import static org.lwjgl.glfw.GLFW.GLFW_PRESS; +import static org.lwjgl.glfw.GLFW.GLFW_RELEASE; public class KeyboardInputCallback extends GLFWKeyCallback { - private Set keyPressed = new HashSet<>(); + private final Set keyPressed = new HashSet<>(); private Set keyDown = new HashSet<>(); private Set keyReleased = new HashSet<>(); diff --git a/plutocore/src/main/java/cz/tefek/pluto/engine/input/MouseButtonCallback.java b/plutocore/src/main/java/cz/tefek/pluto/engine/input/MouseButtonCallback.java index abcfb07..503751c 100644 --- a/plutocore/src/main/java/cz/tefek/pluto/engine/input/MouseButtonCallback.java +++ b/plutocore/src/main/java/cz/tefek/pluto/engine/input/MouseButtonCallback.java @@ -3,6 +3,8 @@ package cz.tefek.pluto.engine.input; import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFWMouseButtonCallback; +import java.util.Arrays; + public class MouseButtonCallback extends GLFWMouseButtonCallback { public boolean[] buttonClicked = new boolean[32]; @@ -19,15 +21,8 @@ public class MouseButtonCallback extends GLFWMouseButtonCallback public void reset() { - for (int i = 0; i < this.buttonClicked.length; i++) - { - this.buttonClicked[i] = false; - } - - for (int i = 0; i < this.buttonClicked.length; i++) - { - this.buttonReleased[i] = false; - } + Arrays.fill(this.buttonClicked, false); + Arrays.fill(this.buttonReleased, false); } } diff --git a/plutocore/src/main/java/cz/tefek/pluto/engine/input/ScrollInputCallback.java b/plutocore/src/main/java/cz/tefek/pluto/engine/input/ScrollInputCallback.java index 353a782..cd8e0a5 100644 --- a/plutocore/src/main/java/cz/tefek/pluto/engine/input/ScrollInputCallback.java +++ b/plutocore/src/main/java/cz/tefek/pluto/engine/input/ScrollInputCallback.java @@ -29,18 +29,8 @@ public class ScrollInputCallback extends GLFWScrollCallback return yScroll; } - public void setYScroll(double yScroll) - { - this.yScroll = yScroll; - } - public double getXScroll() { return xScroll; } - - public void setXScroll(double xScroll) - { - this.xScroll = xScroll; - } } diff --git a/plutolib/src/main/java/cz/tefek/pluto/annotation/ThreadSensitive.java b/plutolib/src/main/java/cz/tefek/pluto/annotation/ThreadSensitive.java new file mode 100644 index 0000000..756d020 --- /dev/null +++ b/plutolib/src/main/java/cz/tefek/pluto/annotation/ThreadSensitive.java @@ -0,0 +1,33 @@ +package cz.tefek.pluto.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + *

+ * Marks a type as a thread-sensitive unit. Accesses from other threads + * other than the original one may result in undesirable behaviour (see below for exceptions). + *

+ * + *

+ * Types can opt in to set the {@link ThreadSensitive#localContexts} field to true, + * committing to support per-thread local contexts. + *

+ * + * @author 493msi + * + * @since 20.2.0.0-alpha.2 + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.SOURCE) +public @interface ThreadSensitive +{ + /** + * When true, the annotated type commits to support thread-local contexts. + * + * @since 20.2.0.0-alpha.2 + * */ + boolean localContexts() default false; +}