Sort block entities back to front before dispatch

This commit is contained in:
Ruling-0 committed 2026-11-08 12:15:29 -06:00
1 parent 3717d2d46e
commit 30f0835a21
3 files changed
+116 -38

No files matched your search

@@ -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<WorldClient, Ang
private final ObjectArrayList<TileEntity> frameTEs = new ObjectArrayList<>();
private final ObjectArrayList<TileEntity> frameOverride = new ObjectArrayList<>();
// For sorting transparent TESRs
private final TileEntityOrderer tileEntityOrderer = new TileEntityOrderer();
private final ArrayList<TileEntity> 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<WorldClient, Ang
DynamicLights.setActiveRenderer(null);
this.frameTEs.clear();
this.frameOverride.clear();
this.sortedTileEntities.clear();
ShadowRenderer.visibleTileEntities.clear();
ShadowRenderer.globalTileEntities.clear();
TesrLifecycle.reset();
@@ -442,6 +437,9 @@ public class CeleritasWorldRenderer extends SimpleWorldRenderer<WorldClient, Ang
this.teTransform = null;
if (Tracy.ENABLED) Tracy.beginZone(Z_TESR_DISPATCH);
try {
if (ClientProxy.options().performance.translucencySorting) {
depthOrder.sortBackToFront(frameTEs, teCamX, teCamY, teCamZ);
}
for (int i = 0; i < frameTEs.size(); i++) {
final TileEntity te = frameTEs.get(i);
if (!(te instanceof OverridesShouldRenderInPass)) {
@@ -461,20 +459,13 @@ public class CeleritasWorldRenderer extends SimpleWorldRenderer<WorldClient, Ang
} else {
if (Tracy.ENABLED) Tracy.beginZone(Z_TESR_DISPATCH);
try {
sortedTileEntities.clear();
for (int i = 0; i < frameOverride.size(); i++) {
final TileEntity te = frameOverride.get(i);
if (te.shouldRenderInPass(pass)) {
sortedTileEntities.add(te);
dispatchTE(te, partialTicks);
count++;
}
}
if (sortedTileEntities.size() > 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<WorldClient, Ang
return this;
}
}
private static class TileEntityOrderer implements Comparator<TileEntity> {
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);
}
}
}
@@ -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<TileEntity> 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;
}
}
@@ -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<TileEntity> 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);
}
}