2019-10-05 21:02:54 +00:00
|
|
|
/*
|
|
|
|
* Minecraft Forge
|
|
|
|
* Copyright (c) 2016-2019.
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation version 2.1
|
|
|
|
* of the License.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
package net.minecraftforge.fml.loading.progress;
|
|
|
|
|
|
|
|
import org.apache.commons.lang3.tuple.Pair;
|
2019-11-23 20:37:56 +00:00
|
|
|
import org.apache.logging.log4j.LogManager;
|
2019-10-05 21:02:54 +00:00
|
|
|
import org.lwjgl.glfw.GLFWErrorCallback;
|
|
|
|
import org.lwjgl.glfw.GLFWVidMode;
|
|
|
|
import org.lwjgl.opengl.GL;
|
|
|
|
import org.lwjgl.opengl.GL11;
|
|
|
|
import org.lwjgl.opengl.GL14;
|
|
|
|
import org.lwjgl.stb.STBEasyFont;
|
|
|
|
import org.lwjgl.system.MemoryStack;
|
|
|
|
import org.lwjgl.system.MemoryUtil;
|
|
|
|
|
|
|
|
import java.lang.management.ManagementFactory;
|
|
|
|
import java.lang.management.MemoryUsage;
|
|
|
|
import java.nio.ByteBuffer;
|
|
|
|
import java.nio.IntBuffer;
|
|
|
|
import java.util.List;
|
|
|
|
|
|
|
|
import static org.lwjgl.glfw.Callbacks.glfwFreeCallbacks;
|
|
|
|
import static org.lwjgl.glfw.GLFW.*;
|
|
|
|
import static org.lwjgl.glfw.GLFW.glfwCreateWindow;
|
|
|
|
import static org.lwjgl.opengl.GL11.*;
|
|
|
|
import static org.lwjgl.system.MemoryStack.stackPush;
|
|
|
|
import static org.lwjgl.system.MemoryUtil.NULL;
|
|
|
|
|
|
|
|
class ClientVisualization implements EarlyProgressVisualization.Visualization {
|
|
|
|
private final int screenWidth = 800;
|
|
|
|
private final int screenHeight = 400;
|
|
|
|
private long window;
|
|
|
|
private Thread thread;
|
|
|
|
private boolean running;
|
|
|
|
|
|
|
|
private void initWindow() {
|
|
|
|
GLFWErrorCallback.createPrint(System.err).set();
|
|
|
|
|
2019-11-23 20:37:56 +00:00
|
|
|
long glfwInitBegin = System.nanoTime();
|
2019-10-05 21:02:54 +00:00
|
|
|
if (!glfwInit()) {
|
|
|
|
throw new IllegalStateException("Unable to initialize GLFW");
|
|
|
|
}
|
2019-11-23 20:37:56 +00:00
|
|
|
long glfwInitEnd = System.nanoTime();
|
|
|
|
|
|
|
|
if (glfwInitEnd - glfwInitBegin > 1e9) {
|
|
|
|
LogManager.getLogger().fatal("WARNING : glfwInit took {} seconds to start.", (glfwInitEnd-glfwInitBegin) / 1.0e9);
|
|
|
|
}
|
2019-10-05 21:02:54 +00:00
|
|
|
|
|
|
|
glfwDefaultWindowHints();
|
|
|
|
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
|
|
|
|
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
|
|
|
|
|
|
|
|
window = glfwCreateWindow(screenWidth, screenHeight, "FML early loading progress", NULL, NULL);
|
|
|
|
if (window == NULL) {
|
|
|
|
throw new RuntimeException("Failed to create the GLFW window"); // ignore it and make the GUI optional?
|
|
|
|
}
|
|
|
|
|
|
|
|
try (MemoryStack stack = stackPush()) {
|
|
|
|
IntBuffer pWidth = stack.mallocInt(1);
|
|
|
|
IntBuffer pHeight = stack.mallocInt(1);
|
|
|
|
IntBuffer monPosLeft = stack.mallocInt(1);
|
|
|
|
IntBuffer monPosTop = stack.mallocInt(1);
|
|
|
|
glfwGetWindowSize(window, pWidth, pHeight);
|
|
|
|
GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
|
|
|
|
glfwGetMonitorPos(glfwGetPrimaryMonitor(), monPosLeft, monPosTop);
|
|
|
|
// Center the window
|
|
|
|
glfwSetWindowPos(
|
|
|
|
window,
|
|
|
|
(vidmode.width() - pWidth.get(0)) / 2 + monPosLeft.get(0),
|
|
|
|
(vidmode.height() - pHeight.get(0)) / 2 + monPosTop.get(0)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
glfwMakeContextCurrent(window);
|
|
|
|
glfwSwapInterval(1);
|
|
|
|
glfwShowWindow(window);
|
|
|
|
GL.createCapabilities();
|
|
|
|
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void renderProgress() {
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glLoadIdentity();
|
|
|
|
glOrtho(0.0D, screenWidth, screenHeight, 0.0D, -1000.0D, 1000.0D);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadIdentity();
|
|
|
|
|
|
|
|
// // replace with more modern opengl?
|
|
|
|
// glBegin(GL_QUADS);
|
|
|
|
// glColor3f(0.1f, 0.1f, 0.9f);
|
|
|
|
// glVertex2f(0, 0);
|
|
|
|
// glVertex2f(0, screenHeight);
|
|
|
|
// glVertex2f(screenWidth * progress, screenHeight);
|
|
|
|
// glVertex2f(screenWidth * progress, 0);
|
|
|
|
// glEnd();
|
|
|
|
|
|
|
|
glEnableClientState(GL11.GL_VERTEX_ARRAY);
|
|
|
|
glEnable(GL_BLEND);
|
|
|
|
renderMessages();
|
|
|
|
glfwSwapBuffers(window);
|
|
|
|
glfwPollEvents();
|
|
|
|
}
|
|
|
|
|
|
|
|
private static float clamp(float num, float min, float max) {
|
|
|
|
if (num < min) {
|
|
|
|
return min;
|
|
|
|
} else {
|
|
|
|
return num > max ? max : num;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private static int clamp(int num, int min, int max) {
|
|
|
|
if (num < min) {
|
|
|
|
return min;
|
|
|
|
} else {
|
|
|
|
return num > max ? max : num;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private static int hsvToRGB(float hue, float saturation, float value) {
|
|
|
|
int i = (int)(hue * 6.0F) % 6;
|
|
|
|
float f = hue * 6.0F - (float)i;
|
|
|
|
float f1 = value * (1.0F - saturation);
|
|
|
|
float f2 = value * (1.0F - f * saturation);
|
|
|
|
float f3 = value * (1.0F - (1.0F - f) * saturation);
|
|
|
|
float f4;
|
|
|
|
float f5;
|
|
|
|
float f6;
|
|
|
|
switch(i) {
|
|
|
|
case 0:
|
|
|
|
f4 = value;
|
|
|
|
f5 = f3;
|
|
|
|
f6 = f1;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
f4 = f2;
|
|
|
|
f5 = value;
|
|
|
|
f6 = f1;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
f4 = f1;
|
|
|
|
f5 = value;
|
|
|
|
f6 = f3;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
f4 = f1;
|
|
|
|
f5 = f2;
|
|
|
|
f6 = value;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
f4 = f3;
|
|
|
|
f5 = f1;
|
|
|
|
f6 = value;
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
f4 = value;
|
|
|
|
f5 = f1;
|
|
|
|
f6 = f2;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
throw new RuntimeException("Something went wrong when converting from HSV to RGB. Input was " + hue + ", " + saturation + ", " + value);
|
|
|
|
}
|
|
|
|
|
|
|
|
int j = clamp((int)(f4 * 255.0F), 0, 255);
|
|
|
|
int k = clamp((int)(f5 * 255.0F), 0, 255);
|
|
|
|
int l = clamp((int)(f6 * 255.0F), 0, 255);
|
|
|
|
return j << 16 | k << 8 | l;
|
|
|
|
}
|
|
|
|
|
|
|
|
private void renderMessages() {
|
|
|
|
List<Pair<Integer, StartupMessageManager.Message>> messages = StartupMessageManager.getMessages();
|
|
|
|
for (int i = 0; i < messages.size(); i++) {
|
|
|
|
final Pair<Integer, StartupMessageManager.Message> pair = messages.get(i);
|
|
|
|
final float fade = clamp((4000.0f - (float) pair.getLeft() - ( i - 4 ) * 1000.0f) / 5000.0f, 0.0f, 1.0f);
|
|
|
|
if (fade <0.01f) continue;
|
|
|
|
StartupMessageManager.Message msg = pair.getRight();
|
|
|
|
renderMessage(msg.getText(), msg.getTypeColour(), ((screenHeight - 15) / 20) - i, fade);
|
|
|
|
}
|
|
|
|
renderMemoryInfo();
|
|
|
|
}
|
|
|
|
|
|
|
|
private static final float[] memorycolour = new float[] { 0.0f, 0.0f, 0.0f};
|
|
|
|
|
|
|
|
private void renderMemoryInfo() {
|
|
|
|
final MemoryUsage heapusage = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage();
|
|
|
|
final MemoryUsage offheapusage = ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage();
|
|
|
|
final float pctmemory = (float) heapusage.getUsed() / heapusage.getMax();
|
|
|
|
String memory = String.format("Memory Heap: %d / %d MB (%.1f%%) OffHeap: %d MB", heapusage.getUsed() >> 20, heapusage.getMax() >> 20, pctmemory * 100.0, offheapusage.getUsed() >> 20);
|
|
|
|
|
|
|
|
final int i = hsvToRGB((1.0f - (float)Math.pow(pctmemory, 1.5f)) / 3f, 1.0f, 0.5f);
|
|
|
|
memorycolour[2] = ((i) & 0xFF) / 255.0f;
|
|
|
|
memorycolour[1] = ((i >> 8 ) & 0xFF) / 255.0f;
|
|
|
|
memorycolour[0] = ((i >> 16 ) & 0xFF) / 255.0f;
|
|
|
|
renderMessage(memory, memorycolour, 1, 1.0f);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void renderMessage(final String message, final float[] colour, int row, float alpha) {
|
|
|
|
ByteBuffer charBuffer = MemoryUtil.memAlloc(message.length() * 270);
|
|
|
|
int quads = STBEasyFont.stb_easy_font_print(0, 0, message, null, charBuffer);
|
|
|
|
|
|
|
|
glVertexPointer(3, GL11.GL_FLOAT, 16, charBuffer);
|
|
|
|
glEnable(GL_BLEND);
|
|
|
|
GL14.glBlendColor(0,0,0, alpha);
|
|
|
|
glBlendFunc(GL14.GL_CONSTANT_ALPHA, GL14.GL_ONE_MINUS_CONSTANT_ALPHA);
|
|
|
|
glColor3f(colour[0], colour[1], colour[2]);
|
|
|
|
glPushMatrix();
|
|
|
|
glTranslatef(10, row * 20, 0);
|
|
|
|
glScalef(2, 2, 1);
|
|
|
|
glDrawArrays(GL11.GL_QUADS, 0, quads * 4);
|
|
|
|
glPopMatrix();
|
|
|
|
MemoryUtil.memFree(charBuffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void closeWindow() {
|
|
|
|
glfwFreeCallbacks(window);
|
|
|
|
glfwDestroyWindow(window);
|
|
|
|
glfwTerminate();
|
|
|
|
glfwSetErrorCallback(null).free();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void start() {
|
|
|
|
thread = new Thread(this::run);
|
|
|
|
thread.setDaemon(true);
|
|
|
|
thread.start();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void run() {
|
|
|
|
running = true;
|
2019-11-23 20:37:56 +00:00
|
|
|
initWindow();
|
2019-10-05 21:02:54 +00:00
|
|
|
while (running) {
|
|
|
|
renderProgress();
|
|
|
|
try {
|
|
|
|
Thread.sleep(50);
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
closeWindow();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void join() {
|
|
|
|
running = false;
|
|
|
|
try {
|
|
|
|
thread.join();
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|