261 lines
8.1 KiB
Java
261 lines
8.1 KiB
Java
|
package io.gitlab.jfronny.glaunch;
|
||
|
|
||
|
import com.google.gson.Gson;
|
||
|
import com.google.gson.GsonBuilder;
|
||
|
import imgui.ImGui;
|
||
|
import imgui.ImGuiIO;
|
||
|
import imgui.flag.ImGuiConfigFlags;
|
||
|
import imgui.gl3.ImGuiImplGl3;
|
||
|
import imgui.glfw.ImGuiImplGlfw;
|
||
|
import io.gitlab.jfronny.glaunch.gson.MinecraftArgumentDeserializer;
|
||
|
import io.gitlab.jfronny.glaunch.model.MinecraftArgument;
|
||
|
import io.gitlab.jfronny.glaunch.windows.MainWindow;
|
||
|
import org.apache.logging.log4j.LogManager;
|
||
|
import org.apache.logging.log4j.Logger;
|
||
|
import org.lwjgl.glfw.*;
|
||
|
import org.lwjgl.opengl.GL;
|
||
|
import org.lwjgl.opengl.GL32;
|
||
|
import org.lwjgl.system.MemoryStack;
|
||
|
import org.lwjgl.system.MemoryUtil;
|
||
|
|
||
|
import java.io.IOException;
|
||
|
import java.nio.IntBuffer;
|
||
|
import java.nio.file.Files;
|
||
|
import java.nio.file.Path;
|
||
|
import java.util.LinkedHashSet;
|
||
|
import java.util.Objects;
|
||
|
import java.util.Set;
|
||
|
|
||
|
//TODO generate gitignore
|
||
|
//TODO mods browser
|
||
|
//TODO load and launch instance from metadata
|
||
|
//TODO allow instance sync through metadata
|
||
|
public class GLaunch {
|
||
|
public static final Set<Window> WINDOWS = new LinkedHashSet<>();
|
||
|
public static final Logger LOGGER = LogManager.getFormatterLogger("GLaunch");
|
||
|
public static final Gson GSON = new GsonBuilder()
|
||
|
.registerTypeAdapter(MinecraftArgument.class, new MinecraftArgumentDeserializer())
|
||
|
.create();
|
||
|
public static final Path CACHE_DIR = Path.of("run/cache");
|
||
|
public static final Path INSTANCE_DIR = Path.of("run/instances");
|
||
|
public static final Path ASSETS_DIR = Path.of("run/assets");
|
||
|
public static final Path LIBRARIES_DIR = Path.of("run/libraries");
|
||
|
public static final Config CONFIG = new Config(); //TODO from gson
|
||
|
|
||
|
public static void main(String[] args) throws IOException {
|
||
|
LOGGER.info("Setting up cache dir");
|
||
|
if (!Files.exists(CACHE_DIR)) Files.createDirectories(CACHE_DIR);
|
||
|
if (!Files.exists(INSTANCE_DIR)) Files.createDirectories(INSTANCE_DIR);
|
||
|
if (!Files.exists(ASSETS_DIR)) Files.createDirectories(ASSETS_DIR);
|
||
|
if (!Files.exists(LIBRARIES_DIR)) Files.createDirectories(LIBRARIES_DIR);
|
||
|
LOGGER.info("Initializing UI");
|
||
|
WINDOWS.add(new MainWindow());
|
||
|
GLaunch gLaunch = new GLaunch();
|
||
|
gLaunch.init();
|
||
|
gLaunch.run();
|
||
|
gLaunch.dispose();
|
||
|
}
|
||
|
|
||
|
public static void open(Window window) {
|
||
|
WINDOWS.add(window);
|
||
|
}
|
||
|
|
||
|
private final ImGuiImplGlfw imGuiGlfw = new ImGuiImplGlfw();
|
||
|
private final ImGuiImplGl3 imGuiGl3 = new ImGuiImplGl3();
|
||
|
|
||
|
private String glslVersion = null;
|
||
|
|
||
|
/**
|
||
|
* Pointer to the native GLFW window.
|
||
|
*/
|
||
|
protected long handle;
|
||
|
|
||
|
/**
|
||
|
* Method to initialize application.
|
||
|
*/
|
||
|
protected void init() {
|
||
|
initWindow();
|
||
|
initImGui();
|
||
|
imGuiGlfw.init(handle, true);
|
||
|
imGuiGl3.init(glslVersion);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Method to dispose all used application resources and destroy its window.
|
||
|
*/
|
||
|
protected void dispose() {
|
||
|
imGuiGl3.dispose();
|
||
|
imGuiGlfw.dispose();
|
||
|
disposeImGui();
|
||
|
disposeWindow();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Method to create and initialize GLFW window.
|
||
|
*/
|
||
|
protected void initWindow() {
|
||
|
GLFWErrorCallback.createPrint(System.err).set();
|
||
|
|
||
|
if (!GLFW.glfwInit()) {
|
||
|
throw new IllegalStateException("Unable to initialize GLFW");
|
||
|
}
|
||
|
|
||
|
decideGlGlslVersions();
|
||
|
|
||
|
GLFW.glfwWindowHint(GLFW.GLFW_VISIBLE, GLFW.GLFW_FALSE);
|
||
|
GLFW.glfwWindowHint(GLFW.GLFW_RESIZABLE, GLFW.GLFW_FALSE);
|
||
|
handle = GLFW.glfwCreateWindow(10, 10, "GLaunch", MemoryUtil.NULL, MemoryUtil.NULL);
|
||
|
|
||
|
if (handle == MemoryUtil.NULL) {
|
||
|
throw new RuntimeException("Failed to create the GLFW window");
|
||
|
}
|
||
|
|
||
|
try (MemoryStack stack = MemoryStack.stackPush()) {
|
||
|
final IntBuffer pWidth = stack.mallocInt(1); // int*
|
||
|
final IntBuffer pHeight = stack.mallocInt(1); // int*
|
||
|
|
||
|
GLFW.glfwGetWindowSize(handle, pWidth, pHeight);
|
||
|
final GLFWVidMode vidmode = Objects.requireNonNull(GLFW.glfwGetVideoMode(GLFW.glfwGetPrimaryMonitor()));
|
||
|
GLFW.glfwSetWindowPos(handle, (vidmode.width() - pWidth.get(0)) / 2, (vidmode.height() - pHeight.get(0)) / 2);
|
||
|
}
|
||
|
|
||
|
GLFW.glfwMakeContextCurrent(handle);
|
||
|
|
||
|
GL.createCapabilities();
|
||
|
|
||
|
GLFW.glfwSwapInterval(GLFW.GLFW_TRUE);
|
||
|
|
||
|
//GLFW.glfwShowWindow(handle);
|
||
|
|
||
|
clearBuffer();
|
||
|
renderBuffer();
|
||
|
|
||
|
GLFW.glfwSetWindowSizeCallback(handle, new GLFWWindowSizeCallback() {
|
||
|
@Override
|
||
|
public void invoke(final long window, final int width, final int height) {
|
||
|
runFrame();
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
private void decideGlGlslVersions() {
|
||
|
final boolean isMac = System.getProperty("os.name").toLowerCase().contains("mac");
|
||
|
if (isMac) {
|
||
|
glslVersion = "#version 150";
|
||
|
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||
|
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MINOR, 2);
|
||
|
GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_PROFILE, GLFW.GLFW_OPENGL_CORE_PROFILE); // 3.2+ only
|
||
|
GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_FORWARD_COMPAT, GLFW.GLFW_TRUE); // Required on Mac
|
||
|
} else {
|
||
|
glslVersion = "#version 130";
|
||
|
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||
|
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MINOR, 0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Method to initialize Dear ImGui context. Could be overridden to do custom Dear ImGui setup before application start.
|
||
|
*/
|
||
|
protected void initImGui() {
|
||
|
ImGui.createContext();
|
||
|
ImGuiIO io = ImGui.getIO();
|
||
|
io.addConfigFlags(ImGuiConfigFlags.ViewportsEnable);
|
||
|
//io.setConfigViewportsNoDecoration(false);
|
||
|
io.setConfigViewportsNoAutoMerge(true);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Main application loop.
|
||
|
*/
|
||
|
protected void run() {
|
||
|
while (!GLFW.glfwWindowShouldClose(handle)) {
|
||
|
runFrame();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Method used to run the next frame.
|
||
|
*/
|
||
|
protected void runFrame() {
|
||
|
startFrame();
|
||
|
process();
|
||
|
endFrame();
|
||
|
}
|
||
|
|
||
|
public void process() {
|
||
|
if (GLaunch.WINDOWS.isEmpty()) close();
|
||
|
else {
|
||
|
for (Window window : GLaunch.WINDOWS.toArray(new Window[0])) {
|
||
|
if (window.isNew()) window.preFirstDraw();
|
||
|
ImGui.begin(window.getName());
|
||
|
window.draw();
|
||
|
ImGui.end();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Method used to clear the OpenGL buffer.
|
||
|
*/
|
||
|
private void clearBuffer() {
|
||
|
GL32.glClear(GL32.GL_COLOR_BUFFER_BIT | GL32.GL_DEPTH_BUFFER_BIT);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Method called at the beginning of the main cycle.
|
||
|
* It clears OpenGL buffer and starts an ImGui frame.
|
||
|
*/
|
||
|
protected void startFrame() {
|
||
|
clearBuffer();
|
||
|
imGuiGlfw.newFrame();
|
||
|
ImGui.newFrame();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Method called in the end of the main cycle.
|
||
|
* It renders ImGui and swaps GLFW buffers to show an updated frame.
|
||
|
*/
|
||
|
protected void endFrame() {
|
||
|
ImGui.render();
|
||
|
imGuiGl3.renderDrawData(ImGui.getDrawData());
|
||
|
|
||
|
if (ImGui.getIO().hasConfigFlags(ImGuiConfigFlags.ViewportsEnable)) {
|
||
|
final long backupWindowPtr = GLFW.glfwGetCurrentContext();
|
||
|
ImGui.updatePlatformWindows();
|
||
|
ImGui.renderPlatformWindowsDefault();
|
||
|
GLFW.glfwMakeContextCurrent(backupWindowPtr);
|
||
|
}
|
||
|
|
||
|
renderBuffer();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Method to render the OpenGL buffer and poll window events.
|
||
|
*/
|
||
|
private void renderBuffer() {
|
||
|
GLFW.glfwSwapBuffers(handle);
|
||
|
GLFW.glfwPollEvents();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Method to destroy Dear ImGui context.
|
||
|
*/
|
||
|
protected void disposeImGui() {
|
||
|
ImGui.destroyContext();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Method to destroy GLFW window.
|
||
|
*/
|
||
|
protected void disposeWindow() {
|
||
|
Callbacks.glfwFreeCallbacks(handle);
|
||
|
GLFW.glfwDestroyWindow(handle);
|
||
|
GLFW.glfwTerminate();
|
||
|
Objects.requireNonNull(GLFW.glfwSetErrorCallback(null)).free();
|
||
|
}
|
||
|
|
||
|
public void close() {
|
||
|
GLFW.glfwSetWindowShouldClose(handle, true);
|
||
|
}
|
||
|
}
|