package me.hammerle.snuviengine.api; import org.lwjgl.glfw.*; import org.lwjgl.opengl.*; import static org.lwjgl.glfw.Callbacks.*; import static org.lwjgl.glfw.GLFW.*; import static org.lwjgl.opengl.GL11.*; import static org.lwjgl.system.MemoryUtil.*; public abstract class Engine { private static final String VERSION = "0.0.1"; public static final int TILE_SIZE = 16; public static final float SCALE = 2.0f; private long window; private int fpsIndex = 0; private final long[] fps = new long[100]; private long fpsSum = 0; private double currentFps = 0; private int tpsIndex = 0; private final long[] tps = new long[100]; private long tpsSum = 0; private double currentTps = 0; private long nanosPerTick = 10_000_000; public Engine() { } public final void run() { initGLFW(); loop(); glfwFreeCallbacks(window); glfwDestroyWindow(window); glfwTerminate(); GLFWErrorCallback error = glfwSetErrorCallback(null); if(error != null) { error.free(); } } private void initGLFW() { GLFWErrorCallback.createPrint(System.err).set(); if(!glfwInit()) { throw new IllegalStateException("Unable to initialize GLFW"); } glfwDefaultWindowHints(); glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); window = glfwCreateWindow(Shader.getViewWidth(), Shader.getViewHeight(), "SnuviEngine " + VERSION, NULL, NULL); if(window == NULL) { throw new RuntimeException("Failed to create the GLFW window"); } glfwSetKeyCallback(window, (w, key, scancode, action, mods) -> { if(action == GLFW_RELEASE) { KeyHandler.onKeyUpEvent(key); if(key == GLFW_KEY_ESCAPE) { glfwSetWindowShouldClose(window, true); } } else if(action == GLFW_PRESS) { KeyHandler.onKeyDownEvent(key); } }); glfwSetFramebufferSizeCallback(window, (w, fwidth, fheight) -> { glViewport(0, 0, fwidth, fheight); Shader.setViewPort(fwidth, fheight); }); //glfwSetWindowAspectRatio(window, 16, 9); glfwMakeContextCurrent(window); glfwSwapInterval(1); glfwShowWindow(window); } private void loop() { GL.createCapabilities(); long lastFrame = System.nanoTime(); long lastTick = System.nanoTime(); long time; long lag = 0; Shader.init(); init(); while(!glfwWindowShouldClose(window)) { glfwSwapBuffers(window); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); time = System.nanoTime(); fpsSum -= fps[fpsIndex]; fps[fpsIndex] = time - lastFrame; fpsSum += fps[fpsIndex]; lag += fps[fpsIndex]; fpsIndex = (fpsIndex + 1) % fps.length; lastFrame = time; currentFps = (1_000_000_000.0 * fps.length) / fpsSum; while(lag >= nanosPerTick) { lag -= nanosPerTick; time = System.nanoTime(); tpsSum -= tps[tpsIndex]; tps[tpsIndex] = time - lastTick; tpsSum += tps[tpsIndex]; tpsIndex = (tpsIndex + 1) % tps.length; lastTick = time; currentTps = (1_000_000_000.0 * tps.length) / tpsSum; KeyHandler.tick(); tick(); } Shader.doTasks(); renderTick(); glfwPollEvents(); } } public final void setNanosPerTick(long nanos) { nanosPerTick = nanos; } public final double getTps() { return currentTps; } public final double getFps() { return currentFps; } public abstract void init(); public abstract void tick(); public abstract void renderTick(); }