Create/src/main/java/com/simibubi/create/foundation/utility/outliner/Outline.java
2023-05-08 20:26:16 -07:00

593 lines
15 KiB
Java

package com.simibubi.create.foundation.utility.outliner;
import java.util.Optional;
import javax.annotation.Nullable;
import com.jozufozu.flywheel.util.transform.TransformStack;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.math.Matrix3f;
import com.mojang.math.Matrix4f;
import com.mojang.math.Vector3f;
import com.mojang.math.Vector4f;
import com.simibubi.create.AllSpecialTextures;
import com.simibubi.create.foundation.render.SuperRenderTypeBuffer;
import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.Color;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.core.Direction;
import net.minecraft.util.Mth;
public abstract class Outline {
protected final OutlineParams params;
protected final Vector4f colorTemp = new Vector4f();
protected final Vector3f diffPosTemp = new Vector3f();
protected final Vector3f minPosTemp = new Vector3f();
protected final Vector3f maxPosTemp = new Vector3f();
protected final Vector4f posTransformTemp = new Vector4f();
protected final Vector3f normalTransformTemp = new Vector3f();
public Outline() {
params = new OutlineParams();
}
public OutlineParams getParams() {
return params;
}
public abstract void render(PoseStack ms, SuperRenderTypeBuffer buffer, float pt);
public void tick() {}
public void bufferCuboidLine(PoseStack poseStack, VertexConsumer consumer, Vector3f start, Vector3f end, float width, Vector4f color, int lightmap, boolean disableNormals) {
Vector3f diff = this.diffPosTemp;
diff.load(end);
diff.sub(start);
float length = Mth.sqrt(diff.x() * diff.x() + diff.y() * diff.y() + diff.z() * diff.z());
float hAngle = AngleHelper.deg(Mth.atan2(diff.x(), diff.z()));
float hDistance = Mth.sqrt(diff.x() * diff.x() + diff.z() * diff.z());
float vAngle = AngleHelper.deg(Mth.atan2(hDistance, diff.y())) - 90;
poseStack.pushPose();
TransformStack.cast(poseStack)
.rotateY(hAngle)
.rotateX(vAngle);
bufferCuboidLine(poseStack.last(), consumer, start, Direction.NORTH, length, width, color, lightmap, disableNormals);
poseStack.popPose();
}
public void bufferCuboidLine(PoseStack.Pose pose, VertexConsumer consumer, Vector3f origin, Direction direction, float length, float width, Vector4f color, int lightmap, boolean disableNormals) {
Vector3f minPos = minPosTemp;
Vector3f maxPos = maxPosTemp;
float halfWidth = width / 2;
minPos.set(origin.x() - halfWidth, origin.y() - halfWidth, origin.z() - halfWidth);
maxPos.set(origin.x() + halfWidth, origin.y() + halfWidth, origin.z() + halfWidth);
switch (direction) {
case DOWN -> {
minPos.add(0, -length, 0);
}
case UP -> {
maxPos.add(0, length, 0);
}
case NORTH -> {
minPos.add(0, 0, -length);
}
case SOUTH -> {
maxPos.add(0, 0, length);
}
case WEST -> {
minPos.add(-length, 0, 0);
}
case EAST -> {
maxPos.add(length, 0, 0);
}
}
bufferCuboid(pose, consumer, minPos, maxPos, color, lightmap, disableNormals);
}
public void bufferCuboid(PoseStack.Pose pose, VertexConsumer consumer, Vector3f minPos, Vector3f maxPos, Vector4f color, int lightmap, boolean disableNormals) {
Vector4f posTransformTemp = this.posTransformTemp;
Vector3f normalTransformTemp = this.normalTransformTemp;
float minX = minPos.x();
float minY = minPos.y();
float minZ = minPos.z();
float maxX = maxPos.x();
float maxY = maxPos.y();
float maxZ = maxPos.z();
Matrix4f posMatrix = pose.pose();
posTransformTemp.set(minX, minY, maxZ, 1);
posTransformTemp.transform(posMatrix);
double x0 = posTransformTemp.x();
double y0 = posTransformTemp.y();
double z0 = posTransformTemp.z();
posTransformTemp.set(minX, minY, minZ, 1);
posTransformTemp.transform(posMatrix);
double x1 = posTransformTemp.x();
double y1 = posTransformTemp.y();
double z1 = posTransformTemp.z();
posTransformTemp.set(maxX, minY, minZ, 1);
posTransformTemp.transform(posMatrix);
double x2 = posTransformTemp.x();
double y2 = posTransformTemp.y();
double z2 = posTransformTemp.z();
posTransformTemp.set(maxX, minY, maxZ, 1);
posTransformTemp.transform(posMatrix);
double x3 = posTransformTemp.x();
double y3 = posTransformTemp.y();
double z3 = posTransformTemp.z();
posTransformTemp.set(minX, maxY, minZ, 1);
posTransformTemp.transform(posMatrix);
double x4 = posTransformTemp.x();
double y4 = posTransformTemp.y();
double z4 = posTransformTemp.z();
posTransformTemp.set(minX, maxY, maxZ, 1);
posTransformTemp.transform(posMatrix);
double x5 = posTransformTemp.x();
double y5 = posTransformTemp.y();
double z5 = posTransformTemp.z();
posTransformTemp.set(maxX, maxY, maxZ, 1);
posTransformTemp.transform(posMatrix);
double x6 = posTransformTemp.x();
double y6 = posTransformTemp.y();
double z6 = posTransformTemp.z();
posTransformTemp.set(maxX, maxY, minZ, 1);
posTransformTemp.transform(posMatrix);
double x7 = posTransformTemp.x();
double y7 = posTransformTemp.y();
double z7 = posTransformTemp.z();
float r = color.x();
float g = color.y();
float b = color.z();
float a = color.w();
Matrix3f normalMatrix = pose.normal();
// down
if (disableNormals) {
normalTransformTemp.set(0, 1, 0);
} else {
normalTransformTemp.set(0, -1, 0);
}
normalTransformTemp.transform(normalMatrix);
float nx0 = normalTransformTemp.x();
float ny0 = normalTransformTemp.y();
float nz0 = normalTransformTemp.z();
consumer.vertex(x0, y0, z0)
.color(r, g, b, a)
.uv(0, 0)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx0, ny0, nz0)
.endVertex();
consumer.vertex(x1, y1, z1)
.color(r, g, b, a)
.uv(0, 1)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx0, ny0, nz0)
.endVertex();
consumer.vertex(x2, y2, z2)
.color(r, g, b, a)
.uv(1, 1)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx0, ny0, nz0)
.endVertex();
consumer.vertex(x3, y3, z3)
.color(r, g, b, a)
.uv(1, 0)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx0, ny0, nz0)
.endVertex();
// up
normalTransformTemp.set(0, 1, 0);
normalTransformTemp.transform(normalMatrix);
float nx1 = normalTransformTemp.x();
float ny1 = normalTransformTemp.y();
float nz1 = normalTransformTemp.z();
consumer.vertex(x4, y4, z4)
.color(r, g, b, a)
.uv(0, 0)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx1, ny1, nz1)
.endVertex();
consumer.vertex(x5, y5, z5)
.color(r, g, b, a)
.uv(0, 1)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx1, ny1, nz1)
.endVertex();
consumer.vertex(x6, y6, z6)
.color(r, g, b, a)
.uv(1, 1)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx1, ny1, nz1)
.endVertex();
consumer.vertex(x7, y7, z7)
.color(r, g, b, a)
.uv(1, 0)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx1, ny1, nz1)
.endVertex();
// north
if (disableNormals) {
normalTransformTemp.set(0, 1, 0);
} else {
normalTransformTemp.set(0, 0, -1);
}
normalTransformTemp.transform(normalMatrix);
float nx2 = normalTransformTemp.x();
float ny2 = normalTransformTemp.y();
float nz2 = normalTransformTemp.z();
consumer.vertex(x7, y7, z7)
.color(r, g, b, a)
.uv(0, 0)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx2, ny2, nz2)
.endVertex();
consumer.vertex(x2, y2, z2)
.color(r, g, b, a)
.uv(0, 1)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx2, ny2, nz2)
.endVertex();
consumer.vertex(x1, y1, z1)
.color(r, g, b, a)
.uv(1, 1)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx2, ny2, nz2)
.endVertex();
consumer.vertex(x4, y4, z4)
.color(r, g, b, a)
.uv(1, 0)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx2, ny2, nz2)
.endVertex();
// south
if (disableNormals) {
normalTransformTemp.set(0, 1, 0);
} else {
normalTransformTemp.set(0, 0, 1);
}
normalTransformTemp.transform(normalMatrix);
float nx3 = normalTransformTemp.x();
float ny3 = normalTransformTemp.y();
float nz3 = normalTransformTemp.z();
consumer.vertex(x5, y5, z5)
.color(r, g, b, a)
.uv(0, 0)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx3, ny3, nz3)
.endVertex();
consumer.vertex(x0, y0, z0)
.color(r, g, b, a)
.uv(0, 1)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx3, ny3, nz3)
.endVertex();
consumer.vertex(x3, y3, z3)
.color(r, g, b, a)
.uv(1, 1)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx3, ny3, nz3)
.endVertex();
consumer.vertex(x6, y6, z6)
.color(r, g, b, a)
.uv(1, 0)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx3, ny3, nz3)
.endVertex();
// west
if (disableNormals) {
normalTransformTemp.set(0, 1, 0);
} else {
normalTransformTemp.set(-1, 0, 0);
}
normalTransformTemp.transform(normalMatrix);
float nx4 = normalTransformTemp.x();
float ny4 = normalTransformTemp.y();
float nz4 = normalTransformTemp.z();
consumer.vertex(x4, y4, z4)
.color(r, g, b, a)
.uv(0, 0)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx4, ny4, nz4)
.endVertex();
consumer.vertex(x1, y1, z1)
.color(r, g, b, a)
.uv(0, 1)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx4, ny4, nz4)
.endVertex();
consumer.vertex(x0, y0, z0)
.color(r, g, b, a)
.uv(1, 1)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx4, ny4, nz4)
.endVertex();
consumer.vertex(x5, y5, z5)
.color(r, g, b, a)
.uv(1, 0)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx4, ny4, nz4)
.endVertex();
// east
if (disableNormals) {
normalTransformTemp.set(0, 1, 0);
} else {
normalTransformTemp.set(1, 0, 0);
}
normalTransformTemp.transform(normalMatrix);
float nx5 = normalTransformTemp.x();
float ny5 = normalTransformTemp.y();
float nz5 = normalTransformTemp.z();
consumer.vertex(x6, y6, z6)
.color(r, g, b, a)
.uv(0, 0)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx5, ny5, nz5)
.endVertex();
consumer.vertex(x3, y3, z3)
.color(r, g, b, a)
.uv(0, 1)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx5, ny5, nz5)
.endVertex();
consumer.vertex(x2, y2, z2)
.color(r, g, b, a)
.uv(1, 1)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx5, ny5, nz5)
.endVertex();
consumer.vertex(x7, y7, z7)
.color(r, g, b, a)
.uv(1, 0)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx5, ny5, nz5)
.endVertex();
}
public void bufferQuad(PoseStack.Pose pose, VertexConsumer consumer, Vector3f pos0, Vector3f pos1, Vector3f pos2, Vector3f pos3, Vector4f color, int lightmap, Vector3f normal) {
bufferQuad(pose, consumer, pos0, pos1, pos2, pos3, color, 0, 0, 1, 1, lightmap, normal);
}
public void bufferQuad(PoseStack.Pose pose, VertexConsumer consumer, Vector3f pos0, Vector3f pos1, Vector3f pos2, Vector3f pos3, Vector4f color, float minU, float minV, float maxU, float maxV, int lightmap, Vector3f normal) {
Vector4f posTransformTemp = this.posTransformTemp;
Vector3f normalTransformTemp = this.normalTransformTemp;
Matrix4f posMatrix = pose.pose();
posTransformTemp.set(pos0.x(), pos0.y(), pos0.z(), 1);
posTransformTemp.transform(posMatrix);
double x0 = posTransformTemp.x();
double y0 = posTransformTemp.y();
double z0 = posTransformTemp.z();
posTransformTemp.set(pos1.x(), pos1.y(), pos1.z(), 1);
posTransformTemp.transform(posMatrix);
double x1 = posTransformTemp.x();
double y1 = posTransformTemp.y();
double z1 = posTransformTemp.z();
posTransformTemp.set(pos2.x(), pos2.y(), pos2.z(), 1);
posTransformTemp.transform(posMatrix);
double x2 = posTransformTemp.x();
double y2 = posTransformTemp.y();
double z2 = posTransformTemp.z();
posTransformTemp.set(pos3.x(), pos3.y(), pos3.z(), 1);
posTransformTemp.transform(posMatrix);
double x3 = posTransformTemp.x();
double y3 = posTransformTemp.y();
double z3 = posTransformTemp.z();
float r = color.x();
float g = color.y();
float b = color.z();
float a = color.w();
normalTransformTemp.load(normal);
normalTransformTemp.transform(pose.normal());
float nx = normalTransformTemp.x();
float ny = normalTransformTemp.y();
float nz = normalTransformTemp.z();
consumer.vertex(x0, y0, z0)
.color(r, g, b, a)
.uv(minU, minV)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx, ny, nz)
.endVertex();
consumer.vertex(x1, y1, z1)
.color(r, g, b, a)
.uv(minU, maxV)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx, ny, nz)
.endVertex();
consumer.vertex(x2, y2, z2)
.color(r, g, b, a)
.uv(maxU, maxV)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx, ny, nz)
.endVertex();
consumer.vertex(x3, y3, z3)
.color(r, g, b, a)
.uv(maxU, minV)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx, ny, nz)
.endVertex();
}
public static class OutlineParams {
protected Optional<AllSpecialTextures> faceTexture;
protected Optional<AllSpecialTextures> hightlightedFaceTexture;
protected Direction highlightedFace;
protected boolean fadeLineWidth;
protected boolean disableCull;
protected boolean disableLineNormals;
protected float alpha;
protected int lightmap;
protected Color rgb;
private float lineWidth;
public OutlineParams() {
faceTexture = hightlightedFaceTexture = Optional.empty();
alpha = 1;
lineWidth = 1 / 32f;
fadeLineWidth = true;
rgb = Color.WHITE;
lightmap = LightTexture.FULL_BRIGHT;
}
// builder
public OutlineParams colored(int color) {
rgb = new Color(color, false);
return this;
}
public OutlineParams colored(Color c) {
rgb = c.copy();
return this;
}
public OutlineParams lightmap(int light) {
lightmap = light;
return this;
}
public OutlineParams lineWidth(float width) {
this.lineWidth = width;
return this;
}
public OutlineParams withFaceTexture(AllSpecialTextures texture) {
this.faceTexture = Optional.ofNullable(texture);
return this;
}
public OutlineParams clearTextures() {
return this.withFaceTextures(null, null);
}
public OutlineParams withFaceTextures(AllSpecialTextures texture, AllSpecialTextures highlightTexture) {
this.faceTexture = Optional.ofNullable(texture);
this.hightlightedFaceTexture = Optional.ofNullable(highlightTexture);
return this;
}
public OutlineParams highlightFace(@Nullable Direction face) {
highlightedFace = face;
return this;
}
public OutlineParams disableLineNormals() {
disableLineNormals = true;
return this;
}
public OutlineParams disableCull() {
disableCull = true;
return this;
}
// getter
public float getLineWidth() {
return fadeLineWidth ? alpha * lineWidth : lineWidth;
}
public Direction getHighlightedFace() {
return highlightedFace;
}
public void loadColor(Vector4f vec) {
vec.set(rgb.getRedAsFloat(), rgb.getGreenAsFloat(), rgb.getBlueAsFloat(), rgb.getAlphaAsFloat() * alpha);
}
}
}