diff --git a/src/main/java/nl/requios/effortlessbuilding/create/CreateClient.java b/src/main/java/nl/requios/effortlessbuilding/create/CreateClient.java index a983c25..eb8f15a 100644 --- a/src/main/java/nl/requios/effortlessbuilding/create/CreateClient.java +++ b/src/main/java/nl/requios/effortlessbuilding/create/CreateClient.java @@ -2,7 +2,7 @@ package nl.requios.effortlessbuilding.create; import nl.requios.effortlessbuilding.create.foundation.render.SuperByteBufferCache; import nl.requios.effortlessbuilding.create.foundation.utility.ghost.GhostBlocks; -import nl.requios.effortlessbuilding.create.foundation.utility.outliner.Outliner; +import nl.requios.effortlessbuilding.create.foundation.outliner.Outliner; public class CreateClient { public static final SuperByteBufferCache BUFFER_CACHE = new SuperByteBufferCache(); diff --git a/src/main/java/nl/requios/effortlessbuilding/create/foundation/outliner/AABBOutline.java b/src/main/java/nl/requios/effortlessbuilding/create/foundation/outliner/AABBOutline.java new file mode 100644 index 0000000..2cb28f2 --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/create/foundation/outliner/AABBOutline.java @@ -0,0 +1,230 @@ +package nl.requios.effortlessbuilding.create.foundation.outliner; + +import java.util.Optional; + +import org.joml.Vector3f; +import org.joml.Vector4f; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import nl.requios.effortlessbuilding.create.AllSpecialTextures; +import nl.requios.effortlessbuilding.create.foundation.render.RenderTypes; +import nl.requios.effortlessbuilding.create.foundation.render.SuperRenderTypeBuffer; + +import net.minecraft.client.renderer.RenderType; +import net.minecraft.core.Direction; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; + +public class AABBOutline extends Outline { + + protected AABB bb; + + protected final Vector3f minPosTemp1 = new Vector3f(); + protected final Vector3f maxPosTemp1 = new Vector3f(); + + protected final Vector4f colorTemp1 = new Vector4f(); + protected final Vector3f pos0Temp = new Vector3f(); + protected final Vector3f pos1Temp = new Vector3f(); + protected final Vector3f pos2Temp = new Vector3f(); + protected final Vector3f pos3Temp = new Vector3f(); + protected final Vector3f normalTemp = new Vector3f(); + protected final Vector3f originTemp = new Vector3f(); + + public AABBOutline(AABB bb) { + setBounds(bb); + } + + public AABB getBounds() { + return bb; + } + + public void setBounds(AABB bb) { + this.bb = bb; + } + + @Override + public void render(PoseStack ms, SuperRenderTypeBuffer buffer, Vec3 camera, float pt) { + params.loadColor(colorTemp); + Vector4f color = colorTemp; + int lightmap = params.lightmap; + boolean disableLineNormals = params.disableLineNormals; + renderBox(ms, buffer, camera, bb, color, lightmap, disableLineNormals); + } + + protected void renderBox(PoseStack ms, SuperRenderTypeBuffer buffer, Vec3 camera, AABB box, Vector4f color, int lightmap, boolean disableLineNormals) { + Vector3f minPos = minPosTemp1; + Vector3f maxPos = maxPosTemp1; + + boolean cameraInside = box.contains(camera); + boolean cull = !cameraInside && !params.disableCull; + float inflate = cameraInside ? -1 / 128f : 1 / 128f; + + box = box.move(camera.scale(-1)); + minPos.set((float) box.minX - inflate, (float) box.minY - inflate, (float) box.minZ - inflate); + maxPos.set((float) box.maxX + inflate, (float) box.maxY + inflate, (float) box.maxZ + inflate); + + renderBoxFaces(ms, buffer, cull, params.getHighlightedFace(), minPos, maxPos, color, lightmap); + + float lineWidth = params.getLineWidth(); + if (lineWidth == 0) + return; + + VertexConsumer consumer = buffer.getBuffer(RenderTypes.getOutlineSolid()); + renderBoxEdges(ms, consumer, minPos, maxPos, lineWidth, color, lightmap, disableLineNormals); + } + + protected void renderBoxFaces(PoseStack ms, SuperRenderTypeBuffer buffer, boolean cull, Direction highlightedFace, Vector3f minPos, Vector3f maxPos, Vector4f color, int lightmap) { + PoseStack.Pose pose = ms.last(); + renderBoxFace(pose, buffer, cull, highlightedFace, minPos, maxPos, Direction.DOWN, color, lightmap); + renderBoxFace(pose, buffer, cull, highlightedFace, minPos, maxPos, Direction.UP, color, lightmap); + renderBoxFace(pose, buffer, cull, highlightedFace, minPos, maxPos, Direction.NORTH, color, lightmap); + renderBoxFace(pose, buffer, cull, highlightedFace, minPos, maxPos, Direction.SOUTH, color, lightmap); + renderBoxFace(pose, buffer, cull, highlightedFace, minPos, maxPos, Direction.WEST, color, lightmap); + renderBoxFace(pose, buffer, cull, highlightedFace, minPos, maxPos, Direction.EAST, color, lightmap); + } + + protected void renderBoxFace(PoseStack.Pose pose, SuperRenderTypeBuffer buffer, boolean cull, Direction highlightedFace, Vector3f minPos, Vector3f maxPos, Direction face, Vector4f color, int lightmap) { + boolean highlighted = face == highlightedFace; + + // TODO: Presumably, the other texture should be used, but this was not noticed before so fixing it may lead to suboptimal visuals. +// Optional optionalFaceTexture = highlighted ? params.hightlightedFaceTexture : params.faceTexture; + Optional optionalFaceTexture = params.faceTexture; + if (!optionalFaceTexture.isPresent()) + return; + AllSpecialTextures faceTexture = optionalFaceTexture.get(); + + RenderType renderType = RenderTypes.getOutlineTranslucent(faceTexture.getLocation(), cull); + VertexConsumer consumer = buffer.getLateBuffer(renderType); + + float alphaMult = highlighted ? 1 : 0.5f; + colorTemp1.set(color.x(), color.y(), color.z(), color.w() * alphaMult); + color = colorTemp1; + + renderBoxFace(pose, consumer, minPos, maxPos, face, color, lightmap); + } + + protected void renderBoxFace(PoseStack.Pose pose, VertexConsumer consumer, Vector3f minPos, Vector3f maxPos, Direction face, Vector4f color, int lightmap) { + Vector3f pos0 = pos0Temp; + Vector3f pos1 = pos1Temp; + Vector3f pos2 = pos2Temp; + Vector3f pos3 = pos3Temp; + Vector3f normal = normalTemp; + + float minX = minPos.x(); + float minY = minPos.y(); + float minZ = minPos.z(); + float maxX = maxPos.x(); + float maxY = maxPos.y(); + float maxZ = maxPos.z(); + + float maxU; + float maxV; + + switch (face) { + case DOWN -> { + // 0 1 2 3 + pos0.set(minX, minY, maxZ); + pos1.set(minX, minY, minZ); + pos2.set(maxX, minY, minZ); + pos3.set(maxX, minY, maxZ); + maxU = maxX - minX; + maxV = maxZ - minZ; + normal.set(0, -1, 0); + } + case UP -> { + // 4 5 6 7 + pos0.set(minX, maxY, minZ); + pos1.set(minX, maxY, maxZ); + pos2.set(maxX, maxY, maxZ); + pos3.set(maxX, maxY, minZ); + maxU = maxX - minX; + maxV = maxZ - minZ; + normal.set(0, 1, 0); + } + case NORTH -> { + // 7 2 1 4 + pos0.set(maxX, maxY, minZ); + pos1.set(maxX, minY, minZ); + pos2.set(minX, minY, minZ); + pos3.set(minX, maxY, minZ); + maxU = maxX - minX; + maxV = maxY - minY; + normal.set(0, 0, -1); + } + case SOUTH -> { + // 5 0 3 6 + pos0.set(minX, maxY, maxZ); + pos1.set(minX, minY, maxZ); + pos2.set(maxX, minY, maxZ); + pos3.set(maxX, maxY, maxZ); + maxU = maxX - minX; + maxV = maxY - minY; + normal.set(0, 0, 1); + } + case WEST -> { + // 4 1 0 5 + pos0.set(minX, maxY, minZ); + pos1.set(minX, minY, minZ); + pos2.set(minX, minY, maxZ); + pos3.set(minX, maxY, maxZ); + maxU = maxZ - minZ; + maxV = maxY - minY; + normal.set(-1, 0, 0); + } + case EAST -> { + // 6 3 2 7 + pos0.set(maxX, maxY, maxZ); + pos1.set(maxX, minY, maxZ); + pos2.set(maxX, minY, minZ); + pos3.set(maxX, maxY, minZ); + maxU = maxZ - minZ; + maxV = maxY - minY; + normal.set(1, 0, 0); + } + default -> { + maxU = 1; + maxV = 1; + } + } + + bufferQuad(pose, consumer, pos0, pos1, pos2, pos3, color, 0, 0, maxU, maxV, lightmap, normal); + } + + protected void renderBoxEdges(PoseStack ms, VertexConsumer consumer, Vector3f minPos, Vector3f maxPos, float lineWidth, Vector4f color, int lightmap, boolean disableNormals) { + Vector3f origin = originTemp; + + PoseStack.Pose pose = ms.last(); + + float lineLengthX = maxPos.x() - minPos.x(); + float lineLengthY = maxPos.y() - minPos.y(); + float lineLengthZ = maxPos.z() - minPos.z(); + + origin.set(minPos); + bufferCuboidLine(pose, consumer, origin, Direction.EAST, lineLengthX, lineWidth, color, lightmap, disableNormals); + bufferCuboidLine(pose, consumer, origin, Direction.UP, lineLengthY, lineWidth, color, lightmap, disableNormals); + bufferCuboidLine(pose, consumer, origin, Direction.SOUTH, lineLengthZ, lineWidth, color, lightmap, disableNormals); + + origin.set(maxPos.x(), minPos.y(), minPos.z()); + bufferCuboidLine(pose, consumer, origin, Direction.UP, lineLengthY, lineWidth, color, lightmap, disableNormals); + bufferCuboidLine(pose, consumer, origin, Direction.SOUTH, lineLengthZ, lineWidth, color, lightmap, disableNormals); + + origin.set(minPos.x(), maxPos.y(), minPos.z()); + bufferCuboidLine(pose, consumer, origin, Direction.EAST, lineLengthX, lineWidth, color, lightmap, disableNormals); + bufferCuboidLine(pose, consumer, origin, Direction.SOUTH, lineLengthZ, lineWidth, color, lightmap, disableNormals); + + origin.set(minPos.x(), minPos.y(), maxPos.z()); + bufferCuboidLine(pose, consumer, origin, Direction.EAST, lineLengthX, lineWidth, color, lightmap, disableNormals); + bufferCuboidLine(pose, consumer, origin, Direction.UP, lineLengthY, lineWidth, color, lightmap, disableNormals); + + origin.set(minPos.x(), maxPos.y(), maxPos.z()); + bufferCuboidLine(pose, consumer, origin, Direction.EAST, lineLengthX, lineWidth, color, lightmap, disableNormals); + + origin.set(maxPos.x(), minPos.y(), maxPos.z()); + bufferCuboidLine(pose, consumer, origin, Direction.UP, lineLengthY, lineWidth, color, lightmap, disableNormals); + + origin.set(maxPos.x(), maxPos.y(), minPos.z()); + bufferCuboidLine(pose, consumer, origin, Direction.SOUTH, lineLengthZ, lineWidth, color, lightmap, disableNormals); + } + +} diff --git a/src/main/java/nl/requios/effortlessbuilding/create/foundation/outliner/BlockClusterOutline.java b/src/main/java/nl/requios/effortlessbuilding/create/foundation/outliner/BlockClusterOutline.java new file mode 100644 index 0000000..1fa6bfc --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/create/foundation/outliner/BlockClusterOutline.java @@ -0,0 +1,272 @@ +package nl.requios.effortlessbuilding.create.foundation.outliner; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import org.joml.Vector3f; +import org.joml.Vector4f; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import nl.requios.effortlessbuilding.create.AllSpecialTextures; +import nl.requios.effortlessbuilding.create.foundation.render.RenderTypes; +import nl.requios.effortlessbuilding.create.foundation.render.SuperRenderTypeBuffer; +import nl.requios.effortlessbuilding.create.foundation.utility.Iterate; + +import net.minecraft.client.renderer.RenderType; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.Direction.AxisDirection; +import net.minecraft.world.phys.Vec3; + +public class BlockClusterOutline extends Outline { + + private final Cluster cluster; + + protected final Vector3f pos0Temp = new Vector3f(); + protected final Vector3f pos1Temp = new Vector3f(); + protected final Vector3f pos2Temp = new Vector3f(); + protected final Vector3f pos3Temp = new Vector3f(); + protected final Vector3f normalTemp = new Vector3f(); + protected final Vector3f originTemp = new Vector3f(); + + public BlockClusterOutline(Iterable positions) { + cluster = new Cluster(); + positions.forEach(cluster::include); + } + + @Override + public void render(PoseStack ms, SuperRenderTypeBuffer buffer, Vec3 camera, float pt) { + params.loadColor(colorTemp); + Vector4f color = colorTemp; + int lightmap = params.lightmap; + boolean disableLineNormals = params.disableLineNormals; + + renderFaces(ms, buffer, camera, pt, color, lightmap); + renderEdges(ms, buffer, camera, pt, color, lightmap, disableLineNormals); + } + + protected void renderFaces(PoseStack ms, SuperRenderTypeBuffer buffer, Vec3 camera, float pt, Vector4f color, int lightmap) { + Optional optionalFaceTexture = params.faceTexture; + if (!optionalFaceTexture.isPresent()) + return; + if (cluster.isEmpty()) + return; + + ms.pushPose(); + ms.translate(cluster.anchor.getX() - camera.x, cluster.anchor.getY() - camera.y, + cluster.anchor.getZ() - camera.z); + + AllSpecialTextures faceTexture = optionalFaceTexture.get(); + PoseStack.Pose pose = ms.last(); + RenderType renderType = RenderTypes.getOutlineTranslucent(faceTexture.getLocation(), true); + VertexConsumer consumer = buffer.getLateBuffer(renderType); + + cluster.visibleFaces.forEach((face, axisDirection) -> { + Direction direction = Direction.get(axisDirection, face.axis); + BlockPos pos = face.pos; + if (axisDirection == AxisDirection.POSITIVE) + pos = pos.relative(direction.getOpposite()); + bufferBlockFace(pose, consumer, pos, direction, color, lightmap); + }); + + ms.popPose(); + } + + protected void renderEdges(PoseStack ms, SuperRenderTypeBuffer buffer, Vec3 camera, float pt, Vector4f color, int lightmap, boolean disableNormals) { + float lineWidth = params.getLineWidth(); + if (lineWidth == 0) + return; + if (cluster.isEmpty()) + return; + + ms.pushPose(); + ms.translate(cluster.anchor.getX() - camera.x, cluster.anchor.getY() - camera.y, + cluster.anchor.getZ() - camera.z); + + PoseStack.Pose pose = ms.last(); + VertexConsumer consumer = buffer.getBuffer(RenderTypes.getOutlineSolid()); + + cluster.visibleEdges.forEach(edge -> { + BlockPos pos = edge.pos; + Vector3f origin = originTemp; + origin.set(pos.getX(), pos.getY(), pos.getZ()); + Direction direction = Direction.get(AxisDirection.POSITIVE, edge.axis); + bufferCuboidLine(pose, consumer, origin, direction, 1, lineWidth, color, lightmap, disableNormals); + }); + + ms.popPose(); + } + + public static void loadFaceData(Direction face, Vector3f pos0, Vector3f pos1, Vector3f pos2, Vector3f pos3, Vector3f normal) { + switch (face) { + case DOWN -> { + // 0 1 2 3 + pos0.set(0, 0, 1); + pos1.set(0, 0, 0); + pos2.set(1, 0, 0); + pos3.set(1, 0, 1); + normal.set(0, -1, 0); + } + case UP -> { + // 4 5 6 7 + pos0.set(0, 1, 0); + pos1.set(0, 1, 1); + pos2.set(1, 1, 1); + pos3.set(1, 1, 0); + normal.set(0, 1, 0); + } + case NORTH -> { + // 7 2 1 4 + pos0.set(1, 1, 0); + pos1.set(1, 0, 0); + pos2.set(0, 0, 0); + pos3.set(0, 1, 0); + normal.set(0, 0, -1); + } + case SOUTH -> { + // 5 0 3 6 + pos0.set(0, 1, 1); + pos1.set(0, 0, 1); + pos2.set(1, 0, 1); + pos3.set(1, 1, 1); + normal.set(0, 0, 1); + } + case WEST -> { + // 4 1 0 5 + pos0.set(0, 1, 0); + pos1.set(0, 0, 0); + pos2.set(0, 0, 1); + pos3.set(0, 1, 1); + normal.set(-1, 0, 0); + } + case EAST -> { + // 6 3 2 7 + pos0.set(1, 1, 1); + pos1.set(1, 0, 1); + pos2.set(1, 0, 0); + pos3.set(1, 1, 0); + normal.set(1, 0, 0); + } + } + } + + public static void addPos(float x, float y, float z, Vector3f pos0, Vector3f pos1, Vector3f pos2, Vector3f pos3) { + pos0.add(x, y, z); + pos1.add(x, y, z); + pos2.add(x, y, z); + pos3.add(x, y, z); + } + + protected void bufferBlockFace(PoseStack.Pose pose, VertexConsumer consumer, BlockPos pos, Direction face, Vector4f color, int lightmap) { + Vector3f pos0 = pos0Temp; + Vector3f pos1 = pos1Temp; + Vector3f pos2 = pos2Temp; + Vector3f pos3 = pos3Temp; + Vector3f normal = normalTemp; + + loadFaceData(face, pos0, pos1, pos2, pos3, normal); + addPos(pos.getX() + face.getStepX() * 1 / 128f, + pos.getY() + face.getStepY() * 1 / 128f, + pos.getZ() + face.getStepZ() * 1 / 128f, + pos0, pos1, pos2, pos3); + + bufferQuad(pose, consumer, pos0, pos1, pos2, pos3, color, lightmap, normal); + } + + private static class Cluster { + + private BlockPos anchor; + private Map visibleFaces; + private Set visibleEdges; + + public Cluster() { + visibleEdges = new HashSet<>(); + visibleFaces = new HashMap<>(); + } + + public boolean isEmpty() { + return anchor == null; + } + + public void include(BlockPos pos) { + if (anchor == null) + anchor = pos; + + pos = pos.subtract(anchor); + + // 6 FACES + for (Axis axis : Iterate.axes) { + Direction direction = Direction.get(AxisDirection.POSITIVE, axis); + for (int offset : Iterate.zeroAndOne) { + MergeEntry entry = new MergeEntry(axis, pos.relative(direction, offset)); + if (visibleFaces.remove(entry) == null) + visibleFaces.put(entry, offset == 0 ? AxisDirection.NEGATIVE : AxisDirection.POSITIVE); + } + } + + // 12 EDGES + for (Axis axis : Iterate.axes) { + for (Axis axis2 : Iterate.axes) { + if (axis == axis2) + continue; + for (Axis axis3 : Iterate.axes) { + if (axis == axis3) + continue; + if (axis2 == axis3) + continue; + + Direction direction = Direction.get(AxisDirection.POSITIVE, axis2); + Direction direction2 = Direction.get(AxisDirection.POSITIVE, axis3); + + for (int offset : Iterate.zeroAndOne) { + BlockPos entryPos = pos.relative(direction, offset); + for (int offset2 : Iterate.zeroAndOne) { + entryPos = entryPos.relative(direction2, offset2); + MergeEntry entry = new MergeEntry(axis, entryPos); + if (!visibleEdges.remove(entry)) + visibleEdges.add(entry); + } + } + } + + break; + } + } + + } + + } + + private static class MergeEntry { + + private Axis axis; + private BlockPos pos; + + public MergeEntry(Axis axis, BlockPos pos) { + this.axis = axis; + this.pos = pos; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (!(o instanceof MergeEntry)) + return false; + + MergeEntry other = (MergeEntry) o; + return this.axis == other.axis && this.pos.equals(other.pos); + } + + @Override + public int hashCode() { + return this.pos.hashCode() * 31 + axis.ordinal(); + } + } + +} diff --git a/src/main/java/nl/requios/effortlessbuilding/create/foundation/utility/outliner/ChasingAABBOutline.java b/src/main/java/nl/requios/effortlessbuilding/create/foundation/outliner/ChasingAABBOutline.java similarity index 51% rename from src/main/java/nl/requios/effortlessbuilding/create/foundation/utility/outliner/ChasingAABBOutline.java rename to src/main/java/nl/requios/effortlessbuilding/create/foundation/outliner/ChasingAABBOutline.java index d5639ea..50afb62 100644 --- a/src/main/java/nl/requios/effortlessbuilding/create/foundation/utility/outliner/ChasingAABBOutline.java +++ b/src/main/java/nl/requios/effortlessbuilding/create/foundation/outliner/ChasingAABBOutline.java @@ -1,9 +1,13 @@ -package nl.requios.effortlessbuilding.create.foundation.utility.outliner; +package nl.requios.effortlessbuilding.create.foundation.outliner; + +import org.joml.Vector4f; import com.mojang.blaze3d.vertex.PoseStack; import nl.requios.effortlessbuilding.create.foundation.render.SuperRenderTypeBuffer; + import net.minecraft.util.Mth; import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; public class ChasingAABBOutline extends AABBOutline { @@ -27,15 +31,18 @@ public class ChasingAABBOutline extends AABBOutline { } @Override - public void render(PoseStack ms, SuperRenderTypeBuffer buffer, float pt) { - renderBB(ms, buffer, interpolateBBs(prevBB, bb, pt)); + public void render(PoseStack ms, SuperRenderTypeBuffer buffer, Vec3 camera, float pt) { + params.loadColor(colorTemp); + Vector4f color = colorTemp; + int lightmap = params.lightmap; + boolean disableLineNormals = params.disableLineNormals; + renderBox(ms, buffer, camera, interpolateBBs(prevBB, bb, pt), color, lightmap, disableLineNormals); } private static AABB interpolateBBs(AABB current, AABB target, float pt) { - return new AABB(Mth.lerp(pt, current.minX, target.minX), - Mth.lerp(pt, current.minY, target.minY), Mth.lerp(pt, current.minZ, target.minZ), - Mth.lerp(pt, current.maxX, target.maxX), Mth.lerp(pt, current.maxY, target.maxY), - Mth.lerp(pt, current.maxZ, target.maxZ)); + return new AABB(Mth.lerp(pt, current.minX, target.minX), Mth.lerp(pt, current.minY, target.minY), + Mth.lerp(pt, current.minZ, target.minZ), Mth.lerp(pt, current.maxX, target.maxX), + Mth.lerp(pt, current.maxY, target.maxY), Mth.lerp(pt, current.maxZ, target.maxZ)); } } diff --git a/src/main/java/nl/requios/effortlessbuilding/create/foundation/outliner/ItemOutline.java b/src/main/java/nl/requios/effortlessbuilding/create/foundation/outliner/ItemOutline.java new file mode 100644 index 0000000..c03e308 --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/create/foundation/outliner/ItemOutline.java @@ -0,0 +1,39 @@ +package nl.requios.effortlessbuilding.create.foundation.outliner; + +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import nl.requios.effortlessbuilding.create.foundation.render.SuperRenderTypeBuffer; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.world.item.ItemDisplayContext; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.phys.Vec3; + +public class ItemOutline extends Outline { + + protected Vec3 pos; + protected ItemStack stack; + + public ItemOutline(Vec3 pos, ItemStack stack) { + this.pos = pos; + this.stack = stack; + } + + @Override + public void render(PoseStack ms, SuperRenderTypeBuffer buffer, Vec3 camera, float pt) { + Minecraft mc = Minecraft.getInstance(); + ms.pushPose(); + + TransformStack.cast(ms) + .translate(pos.x - camera.x, pos.y - camera.y, pos.z - camera.z) + .scale(params.alpha); + + mc.getItemRenderer().render(stack, ItemDisplayContext.FIXED, false, ms, + buffer, LightTexture.FULL_BRIGHT, OverlayTexture.NO_OVERLAY, + mc.getItemRenderer().getModel(stack, null, null, 0)); + + ms.popPose(); + } +} diff --git a/src/main/java/nl/requios/effortlessbuilding/create/foundation/outliner/LineOutline.java b/src/main/java/nl/requios/effortlessbuilding/create/foundation/outliner/LineOutline.java new file mode 100644 index 0000000..9c05710 --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/create/foundation/outliner/LineOutline.java @@ -0,0 +1,89 @@ +package nl.requios.effortlessbuilding.create.foundation.outliner; + +import org.joml.Vector3d; +import org.joml.Vector4f; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import nl.requios.effortlessbuilding.create.foundation.render.RenderTypes; +import nl.requios.effortlessbuilding.create.foundation.render.SuperRenderTypeBuffer; + +import net.minecraft.util.Mth; +import net.minecraft.world.phys.Vec3; + +public class LineOutline extends Outline { + + protected final Vector3d start = new Vector3d(0, 0, 0); + protected final Vector3d end = new Vector3d(0, 0, 0); + + public LineOutline set(Vector3d start, Vector3d end) { + this.start.set(start.x, start.y, start.z); + this.end.set(end.x, end.y, end.z); + return this; + } + + public LineOutline set(Vec3 start, Vec3 end) { + this.start.set(start.x, start.y, start.z); + this.end.set(end.x, end.y, end.z); + return this; + } + + @Override + public void render(PoseStack ms, SuperRenderTypeBuffer buffer, Vec3 camera, float pt) { + float width = params.getLineWidth(); + if (width == 0) + return; + + VertexConsumer consumer = buffer.getBuffer(RenderTypes.getOutlineSolid()); + params.loadColor(colorTemp); + Vector4f color = colorTemp; + int lightmap = params.lightmap; + boolean disableLineNormals = params.disableLineNormals; + renderInner(ms, consumer, camera, pt, width, color, lightmap, disableLineNormals); + } + + protected void renderInner(PoseStack ms, VertexConsumer consumer, Vec3 camera, float pt, float width, + Vector4f color, int lightmap, boolean disableNormals) { + bufferCuboidLine(ms, consumer, camera, start, end, width, color, lightmap, disableNormals); + } + + public static class EndChasingLineOutline extends LineOutline { + private float progress = 0; + private float prevProgress = 0; + private boolean lockStart; + + private final Vector3d startTemp = new Vector3d(0, 0, 0); + + public EndChasingLineOutline(boolean lockStart) { + this.lockStart = lockStart; + } + + public EndChasingLineOutline setProgress(float progress) { + prevProgress = this.progress; + this.progress = progress; + return this; + } + + @Override + protected void renderInner(PoseStack ms, VertexConsumer consumer, Vec3 camera, float pt, float width, + Vector4f color, int lightmap, boolean disableNormals) { + float distanceToTarget = Mth.lerp(pt, prevProgress, progress); + + Vector3d end; + if (lockStart) { + end = this.start; + } else { + end = this.end; + distanceToTarget = 1 - distanceToTarget; + } + + Vector3d start = this.startTemp; + double x = (this.start.x - end.x) * distanceToTarget + end.x; + double y = (this.start.y - end.y) * distanceToTarget + end.y; + double z = (this.start.z - end.z) * distanceToTarget + end.z; + start.set((float) x, (float) y, (float) z); + bufferCuboidLine(ms, consumer, camera, start, end, width, color, lightmap, disableNormals); + } + } + +} diff --git a/src/main/java/nl/requios/effortlessbuilding/create/foundation/outliner/Outline.java b/src/main/java/nl/requios/effortlessbuilding/create/foundation/outliner/Outline.java new file mode 100644 index 0000000..81b157d --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/create/foundation/outliner/Outline.java @@ -0,0 +1,601 @@ +package nl.requios.effortlessbuilding.create.foundation.outliner; + +import java.util.Optional; + +import javax.annotation.Nullable; + +import org.joml.Matrix3f; +import org.joml.Matrix4f; +import org.joml.Vector3d; +import org.joml.Vector3f; +import org.joml.Vector4f; + +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import nl.requios.effortlessbuilding.create.AllSpecialTextures; +import nl.requios.effortlessbuilding.create.foundation.render.SuperRenderTypeBuffer; +import nl.requios.effortlessbuilding.create.foundation.utility.AngleHelper; +import nl.requios.effortlessbuilding.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; +import net.minecraft.world.phys.Vec3; + +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, Vec3 camera, float pt); + + public void tick() {} + + public void bufferCuboidLine(PoseStack poseStack, VertexConsumer consumer, Vec3 camera, Vector3d start, Vector3d end, + float width, Vector4f color, int lightmap, boolean disableNormals) { + Vector3f diff = this.diffPosTemp; + diff.set((float) (end.x - start.x), (float) (end.y - start.y), (float) (end.z - start.z)); + + 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) + .translate(start.x - camera.x, start.y - camera.y, start.z - camera.z) + .rotateY(hAngle) + .rotateX(vAngle); + bufferCuboidLine(poseStack.last(), consumer, new Vector3f(), Direction.SOUTH, 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.mul(posMatrix); + double x0 = posTransformTemp.x(); + double y0 = posTransformTemp.y(); + double z0 = posTransformTemp.z(); + + posTransformTemp.set(minX, minY, minZ, 1); + posTransformTemp.mul(posMatrix); + double x1 = posTransformTemp.x(); + double y1 = posTransformTemp.y(); + double z1 = posTransformTemp.z(); + + posTransformTemp.set(maxX, minY, minZ, 1); + posTransformTemp.mul(posMatrix); + double x2 = posTransformTemp.x(); + double y2 = posTransformTemp.y(); + double z2 = posTransformTemp.z(); + + posTransformTemp.set(maxX, minY, maxZ, 1); + posTransformTemp.mul(posMatrix); + double x3 = posTransformTemp.x(); + double y3 = posTransformTemp.y(); + double z3 = posTransformTemp.z(); + + posTransformTemp.set(minX, maxY, minZ, 1); + posTransformTemp.mul(posMatrix); + double x4 = posTransformTemp.x(); + double y4 = posTransformTemp.y(); + double z4 = posTransformTemp.z(); + + posTransformTemp.set(minX, maxY, maxZ, 1); + posTransformTemp.mul(posMatrix); + double x5 = posTransformTemp.x(); + double y5 = posTransformTemp.y(); + double z5 = posTransformTemp.z(); + + posTransformTemp.set(maxX, maxY, maxZ, 1); + posTransformTemp.mul(posMatrix); + double x6 = posTransformTemp.x(); + double y6 = posTransformTemp.y(); + double z6 = posTransformTemp.z(); + + posTransformTemp.set(maxX, maxY, minZ, 1); + posTransformTemp.mul(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.mul(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.mul(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.mul(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.mul(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.mul(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.mul(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.mul(posMatrix); + double x0 = posTransformTemp.x(); + double y0 = posTransformTemp.y(); + double z0 = posTransformTemp.z(); + + posTransformTemp.set(pos1.x(), pos1.y(), pos1.z(), 1); + posTransformTemp.mul(posMatrix); + double x1 = posTransformTemp.x(); + double y1 = posTransformTemp.y(); + double z1 = posTransformTemp.z(); + + posTransformTemp.set(pos2.x(), pos2.y(), pos2.z(), 1); + posTransformTemp.mul(posMatrix); + double x2 = posTransformTemp.x(); + double y2 = posTransformTemp.y(); + double z2 = posTransformTemp.z(); + + posTransformTemp.set(pos3.x(), pos3.y(), pos3.z(), 1); + posTransformTemp.mul(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.set(normal); + normalTransformTemp.mul(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 faceTexture; + protected Optional 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); + } + } + +} diff --git a/src/main/java/nl/requios/effortlessbuilding/create/foundation/utility/outliner/Outliner.java b/src/main/java/nl/requios/effortlessbuilding/create/foundation/outliner/Outliner.java similarity index 74% rename from src/main/java/nl/requios/effortlessbuilding/create/foundation/utility/outliner/Outliner.java rename to src/main/java/nl/requios/effortlessbuilding/create/foundation/outliner/Outliner.java index 5588623..34106de 100644 --- a/src/main/java/nl/requios/effortlessbuilding/create/foundation/utility/outliner/Outliner.java +++ b/src/main/java/nl/requios/effortlessbuilding/create/foundation/outliner/Outliner.java @@ -1,16 +1,23 @@ -package nl.requios.effortlessbuilding.create.foundation.utility.outliner; +package nl.requios.effortlessbuilding.create.foundation.outliner; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Optional; import com.mojang.blaze3d.vertex.PoseStack; +//import nl.requios.effortlessbuilding.create.foundation.blockEntity.behaviour.ValueBox; +import nl.requios.effortlessbuilding.create.foundation.outliner.LineOutline.EndChasingLineOutline; +import nl.requios.effortlessbuilding.create.foundation.outliner.Outline.OutlineParams; import nl.requios.effortlessbuilding.create.foundation.render.SuperRenderTypeBuffer; -import nl.requios.effortlessbuilding.create.foundation.utility.outliner.LineOutline.EndChasingLineOutline; -import nl.requios.effortlessbuilding.create.foundation.utility.outliner.Outline.OutlineParams; + import net.minecraft.core.BlockPos; import net.minecraft.util.Mth; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; -import java.util.*; - public class Outliner { private final Map outlines = Collections.synchronizedMap(new HashMap<>()); @@ -18,10 +25,15 @@ public class Outliner { // Facade +// public OutlineParams showValueBox(Object slot, ValueBox box) { +// outlines.put(slot, new OutlineEntry(box)); +// return box.getParams(); +// } + public OutlineParams showLine(Object slot, Vec3 start, Vec3 end) { if (!outlines.containsKey(slot)) { LineOutline outline = new LineOutline(); - outlines.put(slot, new OutlineEntry(outline)); + addOutline(slot, outline); } OutlineEntry entry = outlines.get(slot); entry.ticksTillRemoval = 1; @@ -32,7 +44,7 @@ public class Outliner { public OutlineParams endChasingLine(Object slot, Vec3 start, Vec3 end, float chasingProgress, boolean lockStart) { if (!outlines.containsKey(slot)) { EndChasingLineOutline outline = new EndChasingLineOutline(lockStart); - outlines.put(slot, new OutlineEntry(outline)); + addOutline(slot, outline); } OutlineEntry entry = outlines.get(slot); entry.ticksTillRemoval = 1; @@ -64,10 +76,17 @@ public class Outliner { public OutlineParams showCluster(Object slot, Iterable selection) { BlockClusterOutline outline = new BlockClusterOutline(selection); + addOutline(slot, outline); + return outline.getParams(); + } + + // + + public OutlineParams showItem(Object slot, Vec3 pos, ItemStack stack) { + ItemOutline outline = new ItemOutline(pos, stack); OutlineEntry entry = new OutlineEntry(outline); outlines.put(slot, entry); - return entry.getOutline() - .getParams(); + return entry.getOutline().getParams(); } public void keep(Object slot) { @@ -75,8 +94,7 @@ public class Outliner { outlines.get(slot).ticksTillRemoval = 1; } - //ADDED - public void keep(Object slot, int ticks) { + public void keep(Object slot, int ticks){ if (outlines.containsKey(slot)) outlines.get(slot).ticksTillRemoval = ticks; } @@ -100,17 +118,19 @@ public class Outliner { // Utility + private void addOutline(Object slot, Outline outline) { + outlines.put(slot, new OutlineEntry(outline)); + } + private void createAABBOutlineIfMissing(Object slot, AABB bb) { if (!outlines.containsKey(slot) || !(outlines.get(slot).outline instanceof AABBOutline)) { ChasingAABBOutline outline = new ChasingAABBOutline(bb); - outlines.put(slot, new OutlineEntry(outline)); + addOutline(slot, outline); } } private ChasingAABBOutline getAndRefreshAABB(Object slot) { - OutlineEntry entry = outlines.get(slot); - entry.ticksTillRemoval = 1; - return (ChasingAABBOutline) entry.getOutline(); + return getAndRefreshAABB(slot, 1); } private ChasingAABBOutline getAndRefreshAABB(Object slot, int ttl) { @@ -132,14 +152,14 @@ public class Outliner { } } - public void renderOutlines(PoseStack ms, SuperRenderTypeBuffer buffer, float pt) { + public void renderOutlines(PoseStack ms, SuperRenderTypeBuffer buffer, Vec3 camera, float pt) { outlines.forEach((key, entry) -> { Outline outline = entry.getOutline(); OutlineParams params = outline.getParams(); params.alpha = 1; if (entry.isFading()) { int prevTicks = entry.ticksTillRemoval + 1; - float fadeticks = OutlineEntry.fadeTicks; + float fadeticks = OutlineEntry.FADE_TICKS; float lastAlpha = prevTicks >= 0 ? 1 : 1 + (prevTicks / fadeticks); float currentAlpha = 1 + (entry.ticksTillRemoval / fadeticks); float alpha = Mth.lerp(pt, lastAlpha, currentAlpha); @@ -148,38 +168,40 @@ public class Outliner { if (params.alpha < 1 / 8f) return; } - outline.render(ms, buffer, pt); + outline.render(ms, buffer, camera, pt); }); } public static class OutlineEntry { + public static final int FADE_TICKS = 8; - static final int fadeTicks = 4; - private Outline outline; - private int ticksTillRemoval; + private final Outline outline; + private int ticksTillRemoval = 1; public OutlineEntry(Outline outline) { this.outline = outline; - ticksTillRemoval = 1; - } - - public void tick() { - ticksTillRemoval--; - outline.tick(); - } - - public boolean isAlive() { - return ticksTillRemoval >= -fadeTicks; - } - - public boolean isFading() { - return ticksTillRemoval < 0; } public Outline getOutline() { return outline; } + public int getTicksTillRemoval() { + return ticksTillRemoval; + } + + public boolean isAlive() { + return ticksTillRemoval >= -FADE_TICKS; + } + + public boolean isFading() { + return ticksTillRemoval < 0; + } + + public void tick() { + ticksTillRemoval--; + outline.tick(); + } } } diff --git a/src/main/java/nl/requios/effortlessbuilding/create/foundation/utility/ghost/GhostBlockParams.java b/src/main/java/nl/requios/effortlessbuilding/create/foundation/utility/ghost/GhostBlockParams.java index 7202e91..e05c7e8 100644 --- a/src/main/java/nl/requios/effortlessbuilding/create/foundation/utility/ghost/GhostBlockParams.java +++ b/src/main/java/nl/requios/effortlessbuilding/create/foundation/utility/ghost/GhostBlockParams.java @@ -4,7 +4,6 @@ import net.minecraft.core.BlockPos; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import nl.requios.effortlessbuilding.create.foundation.utility.Color; -import nl.requios.effortlessbuilding.create.foundation.utility.outliner.Outline; import java.util.function.Supplier; diff --git a/src/main/java/nl/requios/effortlessbuilding/create/foundation/utility/outliner/AABBOutline.java b/src/main/java/nl/requios/effortlessbuilding/create/foundation/utility/outliner/AABBOutline.java deleted file mode 100644 index 5c85797..0000000 --- a/src/main/java/nl/requios/effortlessbuilding/create/foundation/utility/outliner/AABBOutline.java +++ /dev/null @@ -1,100 +0,0 @@ -package nl.requios.effortlessbuilding.create.foundation.utility.outliner; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import nl.requios.effortlessbuilding.create.foundation.render.RenderTypes; -import nl.requios.effortlessbuilding.create.foundation.render.SuperRenderTypeBuffer; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; - -public class AABBOutline extends Outline { - - protected AABB bb; - - public AABBOutline(AABB bb) { - this.setBounds(bb); - } - - @Override - public void render(PoseStack ms, SuperRenderTypeBuffer buffer, float pt) { - renderBB(ms, buffer, bb); - } - - public void renderBB(PoseStack ms, SuperRenderTypeBuffer buffer, AABB bb) { - Vec3 projectedView = Minecraft.getInstance().gameRenderer.getMainCamera() - .getPosition(); - boolean noCull = bb.contains(projectedView); - bb = bb.inflate(noCull ? -1 / 128d : 1 / 128d); - noCull |= params.disableCull; - - Vec3 xyz = new Vec3(bb.minX, bb.minY, bb.minZ); - Vec3 Xyz = new Vec3(bb.maxX, bb.minY, bb.minZ); - Vec3 xYz = new Vec3(bb.minX, bb.maxY, bb.minZ); - Vec3 XYz = new Vec3(bb.maxX, bb.maxY, bb.minZ); - Vec3 xyZ = new Vec3(bb.minX, bb.minY, bb.maxZ); - Vec3 XyZ = new Vec3(bb.maxX, bb.minY, bb.maxZ); - Vec3 xYZ = new Vec3(bb.minX, bb.maxY, bb.maxZ); - Vec3 XYZ = new Vec3(bb.maxX, bb.maxY, bb.maxZ); - - Vec3 start = xyz; - renderAACuboidLine(ms, buffer, start, Xyz); - renderAACuboidLine(ms, buffer, start, xYz); - renderAACuboidLine(ms, buffer, start, xyZ); - - start = XyZ; - renderAACuboidLine(ms, buffer, start, xyZ); - renderAACuboidLine(ms, buffer, start, XYZ); - renderAACuboidLine(ms, buffer, start, Xyz); - - start = XYz; - renderAACuboidLine(ms, buffer, start, xYz); - renderAACuboidLine(ms, buffer, start, Xyz); - renderAACuboidLine(ms, buffer, start, XYZ); - - start = xYZ; - renderAACuboidLine(ms, buffer, start, XYZ); - renderAACuboidLine(ms, buffer, start, xyZ); - renderAACuboidLine(ms, buffer, start, xYz); - - renderFace(ms, buffer, Direction.NORTH, xYz, XYz, Xyz, xyz, noCull); - renderFace(ms, buffer, Direction.SOUTH, XYZ, xYZ, xyZ, XyZ, noCull); - renderFace(ms, buffer, Direction.EAST, XYz, XYZ, XyZ, Xyz, noCull); - renderFace(ms, buffer, Direction.WEST, xYZ, xYz, xyz, xyZ, noCull); - renderFace(ms, buffer, Direction.UP, xYZ, XYZ, XYz, xYz, noCull); - renderFace(ms, buffer, Direction.DOWN, xyz, Xyz, XyZ, xyZ, noCull); - - } - - protected void renderFace(PoseStack ms, SuperRenderTypeBuffer buffer, Direction direction, Vec3 p1, Vec3 p2, - Vec3 p3, Vec3 p4, boolean noCull) { - if (!params.faceTexture.isPresent()) - return; - - ResourceLocation faceTexture = params.faceTexture.get() - .getLocation(); - float alphaBefore = params.alpha; - params.alpha = - (direction == params.getHighlightedFace() && params.hightlightedFaceTexture.isPresent()) ? 1 : 0.5f; - - RenderType translucentType = RenderTypes.getOutlineTranslucent(faceTexture, !noCull); - VertexConsumer builder = buffer.getLateBuffer(translucentType); - - Axis axis = direction.getAxis(); - Vec3 uDiff = p2.subtract(p1); - Vec3 vDiff = p4.subtract(p1); - float maxU = (float) Math.abs(axis == Axis.X ? uDiff.z : uDiff.x); - float maxV = (float) Math.abs(axis == Axis.Y ? vDiff.z : vDiff.y); - putQuadUV(ms, builder, p1, p2, p3, p4, 0, 0, maxU, maxV, Direction.UP); - params.alpha = alphaBefore; - } - - public void setBounds(AABB bb) { - this.bb = bb; - } - -} diff --git a/src/main/java/nl/requios/effortlessbuilding/create/foundation/utility/outliner/BlockClusterOutline.java b/src/main/java/nl/requios/effortlessbuilding/create/foundation/utility/outliner/BlockClusterOutline.java deleted file mode 100644 index 3ef0a55..0000000 --- a/src/main/java/nl/requios/effortlessbuilding/create/foundation/utility/outliner/BlockClusterOutline.java +++ /dev/null @@ -1,178 +0,0 @@ -package nl.requios.effortlessbuilding.create.foundation.utility.outliner; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import nl.requios.effortlessbuilding.create.AllSpecialTextures; -import nl.requios.effortlessbuilding.create.foundation.render.RenderTypes; -import nl.requios.effortlessbuilding.create.foundation.render.SuperRenderTypeBuffer; -import nl.requios.effortlessbuilding.create.foundation.utility.Iterate; -import nl.requios.effortlessbuilding.create.foundation.utility.VecHelper; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.core.Direction.AxisDirection; -import net.minecraft.world.phys.Vec3; - -import java.util.*; - -public class BlockClusterOutline extends Outline { - - private Cluster cluster; - - public BlockClusterOutline(Iterable selection) { - cluster = new Cluster(); - selection.forEach(cluster::include); - } - - @Override - public void render(PoseStack ms, SuperRenderTypeBuffer buffer, float pt) { - cluster.visibleEdges.forEach(edge -> { - Vec3 start = Vec3.atLowerCornerOf(edge.pos); - Direction direction = Direction.get(AxisDirection.POSITIVE, edge.axis); - renderAACuboidLine(ms, buffer, start, Vec3.atLowerCornerOf(edge.pos.relative(direction))); - }); - - Optional faceTexture = params.faceTexture; - if (!faceTexture.isPresent()) - return; - - RenderType translucentType = RenderTypes.getOutlineTranslucent(faceTexture.get() - .getLocation(), true); - VertexConsumer builder = buffer.getLateBuffer(translucentType); - - cluster.visibleFaces.forEach((face, axisDirection) -> { - Direction direction = Direction.get(axisDirection, face.axis); - BlockPos pos = face.pos; - if (axisDirection == AxisDirection.POSITIVE) - pos = pos.relative(direction.getOpposite()); - renderBlockFace(ms, builder, pos, direction); - }); - } - - static Vec3 xyz = new Vec3(-.5, -.5, -.5); - static Vec3 Xyz = new Vec3(.5, -.5, -.5); - static Vec3 xYz = new Vec3(-.5, .5, -.5); - static Vec3 XYz = new Vec3(.5, .5, -.5); - static Vec3 xyZ = new Vec3(-.5, -.5, .5); - static Vec3 XyZ = new Vec3(.5, -.5, .5); - static Vec3 xYZ = new Vec3(-.5, .5, .5); - static Vec3 XYZ = new Vec3(.5, .5, .5); - - protected void renderBlockFace(PoseStack ms, VertexConsumer builder, BlockPos pos, Direction face) { - Vec3 center = VecHelper.getCenterOf(pos); - Vec3 offset = Vec3.atLowerCornerOf(face.getNormal()); - offset = offset.scale(1 / 128d); - center = center.add(offset); - - ms.pushPose(); - ms.translate(center.x, center.y, center.z); - - switch (face) { - case DOWN: - putQuad(ms, builder, xyz, Xyz, XyZ, xyZ, face); - break; - case EAST: - putQuad(ms, builder, XYz, XYZ, XyZ, Xyz, face); - break; - case NORTH: - putQuad(ms, builder, xYz, XYz, Xyz, xyz, face); - break; - case SOUTH: - putQuad(ms, builder, XYZ, xYZ, xyZ, XyZ, face); - break; - case UP: - putQuad(ms, builder, xYZ, XYZ, XYz, xYz, face); - break; - case WEST: - putQuad(ms, builder, xYZ, xYz, xyz, xyZ, face); - default: - break; - } - - ms.popPose(); - } - - private static class Cluster { - - private Map visibleFaces; - private Set visibleEdges; - - public Cluster() { - visibleEdges = new HashSet<>(); - visibleFaces = new HashMap<>(); - } - - public void include(BlockPos pos) { - - // 6 FACES - for (Axis axis : Iterate.axes) { - Direction direction = Direction.get(AxisDirection.POSITIVE, axis); - for (int offset : Iterate.zeroAndOne) { - MergeEntry entry = new MergeEntry(axis, pos.relative(direction, offset)); - if (visibleFaces.remove(entry) == null) - visibleFaces.put(entry, offset == 0 ? AxisDirection.NEGATIVE : AxisDirection.POSITIVE); - } - } - - // 12 EDGES - for (Axis axis : Iterate.axes) { - for (Axis axis2 : Iterate.axes) { - if (axis == axis2) - continue; - for (Axis axis3 : Iterate.axes) { - if (axis == axis3) - continue; - if (axis2 == axis3) - continue; - - Direction direction = Direction.get(AxisDirection.POSITIVE, axis2); - Direction direction2 = Direction.get(AxisDirection.POSITIVE, axis3); - - for (int offset : Iterate.zeroAndOne) { - BlockPos entryPos = pos.relative(direction, offset); - for (int offset2 : Iterate.zeroAndOne) { - entryPos = entryPos.relative(direction2, offset2); - MergeEntry entry = new MergeEntry(axis, entryPos); - if (!visibleEdges.remove(entry)) - visibleEdges.add(entry); - } - } - } - - break; - } - } - - } - - } - - private static class MergeEntry { - - private Axis axis; - private BlockPos pos; - - public MergeEntry(Axis axis, BlockPos pos) { - this.axis = axis; - this.pos = pos; - } - - @Override - public boolean equals(Object o) { - if (this == o) - return true; - if (!(o instanceof MergeEntry)) - return false; - - MergeEntry other = (MergeEntry) o; - return this.axis == other.axis && this.pos.equals(other.pos); - } - - @Override - public int hashCode() { - return this.pos.hashCode() * 31 + axis.ordinal(); - } - } - -} diff --git a/src/main/java/nl/requios/effortlessbuilding/create/foundation/utility/outliner/LineOutline.java b/src/main/java/nl/requios/effortlessbuilding/create/foundation/utility/outliner/LineOutline.java deleted file mode 100644 index 2829a8d..0000000 --- a/src/main/java/nl/requios/effortlessbuilding/create/foundation/utility/outliner/LineOutline.java +++ /dev/null @@ -1,65 +0,0 @@ -package nl.requios.effortlessbuilding.create.foundation.utility.outliner; - -import com.mojang.blaze3d.vertex.PoseStack; -import nl.requios.effortlessbuilding.create.foundation.render.SuperRenderTypeBuffer; -import net.minecraft.util.Mth; -import net.minecraft.world.phys.Vec3; - -public class LineOutline extends Outline { - - protected Vec3 start = Vec3.ZERO; - protected Vec3 end = Vec3.ZERO; - - public LineOutline set(Vec3 start, Vec3 end) { - this.start = start; - this.end = end; - return this; - } - - @Override - public void render(PoseStack ms, SuperRenderTypeBuffer buffer, float pt) { - renderCuboidLine(ms, buffer, start, end); - } - - public static class EndChasingLineOutline extends LineOutline { - - float prevProgress = 0; - float progress = 0; - private boolean lockStart; - - public EndChasingLineOutline(boolean lockStart) { - this.lockStart = lockStart; - } - - @Override - public void tick() {} - - public EndChasingLineOutline setProgress(float progress) { - prevProgress = this.progress; - this.progress = progress; - return this; - } - - @Override - public LineOutline set(Vec3 start, Vec3 end) { - if (!end.equals(this.end)) - super.set(start, end); - return this; - } - - @Override - public void render(PoseStack ms, SuperRenderTypeBuffer buffer, float pt) { - float distanceToTarget = Mth.lerp(pt, prevProgress, progress); - if (!lockStart) - distanceToTarget = 1 - distanceToTarget; - Vec3 start = lockStart ? this.end : this.start; - Vec3 end = lockStart ? this.start : this.end; - - start = end.add(this.start.subtract(end) - .scale(distanceToTarget)); - renderCuboidLine(ms, buffer, start, end); - } - - } - -} diff --git a/src/main/java/nl/requios/effortlessbuilding/create/foundation/utility/outliner/Outline.java b/src/main/java/nl/requios/effortlessbuilding/create/foundation/utility/outliner/Outline.java deleted file mode 100644 index f051d65..0000000 --- a/src/main/java/nl/requios/effortlessbuilding/create/foundation/utility/outliner/Outline.java +++ /dev/null @@ -1,246 +0,0 @@ -package nl.requios.effortlessbuilding.create.foundation.utility.outliner; - -import com.jozufozu.flywheel.util.transform.TransformStack; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import org.joml.Matrix3f; -import nl.requios.effortlessbuilding.create.AllSpecialTextures; -import nl.requios.effortlessbuilding.create.foundation.render.RenderTypes; -import nl.requios.effortlessbuilding.create.foundation.render.SuperRenderTypeBuffer; -import nl.requios.effortlessbuilding.create.foundation.utility.AngleHelper; -import nl.requios.effortlessbuilding.create.foundation.utility.Color; -import nl.requios.effortlessbuilding.create.foundation.utility.VecHelper; -import net.minecraft.client.renderer.LightTexture; -import net.minecraft.client.renderer.texture.OverlayTexture; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.util.Mth; -import net.minecraft.world.phys.Vec3; - -import javax.annotation.Nullable; -import java.util.Optional; - -public abstract class Outline { - - protected OutlineParams params; - protected Matrix3f transformNormals; // TODO: not used? - - public Outline() { - params = new OutlineParams(); - } - - public abstract void render(PoseStack ms, SuperRenderTypeBuffer buffer, float pt); - - public void tick() {} - - public OutlineParams getParams() { - return params; - } - - public void renderCuboidLine(PoseStack ms, SuperRenderTypeBuffer buffer, Vec3 start, Vec3 end) { - Vec3 diff = end.subtract(start); - float hAngle = AngleHelper.deg(Mth.atan2(diff.x, diff.z)); - float hDistance = (float) diff.multiply(1, 0, 1) - .length(); - float vAngle = AngleHelper.deg(Mth.atan2(hDistance, diff.y)) - 90; - ms.pushPose(); - TransformStack.cast(ms) - .translate(start) - .rotateY(hAngle).rotateX(vAngle); - renderAACuboidLine(ms, buffer, Vec3.ZERO, new Vec3(0, 0, diff.length())); - ms.popPose(); - } - - public void renderAACuboidLine(PoseStack ms, SuperRenderTypeBuffer buffer, Vec3 start, Vec3 end) { - float lineWidth = params.getLineWidth(); - if (lineWidth == 0) - return; - - VertexConsumer builder = buffer.getBuffer(RenderTypes.getOutlineSolid()); - - Vec3 diff = end.subtract(start); - if (diff.x + diff.y + diff.z < 0) { - Vec3 temp = start; - start = end; - end = temp; - diff = diff.scale(-1); - } - - Vec3 extension = diff.normalize() - .scale(lineWidth / 2); - Vec3 plane = VecHelper.axisAlingedPlaneOf(diff); - Direction face = Direction.getNearest(diff.x, diff.y, diff.z); - Axis axis = face.getAxis(); - - start = start.subtract(extension); - end = end.add(extension); - plane = plane.scale(lineWidth / 2); - - Vec3 a1 = plane.add(start); - Vec3 b1 = plane.add(end); - plane = VecHelper.rotate(plane, -90, axis); - Vec3 a2 = plane.add(start); - Vec3 b2 = plane.add(end); - plane = VecHelper.rotate(plane, -90, axis); - Vec3 a3 = plane.add(start); - Vec3 b3 = plane.add(end); - plane = VecHelper.rotate(plane, -90, axis); - Vec3 a4 = plane.add(start); - Vec3 b4 = plane.add(end); - - if (params.disableNormals) { - face = Direction.UP; - putQuad(ms, builder, b4, b3, b2, b1, face); - putQuad(ms, builder, a1, a2, a3, a4, face); - putQuad(ms, builder, a1, b1, b2, a2, face); - putQuad(ms, builder, a2, b2, b3, a3, face); - putQuad(ms, builder, a3, b3, b4, a4, face); - putQuad(ms, builder, a4, b4, b1, a1, face); - return; - } - - putQuad(ms, builder, b4, b3, b2, b1, face); - putQuad(ms, builder, a1, a2, a3, a4, face.getOpposite()); - Vec3 vec = a1.subtract(a4); - face = Direction.getNearest(vec.x, vec.y, vec.z); - putQuad(ms, builder, a1, b1, b2, a2, face); - vec = VecHelper.rotate(vec, -90, axis); - face = Direction.getNearest(vec.x, vec.y, vec.z); - putQuad(ms, builder, a2, b2, b3, a3, face); - vec = VecHelper.rotate(vec, -90, axis); - face = Direction.getNearest(vec.x, vec.y, vec.z); - putQuad(ms, builder, a3, b3, b4, a4, face); - vec = VecHelper.rotate(vec, -90, axis); - face = Direction.getNearest(vec.x, vec.y, vec.z); - putQuad(ms, builder, a4, b4, b1, a1, face); - } - - public void putQuad(PoseStack ms, VertexConsumer builder, Vec3 v1, Vec3 v2, Vec3 v3, Vec3 v4, - Direction normal) { - putQuadUV(ms, builder, v1, v2, v3, v4, 0, 0, 1, 1, normal); - } - - public void putQuadUV(PoseStack ms, VertexConsumer builder, Vec3 v1, Vec3 v2, Vec3 v3, Vec3 v4, float minU, - float minV, float maxU, float maxV, Direction normal) { - putVertex(ms, builder, v1, minU, minV, normal); - putVertex(ms, builder, v2, maxU, minV, normal); - putVertex(ms, builder, v3, maxU, maxV, normal); - putVertex(ms, builder, v4, minU, maxV, normal); - } - - protected void putVertex(PoseStack ms, VertexConsumer builder, Vec3 pos, float u, float v, Direction normal) { - putVertex(ms.last(), builder, (float) pos.x, (float) pos.y, (float) pos.z, u, v, normal); - } - - protected void putVertex(PoseStack.Pose pose, VertexConsumer builder, float x, float y, float z, float u, float v, Direction normal) { - Color rgb = params.rgb; - if (transformNormals == null) - transformNormals = pose.normal(); - - int xOffset = 0; - int yOffset = 0; - int zOffset = 0; - - if (normal != null) { - xOffset = normal.getStepX(); - yOffset = normal.getStepY(); - zOffset = normal.getStepZ(); - } - - builder.vertex(pose.pose(), x, y, z) - .color(rgb.getRedAsFloat(), rgb.getGreenAsFloat(), rgb.getBlueAsFloat(), rgb.getAlphaAsFloat() * params.alpha) - .uv(u, v) - .overlayCoords(OverlayTexture.NO_OVERLAY) - .uv2(params.lightMap) - .normal(pose.normal(), xOffset, yOffset, zOffset) - .endVertex(); - - transformNormals = null; - } - - public static class OutlineParams { - protected Optional faceTexture; - protected Optional hightlightedFaceTexture; - protected Direction highlightedFace; - protected boolean fadeLineWidth; - protected boolean disableCull; - protected boolean disableNormals; - 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 disableNormals() { - disableNormals = true; - return this; - } - - public OutlineParams disableCull() { - disableCull = true; - return this; - } - - // getter - - public float getLineWidth() { - return fadeLineWidth ? alpha * lineWidth : lineWidth; - } - - public Direction getHighlightedFace() { - return highlightedFace; - } - - } - -}