From 9538b42cea73c4cfeeeaa09f53593a6c8933cb46 Mon Sep 17 00:00:00 2001
From: ramollia <>
Date: Tue, 16 Sep 2025 11:23:48 +0200
Subject: [PATCH 1/2] add: own branch
---
.gitignore | 109 ++++++--
pom.xml | 238 +++++++-----------
src/main/java/org/toop/Client.java | 5 -
src/main/java/org/toop/Main.java | 83 +++---
src/main/java/org/toop/Window.java | 164 ------------
src/main/java/org/toop/core/FileSystem.java | 34 +++
src/main/java/org/toop/core/ICallable.java | 5 +
src/main/java/org/toop/core/Window.java | 51 ++++
.../java/org/toop/eventbus/EventMeta.java | 2 +-
.../java/org/toop/eventbus/EventRegistry.java | 2 +-
src/main/java/org/toop/eventbus/Events.java | 24 ++
.../org/toop/eventbus/GlobalEventBus.java | 2 +-
src/main/java/org/toop/game/TTT.java | 1 +
src/main/java/org/toop/graphics/Renderer.java | 50 ++++
src/main/java/org/toop/graphics/Shader.java | 26 ++
.../java/org/toop/graphics/node/Button.java | 26 ++
.../java/org/toop/graphics/node/Node.java | 20 ++
.../org/toop/graphics/node/NodeManager.java | 66 +++++
.../java/org/toop/graphics/node/Widget.java | 49 ++++
src/main/java/org/toop/math/Bounds.java | 30 +++
src/main/java/org/toop/math/Color.java | 17 ++
.../toop/platform/core/glfw/GlfwWindow.java | 95 +++++++
.../graphics/opengl/OpenglRenderer.java | 75 ++++++
.../graphics/opengl/OpenglShader.java | 58 +++++
src/main/resources/log4j2.xml | 22 +-
src/main/resources/shaders/gui_fragment.glsl | 9 +
src/main/resources/shaders/gui_vertex.glsl | 11 +
src/test/java/GlobalEventBusTest.java | 2 +-
28 files changed, 882 insertions(+), 394 deletions(-)
delete mode 100644 src/main/java/org/toop/Client.java
delete mode 100644 src/main/java/org/toop/Window.java
create mode 100644 src/main/java/org/toop/core/FileSystem.java
create mode 100644 src/main/java/org/toop/core/ICallable.java
create mode 100644 src/main/java/org/toop/core/Window.java
create mode 100644 src/main/java/org/toop/graphics/Renderer.java
create mode 100644 src/main/java/org/toop/graphics/Shader.java
create mode 100644 src/main/java/org/toop/graphics/node/Button.java
create mode 100644 src/main/java/org/toop/graphics/node/Node.java
create mode 100644 src/main/java/org/toop/graphics/node/NodeManager.java
create mode 100644 src/main/java/org/toop/graphics/node/Widget.java
create mode 100644 src/main/java/org/toop/math/Bounds.java
create mode 100644 src/main/java/org/toop/math/Color.java
create mode 100644 src/main/java/org/toop/platform/core/glfw/GlfwWindow.java
create mode 100644 src/main/java/org/toop/platform/graphics/opengl/OpenglRenderer.java
create mode 100644 src/main/java/org/toop/platform/graphics/opengl/OpenglShader.java
create mode 100644 src/main/resources/shaders/gui_fragment.glsl
create mode 100644 src/main/resources/shaders/gui_vertex.glsl
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
+}
From ef80baae5c37646d408fd63b22af46579d444e44 Mon Sep 17 00:00:00 2001
From: Ticho Hidding
Date: Wed, 17 Sep 2025 17:17:21 +0200
Subject: [PATCH 2/2] Added GUI with swift.
---
.idea/misc.xml | 2 +-
.idea/uiDesigner.xml | 3 +
src/main/java/org/toop/Main.java | 10 +-
.../java/org/toop/UI/GameSelectorWindow.form | 117 ++++++++++++++++++
.../java/org/toop/UI/GameSelectorWindow.java | 57 +++++++++
src/main/java/org/toop/UI/UIGameBoard.form | 55 ++++++++
src/main/java/org/toop/UI/UIGameBoard.java | 78 ++++++++++++
src/main/java/org/toop/eventbus/Events.java | 4 +
8 files changed, 322 insertions(+), 4 deletions(-)
create mode 100644 src/main/java/org/toop/UI/GameSelectorWindow.form
create mode 100644 src/main/java/org/toop/UI/GameSelectorWindow.java
create mode 100644 src/main/java/org/toop/UI/UIGameBoard.form
create mode 100644 src/main/java/org/toop/UI/UIGameBoard.java
diff --git a/.idea/misc.xml b/.idea/misc.xml
index d0e8c51..67f7df6 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -13,7 +13,7 @@
-
+
\ No newline at end of file
diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml
index 2b63946..75d7be8 100644
--- a/.idea/uiDesigner.xml
+++ b/.idea/uiDesigner.xml
@@ -121,4 +121,7 @@
+
+
+
\ No newline at end of file
diff --git a/src/main/java/org/toop/Main.java b/src/main/java/org/toop/Main.java
index 1282e7e..6f7aa62 100644
--- a/src/main/java/org/toop/Main.java
+++ b/src/main/java/org/toop/Main.java
@@ -1,15 +1,14 @@
package org.toop;
-import org.toop.core.*;
+import org.toop.UI.GameSelectorWindow;
import org.toop.eventbus.*;
-import org.toop.graphics.*;
public class Main {
private static boolean running = false;
public static void main(String[] args) {
registerEvents();
-
+ /*
Window window = Window.setup(Window.API.GLFW, "Test", new Window.Size(1280, 720));
Renderer renderer = Renderer.setup(Renderer.API.OPENGL);
@@ -30,6 +29,11 @@ public class Main {
if (shader != null) shader.cleanup();
if (renderer != null) renderer.cleanup();
if (window != null) window.cleanup();
+
+ */
+ //JFrameWindow window = new JFrameWindow();
+ GameSelectorWindow gameSelectorWindow = new GameSelectorWindow();
+
}
private static void registerEvents() {
diff --git a/src/main/java/org/toop/UI/GameSelectorWindow.form b/src/main/java/org/toop/UI/GameSelectorWindow.form
new file mode 100644
index 0000000..7a78dab
--- /dev/null
+++ b/src/main/java/org/toop/UI/GameSelectorWindow.form
@@ -0,0 +1,117 @@
+
+
diff --git a/src/main/java/org/toop/UI/GameSelectorWindow.java b/src/main/java/org/toop/UI/GameSelectorWindow.java
new file mode 100644
index 0000000..8d64e60
--- /dev/null
+++ b/src/main/java/org/toop/UI/GameSelectorWindow.java
@@ -0,0 +1,57 @@
+package org.toop.UI;
+import org.toop.eventbus.GlobalEventBus;
+
+import javax.swing.*;
+import java.awt.event.ActionEvent;
+import java.awt.*;
+
+
+public class GameSelectorWindow extends JFrame {
+ private JPanel mainMenu;
+ private JTextField nameTextField;
+ private JTextField ipTextField;
+ private JTextField portTextField;
+ private JButton connectButton;
+ private JComboBox gameSelectorBox;
+ private JPanel cards;
+ private JPanel gameSelector;
+ private JFrame frame;
+ private JLabel fillAllFields;
+
+ public GameSelectorWindow() {
+ gameSelectorBox.addItem("Tic Tac Toe");
+ gameSelectorBox.addItem("Reversi");
+ //todo get supported games from server and add to gameSelectorBox
+ frame = new JFrame("Game Selector");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setSize(1920, 1080);
+ frame.setResizable(true);
+
+ init();
+ frame.add(mainMenu);
+ frame.setVisible(true);
+ //GlobalEventBus.subscribeAndRegister() Todo add game panel to frame when connection succeeds
+
+ }
+ private void init() {
+ connectButton.addActionListener((
+ ActionEvent e) -> {
+ if(!nameTextField.getText().equals("") && !ipTextField.getText().equals("") && !portTextField.getText().equals("")) {
+ System.out.println(gameSelectorBox.getSelectedItem().toString()); //todo attempt connecting to the server with given ip, port and name.
+ frame.remove(mainMenu);
+ UIGameBoard ttt = new UIGameBoard(gameSelectorBox.getSelectedItem().toString(),this);
+ frame.add(ttt.getTTTPanel());
+ frame.revalidate();
+ frame.repaint();
+ }else{
+ fillAllFields.setVisible(true);
+ }
+ });
+ }
+ public void returnToMainMenu() {
+ frame.removeAll();
+ frame.add(mainMenu);
+ frame.revalidate();
+ frame.repaint();
+ }
+}
diff --git a/src/main/java/org/toop/UI/UIGameBoard.form b/src/main/java/org/toop/UI/UIGameBoard.form
new file mode 100644
index 0000000..0d285e4
--- /dev/null
+++ b/src/main/java/org/toop/UI/UIGameBoard.form
@@ -0,0 +1,55 @@
+
+
diff --git a/src/main/java/org/toop/UI/UIGameBoard.java b/src/main/java/org/toop/UI/UIGameBoard.java
new file mode 100644
index 0000000..56c10a2
--- /dev/null
+++ b/src/main/java/org/toop/UI/UIGameBoard.java
@@ -0,0 +1,78 @@
+package org.toop.UI;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.toop.Main;
+import org.toop.eventbus.Events;
+import org.toop.eventbus.GlobalEventBus;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+
+public class UIGameBoard extends JFrame {
+ private final int TICTACTOE_SIZE = 3;
+ private final int REVERSI_SIZE = 8;
+ private static final Logger logger = LogManager.getLogger(Main.class);
+ private JLabel name;
+ private JLabel ip;
+ private JLabel gameName;
+ private JPanel tttPanel;
+ private JPanel cellPanel;
+ private JButton backToMainMenuButton;
+ private JButton[] buttons = new JButton[9];
+ private JButton[] cells;
+ public UIGameBoard(String game,GameSelectorWindow gameSelectorWindow) {
+
+ //cellPanel = new JPanel();
+ JPanel gamePanel = new JPanel();
+ if(game.toLowerCase().equals("tic tac toe")) {
+ gamePanel = createGridPanel(TICTACTOE_SIZE, TICTACTOE_SIZE);
+ }
+ if(game.toLowerCase().equals("reversi")) {
+ gamePanel = createGridPanel(REVERSI_SIZE, REVERSI_SIZE);
+ }
+
+ cellPanel.removeAll();
+ cellPanel.add(gamePanel);
+ cellPanel.revalidate();
+ cellPanel.repaint();
+ //tttPanel.add(cellPanel);
+ backToMainMenuButton.addActionListener((
+ ActionEvent e) -> {
+ gameSelectorWindow.returnToMainMenu();
+ System.out.println("gothere");
+ });
+ }
+ //Set the IP, game name and name
+ public void setIGN(String ip, String gameName, String name) {
+ this.ip.setText(ip);
+ this.gameName.setText(gameName);
+ this.name.setText(name);
+ }
+ public JPanel getTTTPanel() {
+ return tttPanel;
+ }
+ //Creates a grid of buttons and adds a global event bus event on click with the index of the button.
+ private JPanel createGridPanel(int sizeX, int sizeY) {
+ JPanel cellPanel = new JPanel(new GridLayout(sizeX,sizeY));
+ cells = new JButton[sizeX*sizeY];
+ for(int i =0; i < sizeX*sizeY; i++){
+ cells[i] = new JButton(" ");
+ cells[i].setPreferredSize(new Dimension(1000/sizeX,1000/sizeY));
+ cells[i].setFont(new Font("Arial", Font.BOLD, 480/sizeX));
+ cells[i].setFocusPainted(false);
+ cellPanel.add(cells[i]);
+ final int index = i;
+ cells[i].addActionListener((ActionEvent e) -> {
+ setCell(index,"X");//■ todo get current player
+ GlobalEventBus.post(new Events.ServerEvents.CellClicked(index));
+ logger.info("Grid button {} was clicked.", index);
+ });
+ }
+ return cellPanel;
+ }
+ public void setCell(int cell, String newValue){
+ cells[cell].setText(newValue);
+ }
+}
diff --git a/src/main/java/org/toop/eventbus/Events.java b/src/main/java/org/toop/eventbus/Events.java
index 0eb0d42..11d8550 100644
--- a/src/main/java/org/toop/eventbus/Events.java
+++ b/src/main/java/org/toop/eventbus/Events.java
@@ -110,6 +110,10 @@ public class Events implements IEvents {
*/
public record ChangeConnection(String ip, String port) { }
+ /**
+ * Triggers when a cell is clicked in one of the game boards.
+ */
+ public record CellClicked(int cell) {}
}
public static class EventBusEvents {