From 30f0835a21ac78c0b5c4a9de1483a9d2fb6462e9 Mon Sep 17 00:00:00 2001 From: Ruling-0 <47913168+Ruling-0@users.noreply.github.com> Date: Wed, 28 Oct 2026 19:27:01 -0500 Subject: [PATCH] Sort block entities back to front before dispatch --- .../celeritas/CeleritasWorldRenderer.java | 44 ++--------- .../celeritas/TileEntityDepthOrder.java | 79 +++++++++++++++++++ .../celeritas/TileEntityDepthOrderTest.java | 31 ++++++++ 3 files changed, 116 insertions(+), 38 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/rendering/celeritas/TileEntityDepthOrder.java create mode 100644 src/test/java/com/gtnewhorizons/angelica/rendering/celeritas/TileEntityDepthOrderTest.java diff --git a/src/main/java/com/gtnewhorizons/angelica/rendering/celeritas/CeleritasWorldRenderer.java b/src/main/java/com/gtnewhorizons/angelica/rendering/celeritas/CeleritasWorldRenderer.java index 2983e1e8b..f5a37d485 100644 --- a/src/main/java/com/gtnewhorizons/angelica/rendering/celeritas/CeleritasWorldRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/rendering/celeritas/CeleritasWorldRenderer.java @@ -1,8 +1,6 @@ package com.gtnewhorizons.angelica.rendering.celeritas; -import java.util.ArrayList; import java.util.Collection; -import java.util.Comparator; import java.util.List; import com.gtnewhorizons.angelica.compat.bop.FogBiomeCache; @@ -95,9 +93,7 @@ public class CeleritasWorldRenderer extends SimpleWorldRenderer frameTEs = new ObjectArrayList<>(); private final ObjectArrayList frameOverride = new ObjectArrayList<>(); - // For sorting transparent TESRs - private final TileEntityOrderer tileEntityOrderer = new TileEntityOrderer(); - private final ArrayList sortedTileEntities = new ArrayList<>(); + private final TileEntityDepthOrder depthOrder = new TileEntityDepthOrder(); private CeleritasWorldRenderer(Minecraft mc) { // Private constructor for singleton @@ -172,7 +168,6 @@ public class CeleritasWorldRenderer extends SimpleWorldRenderer 1 && ClientProxy.options().performance.translucencySorting) { - sortedTileEntities.sort(tileEntityOrderer.setLastCameraState(lastCameraState)); - } - for (int i = 0; i < sortedTileEntities.size(); i++) { - dispatchTE(sortedTileEntities.get(i), partialTicks); - } - count = sortedTileEntities.size(); } finally { if (Tracy.ENABLED) Tracy.endZone(); } @@ -673,27 +664,4 @@ public class CeleritasWorldRenderer extends SimpleWorldRenderer { - public CameraState lastCameraState; - - public TileEntityOrderer() { - super(); - } - - public TileEntityOrderer setLastCameraState(CameraState lastCameraState) { - this.lastCameraState = lastCameraState; - return this; - } - - @Override - public int compare(TileEntity te1, TileEntity te2) { - final double x = this.lastCameraState.x(); - final double y = this.lastCameraState.y(); - final double z = this.lastCameraState.z(); - final double d1 = te1.getDistanceFrom(x, y, z); - final double d2 = te2.getDistanceFrom(x, y, z); - return Double.compare(d2, d1); - } - } } diff --git a/src/main/java/com/gtnewhorizons/angelica/rendering/celeritas/TileEntityDepthOrder.java b/src/main/java/com/gtnewhorizons/angelica/rendering/celeritas/TileEntityDepthOrder.java new file mode 100644 index 000000000..1c3406fa0 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/rendering/celeritas/TileEntityDepthOrder.java @@ -0,0 +1,79 @@ +package com.gtnewhorizons.angelica.rendering.celeritas; + +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.minecraft.tileentity.TileEntity; + +import java.util.Arrays; + +final class TileEntityDepthOrder { + + private static final int RADIX_BITS = 8; + private static final int BUCKETS = 1 << RADIX_BITS; + + private final int[] counts = new int[BUCKETS]; + private int[] keys = new int[0]; + private int[] keysScratch = new int[0]; + private int[] order = new int[0]; + private int[] orderScratch = new int[0]; + private TileEntity[] entities = new TileEntity[0]; + + void sortBackToFront(ObjectArrayList list, double camX, double camY, double camZ) { + final int n = list.size(); + if (n < 2) return; + final Object[] source = list.elements(); + if (keys.length < n) { + final int capacity = source.length; + keys = new int[capacity]; + keysScratch = new int[capacity]; + order = new int[capacity]; + orderScratch = new int[capacity]; + entities = new TileEntity[capacity]; + } + for (int i = 0; i < n; i++) { + final TileEntity te = (TileEntity) source[i]; + final double dx = te.xCoord + 0.5 - camX; + final double dy = te.yCoord + 0.5 - camY; + final double dz = te.zCoord + 0.5 - camZ; + keys[i] = Integer.MAX_VALUE - Float.floatToRawIntBits((float) (dx * dx + dy * dy + dz * dz)); + order[i] = i; + entities[i] = te; + } + final int[] sorted = sortOrder(n); + for (int i = 0; i < n; i++) { + source[i] = entities[sorted[i]]; + entities[sorted[i]] = null; + } + } + + private int[] sortOrder(int n) { + int[] keyIn = keys, keyOut = keysScratch; + int[] idxIn = order, idxOut = orderScratch; + for (int shift = 0; shift < Integer.SIZE; shift += RADIX_BITS) { + Arrays.fill(counts, 0); + for (int i = 0; i < n; i++) counts[(keyIn[i] >>> shift) & (BUCKETS - 1)]++; + if (counts[(keyIn[0] >>> shift) & (BUCKETS - 1)] == n) continue; + int sum = 0; + for (int b = 0; b < BUCKETS; b++) { + final int c = counts[b]; + counts[b] = sum; + sum += c; + } + for (int i = 0; i < n; i++) { + final int dst = counts[(keyIn[i] >>> shift) & (BUCKETS - 1)]++; + keyOut[dst] = keyIn[i]; + idxOut[dst] = idxIn[i]; + } + final int[] k = keyIn; + keyIn = keyOut; + keyOut = k; + final int[] x = idxIn; + idxIn = idxOut; + idxOut = x; + } + keys = keyIn; + keysScratch = keyOut; + order = idxIn; + orderScratch = idxOut; + return idxIn; + } +} diff --git a/src/test/java/com/gtnewhorizons/angelica/rendering/celeritas/TileEntityDepthOrderTest.java b/src/test/java/com/gtnewhorizons/angelica/rendering/celeritas/TileEntityDepthOrderTest.java new file mode 100644 index 000000000..e723c4677 --- /dev/null +++ b/src/test/java/com/gtnewhorizons/angelica/rendering/celeritas/TileEntityDepthOrderTest.java @@ -0,0 +1,31 @@ +package com.gtnewhorizons.angelica.rendering.celeritas; + +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.minecraft.tileentity.TileEntity; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class TileEntityDepthOrderTest { + + private static TileEntity at(int x, int y, int z) { + final TileEntity te = new TileEntity(); + te.xCoord = x; + te.yCoord = y; + te.zCoord = z; + return te; + } + + @Test + void sortsFarthestFirstAndKeepsTiesInListOrder() { + final TileEntity near = at(0, 0, 2); + final TileEntity far = at(0, 0, 181); + final TileEntity mid = at(0, 0, 5); + final TileEntity midOpposite = at(0, 0, -5); + final ObjectArrayList list = new ObjectArrayList<>(Arrays.asList(near, far, mid, midOpposite)); + new TileEntityDepthOrder().sortBackToFront(list, 0.5, 0.5, 0.5); + assertEquals(Arrays.asList(far, mid, midOpposite, near), list); + } +}