diff --git a/.gitignore b/.gitignore index 5ff6309..a44b021 100644 --- a/.gitignore +++ b/.gitignore @@ -1,38 +1,93 @@ -target/ -!.mvn/wrapper/maven-wrapper.jar -!**/src/main/**/target/ -!**/src/test/**/target/ +############################## +## Java +############################## +.mtj.tmp/ +*.class +*.jar +*.war +*.ear +*.nar +hs_err_pid* +replay_pid* -### IntelliJ IDEA ### -.idea/modules.xml -.idea/jarRepositories.xml -.idea/compiler.xml -.idea/libraries/ -*.iws +############################## +## Maven +############################## +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +pom.xml.bak +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +.mvn/wrapper/maven-wrapper.jar + +############################## +## Gradle +############################## +bin/ +build/ +.gradle +.gradletasknamecache +gradle-app.setting +!gradle-wrapper.jar + +############################## +## IntelliJ +############################## +out/ +.idea/ +.idea_modules/ *.iml *.ipr +*.iws -### Eclipse ### -.apt_generated +############################## +## Eclipse +############################## +.settings/ +bin/ +tmp/ +.metadata .classpath -.factorypath .project -.settings -.springBeans -.sts4-cache +*.tmp +*.bak +*.swp +*~.nib +local.properties +.loadpath +.factorypath -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ +############################## +## NetBeans +############################## +nbproject/private/ build/ -!**/src/main/**/build/ -!**/src/test/**/build/ +nbbuild/ +dist/ +nbdist/ +nbactions.xml +nb-configuration.xml -### VS Code ### +############################## +## Visual Studio Code +############################## .vscode/ +.code-workspace -### Mac OS ### -.DS_Store \ No newline at end of file +############################## +## OS X +############################## +.DS_Store + +############################## +## Miscellaneous +############################## +*.log + +# Ignore Gradle build output directory +build diff --git a/pom.xml b/pom.xml index f465c42..c152269 100644 --- a/pom.xml +++ b/pom.xml @@ -1,148 +1,102 @@ - 4.0.0 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 - org.toop - pis - 1.0-SNAPSHOT + org.toop + pism + 1.0-SNAPSHOT - - 24 - 24 - UTF-8 - 3.3.6 - natives-windows - - - - lwjgl-natives-linux-amd64 - - - unix - linux - amd64 - - - - natives-linux - - - - lwjgl-natives-macos-aarch64 - - - mac - aarch64 - - - - natives-macos-arm64 - - - - lwjgl-natives-windows-amd64 - - - windows - amd64 - - - - natives-windows - - - - - - - org.lwjgl - lwjgl-bom - ${lwjgl.version} - import - pom - - - + + 24 + 24 - - - - com.google.guava - guava - 33.4.8-jre - - - org.apache.logging.log4j - log4j-api - 2.25.1 - - - org.apache.logging.log4j - log4j-core - 2.25.1 - - - org.lwjgl - lwjgl - - - org.lwjgl - lwjgl-assimp - - - org.lwjgl - lwjgl-glfw - - - org.lwjgl - lwjgl-openal - - - org.lwjgl - lwjgl-opengl - - - org.lwjgl - lwjgl-stb - - - org.lwjgl - lwjgl - ${lwjgl.natives} - - - org.lwjgl - lwjgl-assimp - ${lwjgl.natives} - - - org.lwjgl - lwjgl-glfw - ${lwjgl.natives} - - - org.lwjgl - lwjgl-openal - ${lwjgl.natives} - - - org.lwjgl - lwjgl-opengl - ${lwjgl.natives} - - - org.lwjgl - lwjgl-stb - ${lwjgl.natives} - - - org.junit.jupiter - junit-jupiter - RELEASE - test - - + UTF-8 - \ No newline at end of file + org.toop.Main + + 3.3.6 + + + + lwjgl-natives-windows-amd64windowsamd64natives-windows + lwjgl-natives-linux-amd64unixlinuxamd64natives-linux + lwjgl-natives-macos-aarch64macaarch64natives-macos-arm64 + + + + + + org.lwjgl + lwjgl-bom + ${lwjgl.version} + import + pom + + + + + + + com.google.guava + guava + 33.4.8-jre + + + + org.junit.jupiter + junit-jupiter + RELEASE + test + + + + org.apache.logging.log4j + log4j-api + 2.25.1 + + + org.apache.logging.log4j + log4j-core + 2.25.1 + + + org.lwjgllwjgl + org.lwjgllwjgl-glfw + org.lwjgllwjgl-opengl + org.lwjgllwjgl-stb + org.lwjgllwjgl${lwjgl.natives} + org.lwjgllwjgl-glfw${lwjgl.natives} + org.lwjgllwjgl-opengl${lwjgl.natives} + org.lwjgllwjgl-stb${lwjgl.natives} + + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.6.1 + + + + package + + + shade + + + + + + ${main-class} + + + + + + + + + diff --git a/src/main/java/org/toop/Client.java b/src/main/java/org/toop/Client.java deleted file mode 100644 index b0a1cae..0000000 --- a/src/main/java/org/toop/Client.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.toop; - -public class Client { - -} diff --git a/src/main/java/org/toop/Main.java b/src/main/java/org/toop/Main.java index 22b074e..1282e7e 100644 --- a/src/main/java/org/toop/Main.java +++ b/src/main/java/org/toop/Main.java @@ -1,54 +1,55 @@ package org.toop; -import org.toop.eventbus.Events; -import org.toop.eventbus.GlobalEventBus; -import org.toop.server.Server; -import org.toop.server.backend.Testsss; -import org.toop.server.backend.TcpServer; - -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.LogManager; +import org.toop.core.*; +import org.toop.eventbus.*; +import org.toop.graphics.*; public class Main { - private static final Logger logger = LogManager.getLogger(Main.class); + private static boolean running = false; - public static void main(String[] args) { + public static void main(String[] args) { + registerEvents(); - if (!initEvents()) { - throw new RuntimeException("A event could not be initialized"); - } + Window window = Window.setup(Window.API.GLFW, "Test", new Window.Size(1280, 720)); + Renderer renderer = Renderer.setup(Renderer.API.OPENGL); - TcpServer server = new TcpServer(5001); - Thread serverThread = new Thread(server); - serverThread.start(); - Server.start("127.0.0.1", "5001"); - // Testsss.start(""); // Used for testing server. - Window.start(""); + Shader shader = Shader.create( + "src/main/resources/shaders/gui_vertex.glsl", + "src/main/resources/shaders/gui_fragment.glsl"); - } + running = window != null && renderer != null && shader != null; - /** - * Returns false if any event could not be initialized. - */ - private static boolean initEvents() { - try { + while (running) { + window.update(); + renderer.clear(); - GlobalEventBus.subscribeAndRegister(Events.ServerEvents.OnChangingServerIp.class, - event -> - logger.info("Changing server ip to {}", event.ip()) - ); + shader.start(); + renderer.render(); + } - GlobalEventBus.subscribeAndRegister(Events.ServerEvents.OnChangingServerPort.class, - event -> - logger.info("Changing server port to {}", event.port()) - ); + if (shader != null) shader.cleanup(); + if (renderer != null) renderer.cleanup(); + if (window != null) window.cleanup(); + } - return true; - } - catch (Exception err) { - logger.info("{}", err.getMessage()); - return false; - } - } + private static void registerEvents() { + GlobalEventBus.subscribeAndRegister(Events.WindowEvents.OnQuitRequested.class, event -> { + quit(); + }); -} \ No newline at end of file + GlobalEventBus.subscribeAndRegister(Events.WindowEvents.OnMouseMove.class, event -> { + }); + } + + private static void quit() { + running = false; + } + + public static boolean isRunning() { + return running; + } + + public static void setRunning(boolean running) { + Main.running = running; + } +} diff --git a/src/main/java/org/toop/Window.java b/src/main/java/org/toop/Window.java deleted file mode 100644 index ed8cf09..0000000 --- a/src/main/java/org/toop/Window.java +++ /dev/null @@ -1,164 +0,0 @@ -package org.toop; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.lwjgl.*; -import org.lwjgl.glfw.*; -import org.lwjgl.opengl.*; -import org.lwjgl.system.*; - -import java.nio.*; - -import static org.lwjgl.glfw.Callbacks.*; -import static org.lwjgl.glfw.GLFW.*; -import static org.lwjgl.opengl.GL11.*; -import static org.lwjgl.system.MemoryStack.*; -import static org.lwjgl.system.MemoryUtil.*; -import static org.lwjgl.stb.STBImage.*; - -public class Window extends Thread { - - private static final Logger logger = LogManager.getLogger(Main.class); - // The window handle - private long window; - - public void run() { - - init(); - loop(); - - // Free the window callbacks and destroy the window - glfwFreeCallbacks(window); - glfwDestroyWindow(window); - - // Terminate GLFW and free the error callback - glfwTerminate(); - glfwSetErrorCallback(null).free(); - } - - private void init() { - // Set up an error callback. The default implementation - // will print the error message in System.err. - GLFWErrorCallback.createPrint(System.err).set(); - - // Initialize GLFW. Most GLFW functions will not work before doing this. - if ( !glfwInit() ){ - throw new IllegalStateException("Unable to initialize GLFW"); - } - - - // Configure GLFW - glfwDefaultWindowHints(); // optional, the current window hints are already the default - glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); // the window will stay hidden after creation - glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); // the window will be resizable - - // Create the window - window = glfwCreateWindow(1920, 1080, "ISY Game Selector", NULL, NULL); - if ( window == NULL ) - throw new RuntimeException("Failed to create the GLFW window"); - - // Set up a key callback. It will be called every time a key is pressed, repeated or released. - glfwSetKeyCallback(window, (window, key, scancode, action, mods) -> { - if ( key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE ) { - glfwSetWindowShouldClose(window, true); // We will detect this in the rendering loop - } - }); - - // Get the thread stack and push a new frame - try ( MemoryStack stack = stackPush() ) { - IntBuffer pWidth = stack.mallocInt(1); // int* - IntBuffer pHeight = stack.mallocInt(1); // int* - - // Get the window size passed to glfwCreateWindow - glfwGetWindowSize(window, pWidth, pHeight); - - // Get the resolution of the primary monitor - GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor()); - - // Center the window - assert vidmode != null; - glfwSetWindowPos( - window, - (vidmode.width() - pWidth.get(0)) / 2, - (vidmode.height() - pHeight.get(0)) / 2 - ); - - - - // Prepare buffers to receive image data - IntBuffer width = stack.mallocInt(1); - IntBuffer height = stack.mallocInt(1); - IntBuffer channels = stack.mallocInt(1); - - // Load the image - String imagePath = "img/icon.png"; - ByteBuffer image = stbi_load(imagePath, width, height, channels, 4); // Force RGBA (4 channels) - - if (image == null) { - throw new RuntimeException("Failed to load image: " + stbi_failure_reason()); - } - - // Create GLFWImage - GLFWImage icon = GLFWImage.malloc(stack); - icon.set(width.get(0), height.get(0), image); - - // Create a buffer with the icon(s) — can be multiple icons for different sizes - GLFWImage.Buffer icons = GLFWImage.malloc(1, stack); - icons.put(0, icon); - - // Set the window icon - glfwSetWindowIcon(window, icons); - - // Free the image data - stbi_image_free(image); - - - } // the stack frame is popped automatically - - // Make the OpenGL context current - glfwMakeContextCurrent(window); - // Enable v-sync - glfwSwapInterval(1); - - // Make the window visible - glfwShowWindow(window); - } - - private void loop() { - // This line is critical for LWJGL's interoperation with GLFW's - // OpenGL context, or any context that is managed externally. - // LWJGL detects the context that is current in the current thread, - // creates the GLCapabilities instance and makes the OpenGL - // bindings available for use. - GL.createCapabilities(); - - // Set the clear color - glClearColor(0.5f, 0.5f, 0.5f, 0.0f); - - // Run the rendering loop until the user has attempted to close - // the window or has pressed the ESCAPE key. - while ( !glfwWindowShouldClose(window) ) { - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear the framebuffer - - glfwSwapBuffers(window); // swap the color buffers - - // Poll for window events. The key callback above will only be - // invoked during this call. - glfwPollEvents(); - } - } - - //public static void main(String[] args) { - //new Window().run(); - //} - /** - * TODO: Is putting the window on a second thread, safe? - * Can't overwrite start(), so a overload is needed. - * - * @param ignoredKeepEmpty Just input "" an empty string. - */ - public static void start(String ignoredKeepEmpty){ - new Window().start(); - } - -} diff --git a/src/main/java/org/toop/core/FileSystem.java b/src/main/java/org/toop/core/FileSystem.java new file mode 100644 index 0000000..d5e7ae4 --- /dev/null +++ b/src/main/java/org/toop/core/FileSystem.java @@ -0,0 +1,34 @@ +package org.toop.core; + +import java.io.*; + +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; + +public class FileSystem { + public record File(String path, CharSequence buffer) {}; + + private static final Logger logger = LogManager.getLogger(FileSystem.class); + + public static File read(String path) { + File file; + + try (BufferedReader reader = new BufferedReader(new FileReader(path))) { + StringBuilder buffer = new StringBuilder(); + String line = reader.readLine(); + + while (line != null) { + buffer.append(line); + buffer.append(System.lineSeparator()); + line = reader.readLine(); + } + + file = new File(path, buffer); + } catch (IOException e) { + logger.error("{}", e.getMessage()); + return null; + } + + return file; + } +} diff --git a/src/main/java/org/toop/core/ICallable.java b/src/main/java/org/toop/core/ICallable.java new file mode 100644 index 0000000..fa23c8b --- /dev/null +++ b/src/main/java/org/toop/core/ICallable.java @@ -0,0 +1,5 @@ +package org.toop.core; + +public interface ICallable { + public T call(); +} diff --git a/src/main/java/org/toop/core/Window.java b/src/main/java/org/toop/core/Window.java new file mode 100644 index 0000000..eb7c2b6 --- /dev/null +++ b/src/main/java/org/toop/core/Window.java @@ -0,0 +1,51 @@ +package org.toop.core; + +import org.toop.platform.core.glfw.*; + +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; + +public abstract class Window { + public enum API { + NONE, + GLFW, + } + + public record Size(int width, int height) {} + + protected static final Logger logger = LogManager.getLogger(Window.class); + + private static API api = API.NONE; + private static Window instance = null; + + public static Window setup(API api, String title, Size size) { + if (instance != null) { + logger.warn("Window is already setup."); + return instance; + } + + switch (api) { + case GLFW: + instance = new GlfwWindow(title, size); + break; + + default: + logger.fatal("No valid window api chosen"); + return null; + } + + Window.api = api; + return instance; + } + + public static API getApi() { + return api; + } + + public void cleanup() { + instance = null; + logger.info("Window cleanup."); + } + + public abstract void update(); +} diff --git a/src/main/java/org/toop/eventbus/EventMeta.java b/src/main/java/org/toop/eventbus/EventMeta.java index 4b28640..3ecea2d 100644 --- a/src/main/java/org/toop/eventbus/EventMeta.java +++ b/src/main/java/org/toop/eventbus/EventMeta.java @@ -38,4 +38,4 @@ public class EventMeta { ", ready=" + ready + '}'; } -} \ No newline at end of file +} diff --git a/src/main/java/org/toop/eventbus/EventRegistry.java b/src/main/java/org/toop/eventbus/EventRegistry.java index 29643da..12814c9 100644 --- a/src/main/java/org/toop/eventbus/EventRegistry.java +++ b/src/main/java/org/toop/eventbus/EventRegistry.java @@ -123,4 +123,4 @@ public class EventRegistry { '}'; } } -} \ No newline at end of file +} diff --git a/src/main/java/org/toop/eventbus/Events.java b/src/main/java/org/toop/eventbus/Events.java index 30168d0..0eb0d42 100644 --- a/src/main/java/org/toop/eventbus/Events.java +++ b/src/main/java/org/toop/eventbus/Events.java @@ -1,6 +1,7 @@ package org.toop.eventbus; import org.toop.server.Server; +import org.toop.core.*; import java.lang.reflect.Constructor; import java.util.Arrays; @@ -116,7 +117,30 @@ public class Events implements IEvents { } public static class WindowEvents { + /** + * Triggers when the window wants to quit. + */ + public record OnQuitRequested() {} + /** + * Triggers when the window is resized. + */ + public record OnResize(Window.Size size) {} + + /** + * Triggers when the mouse is moved within the window. + */ + public record OnMouseMove(int x, int y) {} + + /** + * Triggers when the mouse is clicked within the window. + */ + public record OnMouseClick(int button) {} + + /** + * Triggers when the mouse is released within the window. + */ + public record OnMouseRelease(int button) {} } public static class TttEvents { diff --git a/src/main/java/org/toop/eventbus/GlobalEventBus.java b/src/main/java/org/toop/eventbus/GlobalEventBus.java index 46c06d9..d44728a 100644 --- a/src/main/java/org/toop/eventbus/GlobalEventBus.java +++ b/src/main/java/org/toop/eventbus/GlobalEventBus.java @@ -109,4 +109,4 @@ public enum GlobalEventBus { GlobalEventBus.INSTANCE.get().post(event); } -} \ No newline at end of file +} diff --git a/src/main/java/org/toop/game/TTT.java b/src/main/java/org/toop/game/TTT.java index 972f4e3..ab3f875 100644 --- a/src/main/java/org/toop/game/TTT.java +++ b/src/main/java/org/toop/game/TTT.java @@ -5,6 +5,7 @@ public class TTT extends GameBase { public TTT(String player1, String player2) { super(9); + players = new Player[2]; players[0] = new Player(player1, 'X'); players[1] = new Player(player2, 'O'); diff --git a/src/main/java/org/toop/graphics/Renderer.java b/src/main/java/org/toop/graphics/Renderer.java new file mode 100644 index 0000000..f0e13d8 --- /dev/null +++ b/src/main/java/org/toop/graphics/Renderer.java @@ -0,0 +1,50 @@ +package org.toop.graphics; + +import org.toop.platform.graphics.opengl.*; + +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; + +public abstract class Renderer { + public enum API { + NONE, + OPENGL, + }; + + protected static final Logger logger = LogManager.getLogger(Renderer.class); + + private static API api = API.NONE; + private static Renderer instance = null; + + public static Renderer setup(API api) { + if (instance != null) { + logger.warn("Renderer is already setup."); + return instance; + } + + switch (api) { + case OPENGL: + instance = new OpenglRenderer(); + break; + + default: + logger.fatal("No valid renderer api chosen"); + return null; + } + + Renderer.api = api; + return instance; + } + + public static API getApi() { + return api; + } + + public void cleanup() { + instance = null; + logger.info("Renderer cleanup."); + } + + public abstract void clear(); + public abstract void render(); +} diff --git a/src/main/java/org/toop/graphics/Shader.java b/src/main/java/org/toop/graphics/Shader.java new file mode 100644 index 0000000..11e62a3 --- /dev/null +++ b/src/main/java/org/toop/graphics/Shader.java @@ -0,0 +1,26 @@ +package org.toop.graphics; + +import org.toop.platform.graphics.opengl.*; + +public abstract class Shader { + public static Shader create(String vertexPath, String fragmentPath) { + Shader shader = null; + + switch (Renderer.getApi()) { + case OPENGL: + shader = new OpenglShader(vertexPath, fragmentPath); + break; + + case NONE: + default: + break; + } + + return shader; + } + + public abstract void cleanup(); + + public abstract void start(); + public abstract void stop(); +} diff --git a/src/main/java/org/toop/graphics/node/Button.java b/src/main/java/org/toop/graphics/node/Button.java new file mode 100644 index 0000000..3ee74ac --- /dev/null +++ b/src/main/java/org/toop/graphics/node/Button.java @@ -0,0 +1,26 @@ +package org.toop.graphics.node; + +import org.toop.core.*; +import org.toop.math.*; + +public class Button extends Node { + ICallable onHover; + ICallable onClick; + + public Button(int x, int y, int width, int height, Color color, ICallable onHover, ICallable onClick) { + super(x, y, width, height, color); + + this.onHover = onHover; + this.onClick = onClick; + } + + @Override + public void hover() { + onHover.call(); + } + + @Override + public void click() { + onClick.call(); + } +} diff --git a/src/main/java/org/toop/graphics/node/Node.java b/src/main/java/org/toop/graphics/node/Node.java new file mode 100644 index 0000000..929738c --- /dev/null +++ b/src/main/java/org/toop/graphics/node/Node.java @@ -0,0 +1,20 @@ +package org.toop.graphics.node; + +import org.toop.math.*; + +public abstract class Node { + protected Bounds bounds; + protected Color color; + + public Node(int x, int y, int width, int height, Color color) { + bounds = new Bounds(x, y, width, height); + this.color = color; + } + + public boolean check(int x, int y) { + return bounds.check(x, y); + } + + public void hover() {} + public void click() {} +} diff --git a/src/main/java/org/toop/graphics/node/NodeManager.java b/src/main/java/org/toop/graphics/node/NodeManager.java new file mode 100644 index 0000000..f59adaf --- /dev/null +++ b/src/main/java/org/toop/graphics/node/NodeManager.java @@ -0,0 +1,66 @@ +package org.toop.graphics.node; + +import org.toop.eventbus.*; +import org.toop.graphics.*; + +import java.util.*; + +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; + +public class NodeManager { + private static final Logger logger = LogManager.getLogger(NodeManager.class); + + private static NodeManager instance = null; + + public static NodeManager setup() { + if (instance != null) { + logger.warn("NodeManager is already setup."); + return instance; + } + + instance = new NodeManager(); + return instance; + } + + private Shader shader; + private ArrayList nodes; + private Node active; + + private NodeManager() { + shader = Shader.create( + "src/main/resources/shaders/gui_vertex.glsl", + "src/main/resources/shaders/gui_fragment.glsl"); + + nodes = new ArrayList(); + + GlobalEventBus.subscribeAndRegister(Events.WindowEvents.OnMouseMove.class, event -> { + for (int i = 0; i < nodes.size(); i++) { + Node node = nodes.get(i); + + if (node.check(event.x(), event.y())) { + active = node; + node.hover(); + + break; + } + } + }); + + GlobalEventBus.subscribeAndRegister(Events.WindowEvents.OnMouseClick.class, event -> { + if (active != null) { + active.click(); + } + }); + } + + public void cleanup() { + } + + public void add(Node node) { + nodes.add(node); + } + + public void render() { + } +} diff --git a/src/main/java/org/toop/graphics/node/Widget.java b/src/main/java/org/toop/graphics/node/Widget.java new file mode 100644 index 0000000..aa3b3f1 --- /dev/null +++ b/src/main/java/org/toop/graphics/node/Widget.java @@ -0,0 +1,49 @@ +package org.toop.graphics.node; + +import org.toop.math.*; + +import java.util.*; + +public class Widget { + Bounds bounds; + private ArrayList nodes; + + public Widget(Bounds bounds) { + this.bounds = bounds; + nodes = new ArrayList(); + } + + public boolean check(int x, int y) { + return bounds.check(x, y); + } + + public void add(Node node) { + nodes.add(node); + } + + public boolean hover(int x, int y) { + for (int i = 0; i < nodes.size(); i++) { + Node node = nodes.get(i); + + if (node.check(x, y)) { + node.hover(); + return true; + } + } + + return false; + } + + public boolean click(int x, int y) { + for (int i = 0; i < nodes.size(); i++) { + Node node = nodes.get(i); + + if (node.check(x, y)) { + node.click(); + return true; + } + } + + return false; + } +} diff --git a/src/main/java/org/toop/math/Bounds.java b/src/main/java/org/toop/math/Bounds.java new file mode 100644 index 0000000..7b7769a --- /dev/null +++ b/src/main/java/org/toop/math/Bounds.java @@ -0,0 +1,30 @@ +package org.toop.math; + +public class Bounds { + private int x; + private int y; + private int width; + private int height; + + public Bounds(int x, int y, int width, int height) { + set(x, y, width, height); + } + + public void set(int x, int y, int width, int height) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + + public int getX() { return x; } + public int getY() { return y; } + public int getWidth() { return width; } + public int getHeight() { return height; } + + public boolean check(int x, int y) { + return + x >= this.x && x <= this.x + this.width && + y >= this.y && y <= this.y + this.height; + } +} diff --git a/src/main/java/org/toop/math/Color.java b/src/main/java/org/toop/math/Color.java new file mode 100644 index 0000000..322bc16 --- /dev/null +++ b/src/main/java/org/toop/math/Color.java @@ -0,0 +1,17 @@ +package org.toop.math; + +public class Color { + private float r; + private float g; + private float b; + + public Color(float r, float g, float b) { + this.r = r; + this.g = g; + this.b = b; + } + + public float r() { return r; } + public float g() { return g; } + public float b() { return b; } +} diff --git a/src/main/java/org/toop/platform/core/glfw/GlfwWindow.java b/src/main/java/org/toop/platform/core/glfw/GlfwWindow.java new file mode 100644 index 0000000..3b02a74 --- /dev/null +++ b/src/main/java/org/toop/platform/core/glfw/GlfwWindow.java @@ -0,0 +1,95 @@ +package org.toop.platform.core.glfw; + +import org.toop.core.*; +import org.toop.eventbus.*; + +import org.lwjgl.glfw.*; +import org.lwjgl.system.*; + +public class GlfwWindow extends Window { + private long window; + + public GlfwWindow(String title, Size size) { + if (!GLFW.glfwInit()) { + logger.fatal("Failed to initialize glfw"); + return; + } + + GLFW.glfwDefaultWindowHints(); + GLFW.glfwWindowHint(GLFW.GLFW_VISIBLE, GLFW.GLFW_FALSE); + GLFW.glfwWindowHint(GLFW.GLFW_RESIZABLE, GLFW.GLFW_TRUE); + + GLFWVidMode videoMode = GLFW.glfwGetVideoMode(GLFW.glfwGetPrimaryMonitor()); + + int width = size.width(); + int height = size.height(); + + if (width <= 0 || height <= 0 || width > videoMode.width() || height > videoMode.height()) { + width = videoMode.width(); + height = videoMode.height(); + + GLFW.glfwWindowHint(GLFW.GLFW_MAXIMIZED, GLFW.GLFW_TRUE); + } + + long window = GLFW.glfwCreateWindow(width, height, title, MemoryUtil.NULL, MemoryUtil.NULL); + + if (window == MemoryUtil.NULL) { + GLFW.glfwTerminate(); + + logger.fatal("Failed to create glfw window"); + return; + } + + int[] widthBuffer = new int[1]; + int[] heightBuffer = new int[1]; + GLFW.glfwGetWindowSize(window, widthBuffer, heightBuffer); + + GLFW.glfwMakeContextCurrent(window); + GLFW.glfwSwapInterval(1); + + GLFW.glfwSetWindowCloseCallback(window, (lwindow) -> { + GlobalEventBus.post(new Events.WindowEvents.OnQuitRequested()); + }); + + GLFW.glfwSetFramebufferSizeCallback(window, (lwindow, lwidth, lheight) -> { + GlobalEventBus.post(new Events.WindowEvents.OnResize(new Size(lwidth, lheight))); + }); + + GLFW.glfwSetCursorPosCallback(window, (lwindow, lx, ly) -> { + GlobalEventBus.post(new Events.WindowEvents.OnMouseMove((int)lx, (int)ly)); + }); + + GLFW.glfwSetMouseButtonCallback(window, (lwindow, lbutton, laction, lmods) -> { + switch (laction) { + case GLFW.GLFW_PRESS: + GlobalEventBus.post(new Events.WindowEvents.OnMouseClick(lbutton)); + break; + + case GLFW.GLFW_RELEASE: + GlobalEventBus.post(new Events.WindowEvents.OnMouseRelease(lbutton)); + break; + + default: break; + } + }); + + this.window = window; + GLFW.glfwShowWindow(window); + + logger.info("Glfw window setup. Title: {}. Width: {}. Height: {}.", title, size.width(), size.height()); + } + + @Override + public void cleanup() { + GLFW.glfwDestroyWindow(window); + GLFW.glfwTerminate(); + + super.cleanup(); + } + + @Override + public void update() { + GLFW.glfwSwapBuffers(window); + GLFW.glfwPollEvents(); + } +} diff --git a/src/main/java/org/toop/platform/graphics/opengl/OpenglRenderer.java b/src/main/java/org/toop/platform/graphics/opengl/OpenglRenderer.java new file mode 100644 index 0000000..6b0a963 --- /dev/null +++ b/src/main/java/org/toop/platform/graphics/opengl/OpenglRenderer.java @@ -0,0 +1,75 @@ +package org.toop.platform.graphics.opengl; + +import org.toop.eventbus.*; +import org.toop.graphics.*; + +import org.lwjgl.opengl.*; +import org.lwjgl.system.*; + +public class OpenglRenderer extends Renderer { + private Shader shader; + private int vao; + + public OpenglRenderer() { + GL.createCapabilities(); + GL45.glClearColor(0.65f, 0.9f, 0.65f, 1f); + + GlobalEventBus.subscribeAndRegister(Events.WindowEvents.OnResize.class, event -> { + GL45.glViewport(0, 0, event.size().width(), event.size().height()); + }); + + logger.info("Opengl renderer setup."); + + // Form here on, everything is temporary + float vertices[] = { + -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, + -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, + 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, + 0.5f, 0.5f, 1.0f, 1.0f, 0.0f, + }; + + int indicies[] = { + 0, 1, 2, + 2, 3, 0, + }; + + vao = GL45.glCreateVertexArrays(); + GL45.glBindVertexArray(vao); + + int vbo = GL45.glCreateBuffers(); + GL45.glBindBuffer(GL45.GL_ARRAY_BUFFER, vbo); + GL45.glBufferData(GL45.GL_ARRAY_BUFFER, vertices, GL45.GL_STATIC_DRAW); + + GL45.glVertexAttribPointer(0, 2, GL45.GL_FLOAT, false, 5 * 4, 0); + GL45.glVertexAttribPointer(1, 3, GL45.GL_FLOAT, false, 5 * 4, 2 * 4); + + GL45.glEnableVertexAttribArray(0); + GL45.glEnableVertexAttribArray(1); + + int ib = GL45.glCreateBuffers(); + GL45.glBindBuffer(GL45.GL_ELEMENT_ARRAY_BUFFER, ib); + GL45.glBufferData(GL45.GL_ELEMENT_ARRAY_BUFFER, indicies, GL45.GL_STATIC_DRAW); + + shader = Shader.create( + "src/main/resources/shaders/gui_vertex.glsl", + "src/main/resources/shaders/gui_fragment.glsl"); + } + + @Override + public void cleanup() { + super.cleanup(); + } + + @Override + public void clear() { + GL45.glClear(GL45.GL_COLOR_BUFFER_BIT); + } + + @Override + public void render() { + // temporary + // shader.start(); + GL45.glBindVertexArray(vao); + GL45.glDrawElements(GL45.GL_TRIANGLES, 6, GL45.GL_UNSIGNED_INT, MemoryUtil.NULL); + } +} diff --git a/src/main/java/org/toop/platform/graphics/opengl/OpenglShader.java b/src/main/java/org/toop/platform/graphics/opengl/OpenglShader.java new file mode 100644 index 0000000..1d0dd8d --- /dev/null +++ b/src/main/java/org/toop/platform/graphics/opengl/OpenglShader.java @@ -0,0 +1,58 @@ +package org.toop.platform.graphics.opengl; + +import org.toop.core.*; +import org.toop.graphics.*; + +import org.lwjgl.opengl.*; + +public class OpenglShader extends Shader { + private int programID; + + public OpenglShader(String vertexPath, String fragmentPath) { + FileSystem.File vertexSource = FileSystem.read(vertexPath); + FileSystem.File fragmentSource = FileSystem.read(fragmentPath); + + if (vertexSource == null || fragmentPath == null) { + return; + } + + programID = GL45.glCreateProgram(); + + int vertexShader = GL45.glCreateShader(GL45.GL_VERTEX_SHADER); + int fragmentShader = GL45.glCreateShader(GL45.GL_FRAGMENT_SHADER); + + GL45.glShaderSource(vertexShader, vertexSource.buffer()); + GL45.glShaderSource(fragmentShader, fragmentSource.buffer()); + + GL45.glCompileShader(vertexShader); + GL45.glCompileShader(fragmentShader); + + GL45.glAttachShader(programID, vertexShader); + GL45.glAttachShader(programID, fragmentShader); + + GL45.glLinkProgram(programID); + GL45.glValidateProgram(programID); + + GL45.glDetachShader(programID, vertexShader); + GL45.glDetachShader(programID, fragmentShader); + + GL45.glDeleteShader(vertexShader); + GL45.glDeleteShader(fragmentShader); + } + + @Override + public void cleanup() { + stop(); + GL45.glDeleteProgram(programID); + } + + @Override + public void start() { + GL45.glUseProgram(programID); + } + + @Override + public void stop() { + GL45.glUseProgram(0); + } +} diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml index 21163f9..12bfd81 100644 --- a/src/main/resources/log4j2.xml +++ b/src/main/resources/log4j2.xml @@ -1,13 +1,13 @@ - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + diff --git a/src/main/resources/shaders/gui_fragment.glsl b/src/main/resources/shaders/gui_fragment.glsl new file mode 100644 index 0000000..f1d5ccd --- /dev/null +++ b/src/main/resources/shaders/gui_fragment.glsl @@ -0,0 +1,9 @@ +#version 450 core + +in vec3 pass_color; + +out vec4 out_color; + +void main(void) { + out_color = vec4(pass_color, 1.0); +} diff --git a/src/main/resources/shaders/gui_vertex.glsl b/src/main/resources/shaders/gui_vertex.glsl new file mode 100644 index 0000000..60e9cb4 --- /dev/null +++ b/src/main/resources/shaders/gui_vertex.glsl @@ -0,0 +1,11 @@ +#version 450 core + +layout(location = 0) in vec2 in_position; +layout(location = 1) in vec3 in_color; + +out vec3 pass_color; + +void main(void) { + gl_Position = vec4(in_position, 0.0f, 1.0f); + pass_color = in_color; +} diff --git a/src/test/java/GlobalEventBusTest.java b/src/test/java/GlobalEventBusTest.java index 7ed81f4..70ed85a 100644 --- a/src/test/java/GlobalEventBusTest.java +++ b/src/test/java/GlobalEventBusTest.java @@ -111,4 +111,4 @@ public class GlobalEventBusTest { // TestEvent storedEvent = storedEntry.getEvent(); // assertEquals(event, storedEvent); // } -} \ No newline at end of file +}