diff --git a/src/main/java/net/halbear/Executable/Init.java b/src/main/java/net/halbear/Executable/Init.java index 5568a6c..51f8818 100644 --- a/src/main/java/net/halbear/Executable/Init.java +++ b/src/main/java/net/halbear/Executable/Init.java @@ -1,5 +1,6 @@ package net.halbear.Executable; +import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig; import net.halbear.Terrain4J.EngineCore.Main.GameCore; import net.halbear.Terrain4J.EngineCore.Main.PrimaryRuntime; import org.tinylog.Logger; @@ -7,7 +8,7 @@ import org.tinylog.Logger; public class Init { public static void main(String[] args){ Logger.info("\nLaunching New Terrain4J Powered Software!"); - var GameEngine = new PrimaryRuntime("Terrain4J", new GameCore()); + var GameEngine = new PrimaryRuntime(EngineConfig.getInstance().GetSoftwareName(), new GameCore()); Logger.info("Launched Terrain4J Engine"); GameEngine.run(); } diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Display/GLFWImageParser.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Display/GLFWImageParser.java new file mode 100644 index 0000000..8baca5b --- /dev/null +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Display/GLFWImageParser.java @@ -0,0 +1,49 @@ +package net.halbear.Terrain4J.EngineCore.Display; + +import org.lwjgl.system.MemoryStack; + +import java.nio.ByteBuffer; +import java.nio.IntBuffer; + +import static org.lwjgl.stb.STBImage.stbi_load; + +public class GLFWImageParser { + + private ByteBuffer image; + private int GLFW_Width, GLFW_Height; + + GLFWImageParser(int width, int height, ByteBuffer image) { + this.image = image; + this.GLFW_Height = height; + this.GLFW_Width = width; + } + + public static GLFWImageParser LoadImage(String path) { + ByteBuffer image; + int Width, Height; + try (MemoryStack MemStack = MemoryStack.stackPush()) { + IntBuffer comp = MemStack.mallocInt(1); + IntBuffer width = MemStack.mallocInt(1); + IntBuffer height = MemStack.mallocInt(1); + image = stbi_load(path, width, height, comp, 4); + if (image == null) { + System.out.println("Could not load or find image inputted."); + } + Width = width.get(); + Height = height.get(); + } + return new GLFWImageParser(Width, Height, image); + } + + public ByteBuffer GetImage() { + return image; + } + + public int GetWidth() { + return GLFW_Width; + } + + public int GetHeight() { + return GLFW_Height; + } +} diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Display/Window.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Display/Window.java index 3522d51..643fab6 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Display/Window.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Display/Window.java @@ -3,10 +3,13 @@ package net.halbear.Terrain4J.EngineCore.Display; import net.halbear.Terrain4J.EngineCore.Input.KeyboardInput; import net.halbear.Terrain4J.EngineCore.Input.MouseListener; import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig; +import org.lwjgl.glfw.GLFWImage; import org.lwjgl.glfw.GLFWVidMode; import org.lwjgl.system.MemoryUtil; import org.tinylog.Logger; +import java.io.File; + import static org.lwjgl.glfw.Callbacks.glfwFreeCallbacks; import static org.lwjgl.glfw.GLFW.*; import static org.lwjgl.glfw.GLFWVulkan.glfwVulkanSupported; @@ -48,6 +51,24 @@ public class Window { height = h; }); + File IconLocation = new File("src/main/resources" + EngineConfig.getInstance().FetchIcon()); + GLFWImage Icon = GLFWImage.malloc(); + GLFWImage.Buffer IconBuffer = GLFWImage.malloc(1); + String IconPath = "src/main/java/net/halbear/Terrain4J/EngineCore/EngineSpecificAssets/terrain4JlogoFullBlocks.png"; + if (IconLocation.exists()){ + IconPath =IconLocation.getPath(); + Logger.debug("Loading Icon From Location [{}]",IconPath); + } else Logger.warn("Icon specified in config at Location [{}] does not exist, resorting to Engine Icon", IconLocation.getPath()); + Icon.set(GLFWImageParser.LoadImage(IconPath).GetWidth(), + GLFWImageParser.LoadImage(IconPath).GetHeight(), + GLFWImageParser.LoadImage(IconPath).GetImage()); + IconBuffer.put(0,Icon); + + glfwSetWindowIcon(handle, IconBuffer); + + IconBuffer.free(); //free the buffer once icon is set so when the program closes there isn't memory still floating around + Logger.debug("Freeing icon Buffer"); + glfwMakeContextCurrent(handle); if (EngineConfig.VSYNC) glfwSwapInterval(1); else glfwSwapInterval(0); diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/EngineSpecificAssets/terrain4JlogoFullBlocks.png b/src/main/java/net/halbear/Terrain4J/EngineCore/EngineSpecificAssets/terrain4JlogoFullBlocks.png new file mode 100644 index 0000000..264b793 Binary files /dev/null and b/src/main/java/net/halbear/Terrain4J/EngineCore/EngineSpecificAssets/terrain4JlogoFullBlocks.png differ diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/EngineSpecificAssets/terrain4JlogoNoBlocks.png b/src/main/java/net/halbear/Terrain4J/EngineCore/EngineSpecificAssets/terrain4JlogoNoBlocks.png new file mode 100644 index 0000000..847a490 Binary files /dev/null and b/src/main/java/net/halbear/Terrain4J/EngineCore/EngineSpecificAssets/terrain4JlogoNoBlocks.png differ diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/EngineSpecificAssets/terrain4JlogoNoBlocksCompressed.png b/src/main/java/net/halbear/Terrain4J/EngineCore/EngineSpecificAssets/terrain4JlogoNoBlocksCompressed.png new file mode 100644 index 0000000..85f29ce Binary files /dev/null and b/src/main/java/net/halbear/Terrain4J/EngineCore/EngineSpecificAssets/terrain4JlogoNoBlocksCompressed.png differ diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/EngineConfig.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/EngineConfig.java index b2afd57..b3afaa1 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/EngineConfig.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/EngineConfig.java @@ -33,6 +33,8 @@ public class EngineConfig { private boolean vkValidated; private String PhysicalDeviceName; private int RequestedImages; + private String IconPath = "/WindowResources/Icon/"; + private String IconName = "ProgramIcon.png"; public int GetRequestedImages(){ return RequestedImages; @@ -79,6 +81,8 @@ public class EngineConfig { } } if(SuccessfulLoad) { + IconName = (EngineConfigVar.getOrDefault("Software_Icon", "ProgramIcon.png").toString()); + IconPath = (EngineConfigVar.getOrDefault("Software_Icon_Path", "/WindowResources/Icon/").toString()); CapMainToTickRate = Boolean.parseBoolean(EngineConfigVar.getOrDefault("cap_main_to_tickrate", "false").toString()); MainTickRate = Integer.parseInt(EngineConfigVar.getOrDefault("main_thread_tickrate", "120").toString()); FastTickRate = Integer.parseInt(EngineConfigVar.getOrDefault("fast_thread_tickrate", "240").toString()); @@ -95,6 +99,8 @@ public class EngineConfig { } else if(!ConfigFile.exists()){ try { + EngineConfigVar.setProperty("Software_Icon","ProgramIcon.png"); + EngineConfigVar.setProperty("Software_Icon_Path","/WindowResources/Icon/"); EngineConfigVar.setProperty("cap_main_to_tickrate","false"); EngineConfigVar.setProperty("main_thread_tickrate","120"); EngineConfigVar.setProperty("fast_thread_tickrate","240"); @@ -145,4 +151,10 @@ public class EngineConfig { public String GetPhysicalDeviceName(){ return PhysicalDeviceName; } + public String GetSoftwareName(){ + return SOFTWARE_TITLE; + } + public String FetchIcon(){ + return IconPath + IconName; + } } diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/VulkanContext.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/VulkanContext.java index ce7124f..973c7b4 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/VulkanContext.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Logic/VulkanContext.java @@ -6,6 +6,7 @@ import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.PhysicalDe import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DisplayToScreen.Surface; import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DisplayToScreen.SwapChain; import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.VulkanInstance; +import org.tinylog.Logger; public class VulkanContext { public static int VulkanLayersOpen = 0; @@ -31,6 +32,8 @@ public class VulkanContext { device.cleanup(); PhysDevice.cleanup(); Instance.cleanup(); + Logger.debug("Render Thread Finished ending Vulkan Processes\nVulkan Layers Open:[{}]", VulkanContext.VulkanLayersOpen < 0 ? "All processes closed and vulkan instance removed" : VulkanContext.VulkanLayersOpen); + VulkanLayersOpen--; } public Device GetDevice(){ return device; diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Main/PrimaryRuntime.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Main/PrimaryRuntime.java index 7a6b345..e796e40 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Main/PrimaryRuntime.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Main/PrimaryRuntime.java @@ -19,12 +19,15 @@ public class PrimaryRuntime { private static Window window; private static EngineInstance engineInstance; public static int ThreadsOpen = 0; + public static boolean CanClose = false; + public static long ShutDownStart; public PrimaryRuntime(String windowTitle, GameLogic appLogic) { window = new Window(windowTitle); engineInstance = new EngineInstance(window, new Scene(window)); PrimaryThread = new MainThread(engineInstance, appLogic); DrawingThread = new RenderThread(window, engineInstance); + Thread.currentThread().setName("Terrain4J Primary Runtime Thread"); } public void UpdateTickRate(){ @@ -42,7 +45,7 @@ public class PrimaryRuntime { TickRate = (double) 1000000000 / (double) EngineConfig.getInstance().getTickRate(); long FrameAccuracy = EngineConfig.getInstance().getAccuracy(); Logger.debug("Primary Thread Started"); - while (!window.shouldClose()){ + while (!window.shouldClose() && running){ long now = System.nanoTime(); cycleDiff = now - InitialTime; FrameDiff += cycleDiff; @@ -71,14 +74,11 @@ public class PrimaryRuntime { } InitialTime = now; } + ShutDownStart = System.nanoTime(); + Logger.debug("Closing Software of name [{}]",EngineConfig.getInstance().GetSoftwareName()); PrimaryThread.KillThread(); DrawingThread.KillThread(); cleanup(); - Logger.debug("Waiting to close Primary Thread, making sure vulkan has shut down properly first and Engine Threads are closed\nThreads Open:[{}]\nVulkan Layers Open:[{}]",ThreadsOpen, VulkanContext.VulkanLayersOpen); - while(ThreadsOpen > 0 || VulkanContext.VulkanLayersOpen > 0){ - - } - Logger.debug("Closing Primary Thread"); } @@ -91,5 +91,15 @@ public class PrimaryRuntime { private void cleanup() { engineInstance.cleanup(); window.cleanup(); + Logger.debug("Process still running: [{}]",Thread.getAllStackTraces().keySet().toString()); + if (ThreadsOpen > 0 || VulkanContext.VulkanLayersOpen > -1) { + Logger.debug("Waiting to close Primary Thread, making sure vulkan has shut down properly first and Engine Threads are closed\nThreads Open:[{}]\nVulkan Layers Open:[{}]", ThreadsOpen, VulkanContext.VulkanLayersOpen < 0 ? "All processes closed and vulkan instance removed" : VulkanContext.VulkanLayersOpen); + while ((ThreadsOpen > 0 || VulkanContext.VulkanLayersOpen > 0) && VulkanContext.VulkanLayersOpen > -1 && !CanClose) { + + } + } + Logger.debug("Closing Primary Thread, Thread: [{}]",Thread.currentThread().toString()); + double ShutDownTime = Math.floor(((double)(System.nanoTime() - ShutDownStart)/1000000.0)*1000.0)/1000.0; + Logger.info("Successful stable Shut Down of Terrain4J in [{}] MilliSeconds", ShutDownTime); } } diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/MainThread.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/MainThread.java index 1c32894..90346b7 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/MainThread.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/MainThread.java @@ -23,7 +23,8 @@ public class MainThread implements Runnable { } public void cleanup(){ gameLogic.cleanup(); - Logger.debug("Closing Main Thread"); + PrimaryRuntime.ThreadsOpen--; + Logger.debug("Closing Main Thread, Thread: [{}]",Thread.currentThread().toString()); } public Thread FetchMainThread(){ return mainThread; @@ -37,6 +38,7 @@ public class MainThread implements Runnable { Logger.debug("Starting Main Thread"); UpdateTickRateThreshold(); mainThread = new Thread(this); + mainThread.setName("Terrain4J Main Engine Thread"); } public void UpdateTickRateThreshold(){ CappedToTickRate = EngineConfig.getInstance().GetMainTickCap(); @@ -86,6 +88,5 @@ public class MainThread implements Runnable { InitialTime = now; } cleanup(); - PrimaryRuntime.ThreadsOpen--; } } diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/RenderThread.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/RenderThread.java index 0ff7a28..399a277 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/RenderThread.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Threads/RenderThread.java @@ -4,6 +4,7 @@ import net.halbear.Terrain4J.EngineCore.Display.Render; import net.halbear.Terrain4J.EngineCore.Display.Window; import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig; import net.halbear.Terrain4J.EngineCore.Logic.EngineInstance; +import net.halbear.Terrain4J.EngineCore.Logic.VulkanContext; import net.halbear.Terrain4J.EngineCore.Main.PrimaryRuntime; import org.tinylog.Logger; @@ -18,6 +19,7 @@ public class RenderThread implements Runnable { //this.window = window; render = new Render(engineInstance); renderThread = new Thread(this); + renderThread.setName("Terrain4J Vulkan Render Thread"); } public void KillThread(){ @@ -31,7 +33,9 @@ public class RenderThread implements Runnable { } private void cleanup() { render.cleanup(); - Logger.debug("Closing Render Thread"); + PrimaryRuntime.ThreadsOpen--; + Logger.debug("Closing Render Thread, Thread: [{}]",Thread.currentThread().toString()); + if (PrimaryRuntime.ThreadsOpen <= 0 && VulkanContext.VulkanLayersOpen < 0) PrimaryRuntime.CanClose = true; } @Override public void run() { @@ -62,6 +66,5 @@ public class RenderThread implements Runnable { } //PrimaryRuntime.CloseRuntime(); cleanup(); - PrimaryRuntime.ThreadsOpen--; } } diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Vulkan/Structure/DeviceLayers/GPUSynchronisation/Fence.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Vulkan/Structure/DeviceLayers/GPUSynchronisation/Fence.java index 372e411..51b2259 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Vulkan/Structure/DeviceLayers/GPUSynchronisation/Fence.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Vulkan/Structure/DeviceLayers/GPUSynchronisation/Fence.java @@ -3,6 +3,7 @@ package net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.GPUSynchr import net.halbear.Terrain4J.EngineCore.Logic.VulkanContext; import org.lwjgl.system.MemoryStack; import org.lwjgl.vulkan.VkFenceCreateInfo; +import org.tinylog.Logger; import java.nio.LongBuffer; @@ -27,6 +28,7 @@ public class Fence { } public void cleanup(VulkanContext vulkanContext){ + Logger.debug("Destroying Vulkan Fence"); vkDestroyFence(vulkanContext.GetDevice().FetchVulkanDevice(), VulkanFence, null); } diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Vulkan/Structure/DeviceLayers/GPUSynchronisation/Semaphore.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Vulkan/Structure/DeviceLayers/GPUSynchronisation/Semaphore.java index 49cbc39..2039eb2 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Vulkan/Structure/DeviceLayers/GPUSynchronisation/Semaphore.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Vulkan/Structure/DeviceLayers/GPUSynchronisation/Semaphore.java @@ -3,6 +3,7 @@ package net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.GPUSynchr import net.halbear.Terrain4J.EngineCore.Logic.VulkanContext; import org.lwjgl.system.MemoryStack; import org.lwjgl.vulkan.VkSemaphoreCreateInfo; +import org.tinylog.Logger; import java.nio.LongBuffer; @@ -22,6 +23,7 @@ public class Semaphore { } public void cleanup(VulkanContext vulkanContext){ + Logger.debug("Destroying Vulkan Semaphore"); vkDestroySemaphore(vulkanContext.GetDevice().FetchVulkanDevice(), VulkanSemaphore, null); } public long GetSemaphore(){ diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/Vulkan/Structure/DisplayToScreen/ImageView.java b/src/main/java/net/halbear/Terrain4J/EngineCore/Vulkan/Structure/DisplayToScreen/ImageView.java index 611d0b9..3cc9e78 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/Vulkan/Structure/DisplayToScreen/ImageView.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/Vulkan/Structure/DisplayToScreen/ImageView.java @@ -3,6 +3,7 @@ package net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DisplayToScreen; import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.Device; import org.lwjgl.system.MemoryStack; import org.lwjgl.vulkan.VkImageViewCreateInfo; +import org.tinylog.Logger; import java.nio.LongBuffer; @@ -39,6 +40,7 @@ public class ImageView { } public void cleanup(Device device){ + Logger.debug("Destroying Image View"); vkDestroyImageView(device.FetchVulkanDevice(), VulkanImageView, null); } diff --git a/src/main/resources/DefaultEngineConfig.properties b/src/main/resources/DefaultEngineConfig.properties index c3dae9c..d0c23ea 100644 --- a/src/main/resources/DefaultEngineConfig.properties +++ b/src/main/resources/DefaultEngineConfig.properties @@ -15,4 +15,6 @@ vsync=true #This is the name of the GPU you want the engine to use PhysicalDeviceName= #Title that shows up on app window -Software_Title=Terrain4J Game Engine \ No newline at end of file +Software_Title=Terrain4J Game Engine +Software_Icon=ProgramIcon.png +Software_Icon_Path=/WindowResources/Icon/ \ No newline at end of file diff --git a/src/main/resources/WindowResources/Icon/ProgramIcon.png b/src/main/resources/WindowResources/Icon/ProgramIcon.png new file mode 100644 index 0000000..264b793 Binary files /dev/null and b/src/main/resources/WindowResources/Icon/ProgramIcon.png differ diff --git a/terrain4j.properties b/terrain4j.properties index f95993b..3928f01 100644 --- a/terrain4j.properties +++ b/terrain4j.properties @@ -17,4 +17,6 @@ RequestedImages=3 PhysicalDeviceName= #Title that shows up on app window Software_Title=Terrain4J Game Engine +Software_Icon=ProgramIcon.png +Software_Icon_Path=/WindowResources/Icon/