Skip to content

Commit

Permalink
🚧 Replaced full rendered cuboid in blueprint preview with outlines th…
Browse files Browse the repository at this point in the history
…at are limited to the players render distance times 3.
  • Loading branch information
RXJpaw committed Dec 12, 2023
1 parent 34c91d2 commit 3aea03a
Show file tree
Hide file tree
Showing 7 changed files with 370 additions and 126 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,21 @@
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Hand;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.*;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Matrix4f;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.Vec3f;
import net.minecraft.util.registry.RegistryKey;
import net.minecraft.world.World;
import org.lwjgl.opengl.GL11;
import pw.rxj.iron_quarry.Main;
import pw.rxj.iron_quarry.block.QuarryBlock;
import pw.rxj.iron_quarry.item.BlueprintItem;
import pw.rxj.iron_quarry.resource.ResourceReloadListener;
import pw.rxj.iron_quarry.util.ZUtil;

import java.util.HashSet;
import java.util.List;


public class BlueprintPreviewRenderer {
public static final Identifier BLUEPRINT_PREVIEW_TEXTURE = Identifier.of(Main.MOD_ID, "textures/world/blueprint_preview.png");

private static void render(WorldRenderContext context) {
MinecraftClient minecraftClient = MinecraftClient.getInstance();
if(minecraftClient.world == null) return;
Expand Down Expand Up @@ -60,32 +58,19 @@ private static void render(WorldRenderContext context) {
BlockPos secondPos = blueprintItem.getSecondPos(blueprintStack);
if(secondPos == null) return;

int light = 14680272;
float tickDelta = context.tickDelta();
double viewDistance = Math.min(minecraftClient.options.getClampedViewDistance() * 16 * 4, 2048.0);

double viewDistance = Math.min(minecraftClient.options.getClampedViewDistance() * 16 * 3, 1536.0);
Camera camera = context.camera();
MatrixStack matrices = context.matrixStack();
LightmapTextureManager lightmapTextureManager = context.lightmapTextureManager();

matrices.push();

Vec3d lerpedPlayerPos = player.getLerpedPos(tickDelta);

Vec3d lowest = new Vec3d(
Math.min(firstPos.getX(), secondPos.getX()),
Math.min(firstPos.getY(), secondPos.getY()),
Math.min(firstPos.getZ(), secondPos.getZ())
).subtract(lerpedPlayerPos);
Vec3d highest = new Vec3d(
Math.max(firstPos.getX(), secondPos.getX()),
Math.max(firstPos.getY(), secondPos.getY()),
Math.max(firstPos.getZ(), secondPos.getZ())
).subtract(lerpedPlayerPos).add(1, 1, 1);

Vec3d limitedLowest = RenderUtil.minMaxVec3d(lowest, viewDistance, -viewDistance);
Vec3d limitedHighest = RenderUtil.minMaxVec3d(highest, viewDistance, -viewDistance);
HashSet<Direction> limitedDirections = RenderUtil.limitedDirections(lowest, limitedLowest, highest, limitedHighest);
Cuboid originalCuboid = Cuboid.from(firstPos, secondPos).subtract(lerpedPlayerPos).fullblock();
Cuboid viewDistanceCuboid = Cuboid.from(viewDistance, -viewDistance);
Cuboid limitedCuboid = originalCuboid.limitInside(viewDistanceCuboid);
if(limitedCuboid.isFlat()) return;

Vec3d playerToCameraPos = lerpedPlayerPos.subtract(camera.getPos());
matrices.translate(playerToCameraPos.x, playerToCameraPos.y, playerToCameraPos.z);
Expand All @@ -94,52 +79,58 @@ private static void render(WorldRenderContext context) {
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder buffer = tessellator.getBuffer();

lightmapTextureManager.enable();

RenderSystem.setShader(GameRenderer::getRenderTypeTranslucentShader);
RenderSystem.setShaderTexture(0, BLUEPRINT_PREVIEW_TEXTURE);
// WorldRenderEvents.END doesn't call this when the world border is rendered.
// Resulting in color, transparency and brightness being way off.
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
RenderSystem.depthFunc(GL11.GL_ALWAYS);
RenderSystem.disableCull();
RenderSystem.defaultBlendFunc();

//Outlines
RenderSystem.setShader(GameRenderer::getRenderTypeLinesShader);
RenderSystem.lineWidth(3.0F);
RenderSystem.enableBlend();
RenderSystem.disableCull();

/*
* WorldRenderEvents.END doesn't call this when the world border is rendered.
* Resulting in transparency and brightness being way off.
*/
RenderSystem.defaultBlendFunc();
double outlineOffset = 0.02;

buffer.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR_TEXTURE_LIGHT_NORMAL);
List<SpriteVec2f> boxLines = limitedCuboid.inflate(outlineOffset).getLines();
List<SpriteVec2f> splitBoxLines = boxLines.stream().map(vec -> vec.autoSplit(8.0F)).flatMap(List::stream).toList();
List<SpriteVec2f> filteredSplitBoxLines = splitBoxLines.stream().filter(vec -> vec.distanceTo(Vec3f.ZERO) <= viewDistance).toList();

float minU = 0.0F;
float maxU = 1.0F;
float minV = 0.0F;
float maxV = 1.0F;
//Visible Outlines
RenderSystem.depthFunc(GL11.GL_LESS);
buffer.begin(VertexFormat.DrawMode.LINES, VertexFormats.LINES);

for (Direction direction : Direction.values()) {
if(limitedDirections.contains(direction)) continue;
for (SpriteVec2f line : filteredSplitBoxLines) {
Vec3f n = line.normalize();

SpriteVec anchors = RenderUtil.anchorsFrom(direction, new Vec3f(limitedLowest), new Vec3f(limitedHighest));
buffer.vertex(positionMatrix, line.from.getX(), line.from.getY(), line.from.getZ()).color(1.0F, 1.0F, 1.0F, 1.0F).normal(matrices.peek().getNormalMatrix(), n.getX(), n.getY(), n.getZ()).next();
buffer.vertex(positionMatrix, line.to.getX(), line.to.getY(), line.to.getZ()).color(1.0F, 1.0F, 1.0F, 1.0F).normal(matrices.peek().getNormalMatrix(), n.getX(), n.getY(), n.getZ()).next();
}

tessellator.draw();

//Hidden Outlines
RenderSystem.depthFunc(GL11.GL_GREATER);
buffer.begin(VertexFormat.DrawMode.LINES, VertexFormats.LINES);

buffer.vertex(positionMatrix, anchors.tl.getX(), anchors.tl.getY(), anchors.tl.getZ()).color(0.2F, 0.2F, 0.2F, 1.0F).texture(minU, minV).light(light).normal(0, 0, 0).next();
buffer.vertex(positionMatrix, anchors.bl.getX(), anchors.bl.getY(), anchors.bl.getZ()).color(1.0F, 1.0F, 1.0F, 1.0F).texture(minU, maxV).light(light).normal(0, 0, 0).next();
buffer.vertex(positionMatrix, anchors.br.getX(), anchors.br.getY(), anchors.br.getZ()).color(0.2F, 0.2F, 0.2F, 1.0F).texture(maxU, maxV).light(light).normal(0, 0, 0).next();
buffer.vertex(positionMatrix, anchors.tr.getX(), anchors.tr.getY(), anchors.tr.getZ()).color(1.0F, 1.0F, 1.0F, 1.0F).texture(maxU, minV).light(light).normal(0, 0, 0).next();
for (SpriteVec2f line : filteredSplitBoxLines) {
Vec3f n = line.normalize();

buffer.vertex(positionMatrix, line.from.getX(), line.from.getY(), line.from.getZ()).color(1.0F, 1.0F, 1.0F, 0.2F).normal(matrices.peek().getNormalMatrix(), n.getX(), n.getY(), n.getZ()).next();
buffer.vertex(positionMatrix, line.to.getX(), line.to.getY(), line.to.getZ()).color(1.0F, 1.0F, 1.0F, 0.2F).normal(matrices.peek().getNormalMatrix(), n.getX(), n.getY(), n.getZ()).next();
}

tessellator.draw();

RenderSystem.depthFunc(GL11.GL_LEQUAL);
RenderSystem.enableCull();
RenderSystem.lineWidth(1.0F);
RenderSystem.disableBlend();

lightmapTextureManager.disable();
RenderSystem.enableCull();

matrices.pop();
}

public static void register() {
ResourceReloadListener.include(BLUEPRINT_PREVIEW_TEXTURE);
WorldRenderEvents.END.register(BlueprintPreviewRenderer::render);
}
}
214 changes: 214 additions & 0 deletions src/main/java/pw/rxj/iron_quarry/render/Cuboid.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
package pw.rxj.iron_quarry.render;

import net.minecraft.util.math.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class Cuboid {
private boolean fullblockAdjusted = false;

public Vec3d lowPos;
public Vec3d highPos;

private Cuboid(Vec3d pos1, Vec3d pos2, boolean process) {
if(process) {
this.lowPos = new Vec3d(
Math.min(pos1.getX(), pos2.getX()),
Math.min(pos1.getY(), pos2.getY()),
Math.min(pos1.getZ(), pos2.getZ())
);
this.highPos = new Vec3d(
Math.max(pos1.getX(), pos2.getX()),
Math.max(pos1.getY(), pos2.getY()),
Math.max(pos1.getZ(), pos2.getZ())
);
} else {
this.lowPos = pos1;
this.highPos = pos2;
}
}
public static Cuboid from(Vec3d pos1, Vec3d pos2) {
return new Cuboid(pos1, pos2, true);
}
private static Cuboid fromProcessed(Vec3d lowPos, Vec3d highPos) {
return new Cuboid(lowPos, highPos, false);
}
public static Cuboid from(double allSame1, double allSame2) {
Vec3d pos1 = new Vec3d(allSame1, allSame1, allSame1);
Vec3d pos2 = new Vec3d(allSame2, allSame2, allSame2);

return from(pos1, pos2);
}
public static Cuboid from(BlockPos blockPos1, BlockPos blockPos2) {
Vec3d pos1 = new Vec3d(blockPos1.getX(), blockPos1.getY(), blockPos1.getZ());
Vec3d pos2 = new Vec3d(blockPos2.getX(), blockPos2.getY(), blockPos2.getZ());

return from(pos1, pos2);
}

public Cuboid subtract(double allSame) {
return this.subtract(new Vec3d(allSame, allSame, allSame));
}
public Cuboid subtract(Vec3d vector) {
return Cuboid.fromProcessed(this.lowPos.subtract(vector), this.highPos.subtract(vector));
}
public Cuboid add(double allSame) {
return this.add(new Vec3d(allSame, allSame, allSame));
}
public Cuboid add(Vec3d vector) {
return Cuboid.fromProcessed(this.lowPos.add(vector), this.highPos.add(vector));
}
public Cuboid inflate(double offset) {
return this.inflate(new Vec3d(offset, offset, offset));
}
public Cuboid inflate(Vec3d offset) {
return Cuboid.fromProcessed(this.lowPos.subtract(offset), this.highPos.add(offset));
}
public Cuboid deflate(double offset) {
return this.deflate(new Vec3d(offset, offset, offset));
}
public Cuboid deflate(Vec3d offset) {
return Cuboid.fromProcessed(this.lowPos.add(offset), this.highPos.subtract(offset));
}

public Vec3d abs() {
return this.highPos.subtract(this.lowPos);
}

public Cuboid fullblock() {
if(this.isFullblockAdjusted()) {
throw new IllegalStateException("Cuboid is already fullblock adjusted.");
}

Cuboid cuboid = Cuboid.fromProcessed(this.lowPos, this.highPos.add(1, 1, 1));
cuboid.setFullblockAdjusted();

return cuboid;
}
public boolean isFullblockAdjusted() {
return this.fullblockAdjusted;
}
private void setFullblockAdjusted() {
this.fullblockAdjusted = true;
}

public Cuboid limitInside(Cuboid other) {
Vec3d lowPos = new Vec3d(
Math.min(Math.max(this.lowPos.x, other.lowPos.x), other.highPos.x),
Math.min(Math.max(this.lowPos.y, other.lowPos.y), other.highPos.x),
Math.min(Math.max(this.lowPos.z, other.lowPos.z), other.highPos.x)
);
Vec3d highPos = new Vec3d(
Math.min(Math.max(this.highPos.x, other.lowPos.x), other.highPos.x),
Math.min(Math.max(this.highPos.y, other.lowPos.y), other.highPos.x),
Math.min(Math.max(this.highPos.z, other.lowPos.z), other.highPos.x)
);

return Cuboid.fromProcessed(lowPos, highPos);
}

public boolean isFlat() {
return this.lowPos.x == this.highPos.x ||
this.lowPos.y == this.highPos.y ||
this.lowPos.z == this.highPos.z;
}
public boolean isOutside(Vec3d pos) {
return pos.x < this.lowPos.x || pos.y < this.lowPos.y || pos.z < this.lowPos.z ||
pos.x > this.highPos.x || pos.y > this.highPos.y || pos.z > this.highPos.z;
}
public boolean isPointInside(Vec2f flatPos) {
return flatPos.x >= this.lowPos.x && flatPos.y >= this.lowPos.z && flatPos.x < this.highPos.x && flatPos.y < this.highPos.z;
}

public List<SpriteVec2f> getLines() {
Vec3d abs = this.abs();

List<SpriteVec2f> lines = new ArrayList<>();

lines.add(SpriteVec2f.from(this.lowPos, this.lowPos.add(abs.x, 0, 0)));
lines.add(SpriteVec2f.from(this.lowPos, this.lowPos.add(0, abs.y, 0)));
lines.add(SpriteVec2f.from(this.lowPos, this.lowPos.add(0, 0, abs.z)));

lines.add(SpriteVec2f.from(this.lowPos.add(0, 0, abs.z), this.lowPos.add(abs.x, 0, abs.z)));
lines.add(SpriteVec2f.from(this.lowPos.add(0, 0, abs.z), this.lowPos.add(0, abs.y, abs.z)));
lines.add(SpriteVec2f.from(this.lowPos.add(0, abs.y, 0), this.lowPos.add(0, abs.y, abs.z)));

lines.add(SpriteVec2f.from(this.highPos, this.highPos.subtract(abs.x, 0, 0)));
lines.add(SpriteVec2f.from(this.highPos, this.highPos.subtract(0, abs.y, 0)));
lines.add(SpriteVec2f.from(this.highPos, this.highPos.subtract(0, 0, abs.z)));

lines.add(SpriteVec2f.from(this.highPos.subtract(0, 0, abs.z), this.highPos.subtract(abs.x, 0, abs.z)));
lines.add(SpriteVec2f.from(this.highPos.subtract(0, 0, abs.z), this.highPos.subtract(0, abs.y, abs.z)));
lines.add(SpriteVec2f.from(this.highPos.subtract(0, abs.y, 0), this.highPos.subtract(0, abs.y, abs.z)));

return lines;
}
public SpriteVec4f getAnchors(Direction direction) {
Vec3f anchor_tl = null;
Vec3f anchor_bl = null;
Vec3f anchor_br = null;
Vec3f anchor_tr = null;

float minX = (float) this.lowPos.x;
float minY = (float) this.lowPos.y;
float minZ = (float) this.lowPos.z;

float maxX = (float) this.highPos.x;
float maxY = (float) this.highPos.y;
float maxZ = (float) this.highPos.z;

switch (direction) {
case UP -> {
anchor_tl = new Vec3f(maxX, maxY, maxZ); //top left
anchor_bl = new Vec3f(maxX, maxY, minZ); //bottom left
anchor_br = new Vec3f(minX, maxY, minZ); //bottom right
anchor_tr = new Vec3f(minX, maxY, maxZ); //top right
}
case NORTH -> {
anchor_tl = new Vec3f(maxX, maxY, minZ);
anchor_bl = new Vec3f(maxX, minY, minZ);
anchor_br = new Vec3f(minX, minY, minZ);
anchor_tr = new Vec3f(minX, maxY, minZ);
}
case WEST -> {
anchor_tl = new Vec3f(minX, maxY, minZ);
anchor_bl = new Vec3f(minX, minY, minZ);
anchor_br = new Vec3f(minX, minY, maxZ);
anchor_tr = new Vec3f(minX, maxY, maxZ);
}
case SOUTH -> {
anchor_tl = new Vec3f(minX, maxY, maxZ);
anchor_bl = new Vec3f(minX, minY, maxZ);
anchor_br = new Vec3f(maxX, minY, maxZ);
anchor_tr = new Vec3f(maxX, maxY, maxZ);
}
case EAST -> {
anchor_tl = new Vec3f(maxX, maxY, maxZ);
anchor_bl = new Vec3f(maxX, minY, maxZ);
anchor_br = new Vec3f(maxX, minY, minZ);
anchor_tr = new Vec3f(maxX, maxY, minZ);
}
case DOWN -> {
anchor_tl = new Vec3f(minX, minY, maxZ);
anchor_bl = new Vec3f(minX, minY, minZ);
anchor_br = new Vec3f(maxX, minY, minZ);
anchor_tr = new Vec3f(maxX, minY, maxZ);
}
}

return SpriteVec4f.from(anchor_tl, anchor_bl, anchor_br, anchor_tr);
}
public HashMap<Direction, Boolean> matchingDirections(Cuboid suspect) {
HashMap<Direction, Boolean> directions = new HashMap<>();
directions.put(Direction.WEST, this.lowPos.x == suspect.lowPos.x);
directions.put(Direction.DOWN, this.lowPos.y == suspect.lowPos.y);
directions.put(Direction.NORTH, this.lowPos.z == suspect.lowPos.z);
directions.put(Direction.EAST, this.highPos.x == suspect.highPos.x);
directions.put(Direction.UP, this.highPos.y == suspect.highPos.y);
directions.put(Direction.SOUTH, this.highPos.z == suspect.highPos.z);

return directions;
}
}
Loading

0 comments on commit 3aea03a

Please sign in to comment.