animated-chunks/src/main/java/me/topchetoeu/animatedchunks/gui/ChunkPreview.java

333 lines
11 KiB
Java

package me.topchetoeu.animatedchunks.gui;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.opengl.GL11;
import com.mojang.blaze3d.systems.RenderSystem;
import me.topchetoeu.animatedchunks.AnimatedChunks;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.Drawable;
import net.minecraft.client.gui.DrawableHelper;
import net.minecraft.client.gui.Element;
import net.minecraft.client.gui.Selectable;
import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder;
import net.minecraft.client.gui.screen.narration.NarrationPart;
import net.minecraft.client.render.BufferBuilder;
import net.minecraft.client.render.BufferRenderer;
import net.minecraft.client.render.GameRenderer;
import net.minecraft.client.render.Tessellator;
import net.minecraft.client.render.VertexFormat;
import net.minecraft.client.render.VertexFormats;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.Matrix4f;
import net.minecraft.util.math.Quaternion;
import net.minecraft.util.math.Vec3f;
import net.minecraft.util.math.Vector4f;
import net.minecraft.util.math.ColorHelper.Argb;
public class ChunkPreview extends DrawableHelper implements Drawable, Element, Selectable, BoundboxProvider {
public static interface ClickAction {
void onClick();
}
public ClickAction clickAction;
public final MinecraftClient client;
private boolean clicked = false;
private boolean rotating = false;
private boolean focused = false;
private boolean hovered = false;
private float globalProgress = 0;
private float duration = 0;
private float mouseStartX, mouseStartY;
private float rotX, rotY, scale = 1;
public float x, y;
public float padding = 5;
public float width = 100, height = 100;
public float getX() {
return x;
}
public float getY() {
return y;
}
public float getWidth() {
return width;
}
public float getHeight() {
return height;
}
public void click() {
refresh();
}
@Override
public void appendNarrations(NarrationMessageBuilder msgBuilder) {
msgBuilder.put(NarrationPart.HINT, "Chunk preview");
}
@Override
public SelectionType getType() {
if (focused) return SelectionType.FOCUSED;
if (hovered || clicked || rotating) return SelectionType.HOVERED;
return SelectionType.NONE;
}
@Override
public boolean changeFocus(boolean lookForwards) {
focused = !focused;
return focused;
}
private void refresh() {
globalProgress = 0;
}
private static boolean checkZ(float z) {
return z < 3;
}
private static void myFill(MatrixStack matrices, float x1, float y1, float x2, float y2, float a, float r, float g, float b) {
if (x1 < x2) {
float tmp = x1;
x1 = x2;
x2 = tmp;
}
if (y1 < y2) {
float tmp = y1;
y1 = y2;
y2 = tmp;
}
Vector4f p1 = new Vector4f(x1, y1, 0, 1);
Vector4f p2 = new Vector4f(x1, y2, 0, 1);
Vector4f p3 = new Vector4f(x2, y2, 0, 1);
Vector4f p4 = new Vector4f(x2, y1, 0, 1);
p1.transform(matrices.peek().getPositionMatrix());
p2.transform(matrices.peek().getPositionMatrix());
p3.transform(matrices.peek().getPositionMatrix());
p4.transform(matrices.peek().getPositionMatrix());
p1.multiply(1 / p1.getW());
p2.multiply(1 / p2.getW());
p3.multiply(1 / p3.getW());
p4.multiply(1 / p4.getW());
if (checkZ(p1.getZ()) && checkZ(p2.getZ()) && checkZ(p3.getZ()) && checkZ(p4.getZ())) {
BufferBuilder bufferBuilder = Tessellator.getInstance().getBuffer();
RenderSystem.enableBlend();
RenderSystem.disableCull();
RenderSystem.disableTexture();
RenderSystem.defaultBlendFunc();
RenderSystem.setShader(GameRenderer::getPositionColorShader);
bufferBuilder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR);
bufferBuilder.vertex(p1.getX(), p1.getY(), p1.getZ()).color(r, g, b, a).next();
bufferBuilder.vertex(p2.getX(), p2.getY(), p2.getZ()).color(r, g, b, a).next();
bufferBuilder.vertex(p3.getX(), p3.getY(), p3.getZ()).color(r, g, b, a).next();
bufferBuilder.vertex(p4.getX(), p4.getY(), p4.getZ()).color(r, g, b, a).next();
BufferRenderer.drawWithShader(bufferBuilder.end());
RenderSystem.enableTexture();
RenderSystem.disableBlend();
}
}
private final Quaternion rotation = Quaternion.fromEulerXyzDegrees(new Vec3f(-90, 0, 0));
private void setupDepth(MatrixStack matrices) {
RenderSystem.enableDepthTest();
RenderSystem.disableBlend();
RenderSystem.clearDepth(-1);
RenderSystem.clear(GL11.GL_DEPTH_BUFFER_BIT, true);
RenderSystem.depthFunc(GL11.GL_ALWAYS);
RenderSystem.depthMask(true);
matrices.push();
matrices.scale(.5f, .5f, 1);
matrices.translate(0, 0, .1f);
if (hovered) {
myFill(matrices, -1, -1, 1, 1, 0.1f, 1, 1, 1);
}
else {
myFill(matrices, -1, -1, 1, 1, 0.004f, 0, 0, 0);
}
matrices.pop();
RenderSystem.depthMask(false);
RenderSystem.depthFunc(GL11.GL_LESS);
RenderSystem.enableBlend();
}
private void renderChunk(MatrixStack matrices, int x, int y, int n, float delta) {
matrices.push();
matrices.translate(x * 16 - 8, 0, y * 16 - 8);
// x += n;
// y += n;
float progress = globalProgress / duration - (float)Math.sqrt(x * x + y * y) / (float)n / 2;
if (progress < 0) progress = 0;
if (progress > 1) progress = 1;
if (progress < 0.999) {
float _progress = AnimatedChunks.getInstance().getEaseManager().getValue().ease(progress);
AnimatedChunks.getInstance().getAnimationManager().getValue().animate(
_progress, matrices,
x * 16, 0, y * 16, 0, 0, 0
);
// matrices.translate(0, 0, 16);
}
matrices.translate(0, 0, 16);
matrices.multiply(rotation);
myFill(matrices, 2, 1, 14, 2, progress, 1, 1, 1);
myFill(matrices, 2, 14, 14, 15, progress, 1, 1, 1);
myFill(matrices, 1, 1, 2, 15, progress, 1, 1, 1);
myFill(matrices, 14, 1, 15, 15, progress, 1, 1, 1);
matrices.pop();
}
private void renderChunks(MatrixStack matrices, float delta, int n) {
duration = AnimatedChunks.getInstance().getProgressManager().getDuration();
// globalProgress += (lastTime - (lastTime = System.nanoTime())) / -1000000000f;
globalProgress += delta * 0.05f;
matrices.push();
matrices.scale(width, width, 1);
matrices.translate(.5f, .5f, 0);
setupDepth(matrices);
matrices.multiplyPositionMatrix(Matrix4f.viewboxMatrix(75, 1, .00001f, 100));
matrices.translate(0, 0, -2);
matrices.scale(0.0625f, 0.0625f, 0.0625f);
matrices.scale(1f / (n * 2 + 1), 1f / (n * 2 + 1), 1f / (n * 2 + 1));
// matrices.multiply(Quaternion.fromEulerXyzDegrees(new Vec3f(150, -45, 0)));
matrices.scale(scale, scale, scale);
matrices.multiply(Quaternion.fromEulerXyzDegrees(new Vec3f(rotY + 150, 0, 0)));
matrices.multiply(Quaternion.fromEulerXyzDegrees(new Vec3f(0, rotX - 45, 0)));
// matrices.translate(-8, 0, 8);
for (int x = -n; x <= n; x++) {
for (int y = -n; y <= n; y++) {
renderChunk(matrices, x, y, n, delta);
}
}
RenderSystem.depthMask(true);
RenderSystem.disableDepthTest();
RenderSystem.clearDepth(1);
RenderSystem.clear(GL11.GL_DEPTH_BUFFER_BIT, true);
matrices.pop();
}
@Override
public void render(MatrixStack matrices, int x, int y, float delta) {
int white = Argb.getArgb(255, 255, 255, 255);
matrices.push();
matrices.translate(this.x, this.y, getZOffset());
hovered = isMouseOver(x, y);
renderChunks(matrices, delta, 5);
drawHorizontalLine(matrices, 0, (int)getWidth() - 1, (int)getHeight() - 1, white);
if (focused) {
drawHorizontalLine(matrices, 0, (int)getWidth() - 1, 0, white);
drawVerticalLine(matrices, 0, 0, (int)getHeight() - 1, white);
drawVerticalLine(matrices, (int)getWidth() - 1, 0, (int)getHeight() - 1, white);
}
matrices.pop();
}
@Override
public boolean isMouseOver(double x, double y) {
if (clicked) return true;
return x >= 0 && x < getWidth() && y >= 0 && y < getHeight();
}
@Override
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
if (keyCode == GLFW.GLFW_KEY_ENTER) {
click();
clicked = true;
hovered = true;
return true;
}
return false;
}
@Override
public boolean keyReleased(int keyCode, int scanCode, int modifiers) {
if (keyCode == GLFW.GLFW_KEY_ENTER) {
clicked = false;
return true;
}
return false;
}
@Override
public boolean mouseScrolled(double mouseX, double mouseY, double amount) {
if (isMouseOver(mouseX, mouseY)) {
scale /= Math.pow(2, -amount / 3);
return true;
}
return false;
}
@Override
public boolean mouseClicked(double mouseX, double mouseY, int button) {
if (isMouseOver(mouseX, mouseY)) {
if (button == 0) {
click();
clicked = true;
hovered = true;
return true;
}
else if (button == 2) {
rotating = true;
hovered = true;
mouseStartX = (float)mouseX;
mouseStartY = (float)mouseY;
return true;
}
}
return false;
}
@Override
public void mouseMoved(double mouseX, double mouseY) {
if (rotating) {
rotX += mouseStartX - (float)mouseX;
rotY += mouseStartY - (float)mouseY;
mouseStartX = (float)mouseX;
mouseStartY = (float)mouseY;
}
}
@Override
public boolean mouseReleased(double mouseX, double mouseY, int button) {
if (button == 0 && clicked) {
clicked = false;
return true;
}
if (button == 2 && rotating) {
rotating = false;
return true;
}
return false;
}
public ChunkPreview(int x, int y) {
this.client = MinecraftClient.getInstance();
this.x = x;
this.y = y;
}
public ChunkPreview(int x, int y, int w, int h) {
this.client = MinecraftClient.getInstance();
this.x = x;
this.y = y;
this.width = w;
this.height = h;
}
}