diff --git a/Xplat/src/main/java/vazkii/botania/client/core/helper/RenderHelper.java b/Xplat/src/main/java/vazkii/botania/client/core/helper/RenderHelper.java index f2ca36667e..fcece0c1b3 100644 --- a/Xplat/src/main/java/vazkii/botania/client/core/helper/RenderHelper.java +++ b/Xplat/src/main/java/vazkii/botania/client/core/helper/RenderHelper.java @@ -87,6 +87,23 @@ public final class RenderHelper extends RenderType { private static final int ITEM_AND_PADDING_WIDTH = 20; + private static final double INITIAL_OFFSET = 0.005; + private static final double OFFSET_INCREMENT = 0.001; + // Global y offset so that overlapping landmines or radius descriptors do not Z-fight + private static double offY = INITIAL_OFFSET; + + public static double getOffY() { + return offY; + } + + public static void incrementOffY() { + offY += OFFSET_INCREMENT; + } + + public static void onWorldRenderLast() { + offY = INITIAL_OFFSET; + } + private static RenderType makeLayer(String name, VertexFormat format, VertexFormat.Mode mode, int bufSize, boolean hasCrumbling, boolean sortOnUpload, CompositeState glState) { return RenderTypeAccessor.create(name, format, mode, bufSize, hasCrumbling, sortOnUpload, glState); @@ -324,6 +341,15 @@ public static void triangleFan(Runnable center, List vertices) { } } + public static void flatRectangle(VertexConsumer buffer, Matrix4f mat, + float xMin, float xMax, float y, float zMin, float zMax, + int r, int g, int b, int a) { + buffer.vertex(mat, xMax, y, zMin).color(r, g, b, a).endVertex(); + buffer.vertex(mat, xMin, y, zMin).color(r, g, b, a).endVertex(); + buffer.vertex(mat, xMin, y, zMax).color(r, g, b, a).endVertex(); + buffer.vertex(mat, xMax, y, zMax).color(r, g, b, a).endVertex(); + } + public static void renderProgressPie(GuiGraphics gui, int x, int y, float progress, ItemStack stack) { PoseStack ms = gui.pose(); Minecraft mc = Minecraft.getInstance(); diff --git a/Xplat/src/main/java/vazkii/botania/client/render/block_entity/SpecialFlowerBlockEntityRenderer.java b/Xplat/src/main/java/vazkii/botania/client/render/block_entity/SpecialFlowerBlockEntityRenderer.java index 38ccacc050..686180fa03 100644 --- a/Xplat/src/main/java/vazkii/botania/client/render/block_entity/SpecialFlowerBlockEntityRenderer.java +++ b/Xplat/src/main/java/vazkii/botania/client/render/block_entity/SpecialFlowerBlockEntityRenderer.java @@ -35,10 +35,16 @@ import vazkii.botania.common.item.WandOfTheForestItem; import vazkii.botania.common.item.equipment.bauble.ManaseerMonocleItem; -import java.util.ArrayList; -import java.util.List; - public class SpecialFlowerBlockEntityRenderer implements BlockEntityRenderer { + + public static final int INNER_ALPHA = 32; + public static final int OUTER_ALPHA = 64; + public static final float FRAME_WIDTH = 1F / 16F; + public static final float Y_OFFSET_INNER = 1F / 16F; + public static final float Y_OFFSET_OUTER = FRAME_WIDTH + FRAME_WIDTH / 4F; + public static final int TOTAL_ANGLES = 360; + public static final double DEGREES_TO_RADIAN = (Math.PI / (double) (TOTAL_ANGLES / 2)); + public SpecialFlowerBlockEntityRenderer(BlockEntityRendererProvider.Context ctx) {} @Override @@ -77,12 +83,13 @@ public void render(SpecialFlowerBlockEntity tile, float partialTicks, PoseStack public static void renderRadius(BlockEntity tile, PoseStack ms, MultiBufferSource buffers, @Nullable RadiusDescriptor descriptor) { if (descriptor != null) { ms.pushPose(); - ms.translate(-tile.getBlockPos().getX(), -tile.getBlockPos().getY(), -tile.getBlockPos().getZ()); + ms.translate(0, RenderHelper.getOffY(), 0); if (descriptor instanceof RadiusDescriptor.Circle circle) { - renderCircle(ms, buffers, circle.subtileCoords(), circle.radius()); + renderCircle(ms, buffers, tile.getBlockPos(), circle.subtileCoords(), circle.radius()); } else if (descriptor instanceof RadiusDescriptor.Rectangle rectangle) { - renderRectangle(ms, buffers, rectangle.aabb(), true, null, (byte) 32); + renderRectangle(ms, buffers, tile.getBlockPos(), rectangle.aabb()); } + RenderHelper.incrementOffY(); ms.popPose(); } } @@ -95,87 +102,67 @@ public static boolean hasBindingAttempt(LivingEntity view, BlockPos tilePos) { return false; } - private static void renderCircle(PoseStack ms, MultiBufferSource buffers, BlockPos center, double radius) { + public static void renderCircle(PoseStack ms, MultiBufferSource buffers, BlockPos tilePos, BlockPos center, double radius) { ms.pushPose(); - double x = center.getX() + 0.5; - double y = center.getY(); - double z = center.getZ() + 0.5; - ms.translate(x, y, z); + ms.translate(center.getX() - tilePos.getX() + 0.5, center.getY() - tilePos.getY(), center.getZ() - tilePos.getZ() + 0.5); + int color = Mth.hsvToRgb(ClientTickHandler.ticksInGame % 200 / 200F, 0.6F, 1F); int r = (color >> 16 & 0xFF); int g = (color >> 8 & 0xFF); int b = (color & 0xFF); - int alpha = 32; - float f = 1F / 16F; - - int totalAngles = 360; - int drawAngles = 360; - int step = totalAngles / drawAngles; - - radius -= f; VertexConsumer buffer = buffers.getBuffer(RenderHelper.CIRCLE); Matrix4f mat = ms.last().pose(); - Runnable centerFunc = () -> buffer.vertex(mat, 0, f, 0).color(r, g, b, alpha).endVertex(); - List vertexFuncs = new ArrayList<>(); - for (int i = 0; i < totalAngles + 1; i += step) { - double rad = (totalAngles - i) * Math.PI / 180.0; - float xp = (float) (Math.cos(rad) * radius); - float zp = (float) (Math.sin(rad) * radius); - vertexFuncs.add(() -> buffer.vertex(mat, xp, f, zp).color(r, g, b, alpha).endVertex()); - } - RenderHelper.triangleFan(centerFunc, vertexFuncs); - - radius += f; - float f1 = f + f / 4F; - int alpha2 = 64; - - centerFunc = () -> buffer.vertex(mat, 0, f1, 0).color(r, g, b, alpha2).endVertex(); - vertexFuncs.clear(); - for (int i = 0; i < totalAngles + 1; i += step) { - double rad = (totalAngles - i) * Math.PI / 180.0; - float xp = (float) (Math.cos(rad) * radius); - float zp = (float) (Math.sin(rad) * radius); - vertexFuncs.add(() -> buffer.vertex(mat, xp, f1, zp).color(r, g, b, alpha2).endVertex()); + double innerRadius = radius - FRAME_WIDTH; + Runnable centerFuncInner = () -> buffer.vertex(mat, 0, Y_OFFSET_INNER, 0).color(r, g, b, INNER_ALPHA).endVertex(); + Runnable centerFuncOuter = () -> buffer.vertex(mat, 0, Y_OFFSET_OUTER, 0).color(r, g, b, OUTER_ALPHA).endVertex(); + Runnable[] vertexFuncsInner = new Runnable[TOTAL_ANGLES + 1]; + Runnable[] vertexFuncsOuter = new Runnable[TOTAL_ANGLES + 1]; + + for (int i = 0; i < TOTAL_ANGLES; i++) { + double rad = (TOTAL_ANGLES - i) * DEGREES_TO_RADIAN; + double cos = Math.cos(rad); + double sin = Math.sin(rad); + + float xpInner = (float) (cos * innerRadius); + float zpInner = (float) (sin * innerRadius); + vertexFuncsInner[i] = (() -> buffer.vertex(mat, xpInner, Y_OFFSET_INNER, zpInner).color(r, g, b, INNER_ALPHA).endVertex()); + + float xpOuter = (float) (Math.cos(rad) * radius); + float zpOuter = (float) (Math.sin(rad) * radius); + vertexFuncsOuter[i] = (() -> buffer.vertex(mat, xpOuter, Y_OFFSET_OUTER, zpOuter).color(r, g, b, OUTER_ALPHA).endVertex()); } - RenderHelper.triangleFan(centerFunc, vertexFuncs); + vertexFuncsInner[TOTAL_ANGLES] = vertexFuncsInner[0]; + vertexFuncsOuter[TOTAL_ANGLES] = vertexFuncsOuter[0]; + + RenderHelper.triangleFan(centerFuncInner, vertexFuncsInner); + RenderHelper.triangleFan(centerFuncOuter, vertexFuncsOuter); + ms.popPose(); } - public static void renderRectangle(PoseStack ms, MultiBufferSource buffers, AABB aabb, boolean inner, @Nullable Integer color, byte alpha) { + public static void renderRectangle(PoseStack ms, MultiBufferSource buffers, BlockPos tilePos, AABB aabb) { ms.pushPose(); - ms.translate(aabb.minX, aabb.minY, aabb.minZ); + ms.translate(aabb.minX - tilePos.getX(), aabb.minY - tilePos.getY(), aabb.minZ - tilePos.getZ()); - if (color == null) { - color = Mth.hsvToRgb(ClientTickHandler.ticksInGame % 200 / 200F, 0.6F, 1F); - } + int color = Mth.hsvToRgb(ClientTickHandler.ticksInGame % 200 / 200F, 0.6F, 1F); int r = (color >> 16 & 0xFF); int g = (color >> 8 & 0xFF); int b = (color & 0xFF); - float f = 1F / 16F; - float x = (float) (aabb.maxX - aabb.minX - f); - float z = (float) (aabb.maxZ - aabb.minZ - f); + float xSize = (float) aabb.getXsize(); + float zSize = (float) aabb.getZsize(); + float xSizeInner = xSize - FRAME_WIDTH; + float zSizeInner = zSize - FRAME_WIDTH; VertexConsumer buffer = buffers.getBuffer(RenderHelper.RECTANGLE); Matrix4f mat = ms.last().pose(); - buffer.vertex(mat, x, f, f).color(r, g, b, alpha).endVertex(); - buffer.vertex(mat, f, f, f).color(r, g, b, alpha).endVertex(); - buffer.vertex(mat, f, f, z).color(r, g, b, alpha).endVertex(); - buffer.vertex(mat, x, f, z).color(r, g, b, alpha).endVertex(); - - if (inner) { - x += f; - z += f; - float f1 = f + f / 4F; - alpha *= 2; - buffer.vertex(mat, x, f1, 0).color(r, g, b, alpha).endVertex(); - buffer.vertex(mat, 0, f1, 0).color(r, g, b, alpha).endVertex(); - buffer.vertex(mat, 0, f1, z).color(r, g, b, alpha).endVertex(); - buffer.vertex(mat, x, f1, z).color(r, g, b, alpha).endVertex(); - } + RenderHelper.flatRectangle(buffer, mat, FRAME_WIDTH, xSizeInner, Y_OFFSET_INNER, FRAME_WIDTH, zSizeInner, + r, g, b, INNER_ALPHA); + RenderHelper.flatRectangle(buffer, mat, 0, xSize, Y_OFFSET_OUTER, 0, zSize, r, g, b, OUTER_ALPHA); ms.popPose(); } + } diff --git a/Xplat/src/main/java/vazkii/botania/client/render/entity/MagicLandmineRenderer.java b/Xplat/src/main/java/vazkii/botania/client/render/entity/MagicLandmineRenderer.java index fbe7fa3949..cf264b5b87 100644 --- a/Xplat/src/main/java/vazkii/botania/client/render/entity/MagicLandmineRenderer.java +++ b/Xplat/src/main/java/vazkii/botania/client/render/entity/MagicLandmineRenderer.java @@ -9,6 +9,7 @@ package vazkii.botania.client.render.entity; import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.entity.EntityRenderer; @@ -18,24 +19,18 @@ import net.minecraft.world.phys.AABB; import org.jetbrains.annotations.NotNull; +import org.joml.Matrix4f; import vazkii.botania.client.core.handler.ClientTickHandler; -import vazkii.botania.client.render.block_entity.SpecialFlowerBlockEntityRenderer; +import vazkii.botania.client.core.helper.RenderHelper; import vazkii.botania.common.entity.MagicLandmineEntity; public class MagicLandmineRenderer extends EntityRenderer { - private static final double INITIAL_OFFSET = -1.0 / 16 + 0.005; - // Global y offset so that overlapping landmines do not Z-fight - public static double offY = INITIAL_OFFSET; public MagicLandmineRenderer(EntityRendererProvider.Context ctx) { super(ctx); } - public static void onWorldRenderLast() { - offY = INITIAL_OFFSET; - } - @Override public void render(MagicLandmineEntity e, float entityYaw, float partialTicks, PoseStack ms, MultiBufferSource buffers, int light) { super.render(e, entityYaw, partialTicks, ms, buffers, light); @@ -47,7 +42,6 @@ public void render(MagicLandmineEntity e, float entityYaw, float partialTicks, P int r = (int) (105 * gs); int g = (int) (25 * gs); int b = (int) (145 * gs); - int color = r << 16 | g << 8 | b; int alpha = 32; if (e.tickCount < 8) { @@ -56,8 +50,16 @@ public void render(MagicLandmineEntity e, float entityYaw, float partialTicks, P alpha *= Math.min(1F - (e.tickCount - 47 + partialTicks) / 8F, 1F); } - SpecialFlowerBlockEntityRenderer.renderRectangle(ms, buffers, aabb, false, color, (byte) alpha); - offY += 0.001; + ms.translate(aabb.minX, aabb.minY + RenderHelper.getOffY(), aabb.minZ); + + float f = 1F / 16F; + float x = (float) (aabb.getXsize() - f); + float z = (float) (aabb.getZsize() - f); + + VertexConsumer buffer = buffers.getBuffer(RenderHelper.RECTANGLE); + Matrix4f mat = ms.last().pose(); + RenderHelper.flatRectangle(buffer, mat, f, x, 0, f, z, r, g, b, alpha); + RenderHelper.incrementOffY(); ms.popPose(); } diff --git a/Xplat/src/main/java/vazkii/botania/client/render/world/WorldOverlays.java b/Xplat/src/main/java/vazkii/botania/client/render/world/WorldOverlays.java index 3720ccd0cd..99d50ea506 100644 --- a/Xplat/src/main/java/vazkii/botania/client/render/world/WorldOverlays.java +++ b/Xplat/src/main/java/vazkii/botania/client/render/world/WorldOverlays.java @@ -6,8 +6,8 @@ import net.minecraft.client.renderer.RenderBuffers; import net.minecraft.world.level.Level; +import vazkii.botania.client.core.helper.RenderHelper; import vazkii.botania.client.fx.BoltRenderer; -import vazkii.botania.client.render.entity.MagicLandmineRenderer; import vazkii.botania.common.item.AssemblyHaloItem; public final class WorldOverlays { @@ -16,7 +16,7 @@ public static void renderWorldLast(Camera camera, float tickDelta, PoseStack mat AssemblyHaloItem.Rendering.onRenderWorldLast(camera, tickDelta, matrix, buffers); BoundBlockRenderer.onWorldRenderLast(camera, matrix, level); AstrolabePreviewHandler.onWorldRenderLast(matrix, buffers, level); - MagicLandmineRenderer.onWorldRenderLast(); + RenderHelper.onWorldRenderLast(); } private WorldOverlays() {}