mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-27 14:30:14 +00:00
Batched river lookups
- Post processing samples each river-weight coordinate once per chunk - River exclusions preserve positive-weight and cardinal-neighbor rules - Tests cover boundaries, nonfinite weights, wall patches and slabs
This commit is contained in:
1 parent
12591820e8
commit
6e77755279
4 files changed
+100
-31
No files matched your search
@@ -54,43 +54,44 @@ public class IrisPostModifier extends EngineAssignedModifier<NativeBlockState> {
|
|||||||
int depth = output.getDepth();
|
int depth = output.getDepth();
|
||||||
int planeWidth = width + 2;
|
int planeWidth = width + 2;
|
||||||
int[] heights = heightPlane(x, z, width, depth, planeWidth);
|
int[] heights = heightPlane(x, z, width, depth, planeWidth);
|
||||||
|
boolean[] rivers = riverPlane(getComplex().getRiverCarveWeightStream(), x, z, width, depth);
|
||||||
IrisDimension dimension = getDimension();
|
IrisDimension dimension = getDimension();
|
||||||
boolean walls = dimension.isPostProcessingWalls();
|
boolean walls = dimension.isPostProcessingWalls();
|
||||||
boolean slabs = dimension.isPostProcessingSlabs();
|
boolean slabs = dimension.isPostProcessingSlabs();
|
||||||
for (int i = 0; i < width; i++) {
|
for (int i = 0; i < width; i++) {
|
||||||
for (int j = 0; j < depth; j++) {
|
for (int j = 0; j < depth; j++) {
|
||||||
post(i, j, sync, i + x, j + z, context, heights, planeWidth, walls, slabs);
|
post(i, j, sync, i + x, j + z, context, heights, rivers, planeWidth, walls, slabs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getEngine().getMetrics().getPost().put(p.getMilliseconds());
|
getEngine().getMetrics().getPost().put(p.getMilliseconds());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static boolean[] riverPlane(ProceduralStream<Double> carveWeights, int x, int z, int width, int depth) {
|
||||||
|
int planeWidth = width + 2;
|
||||||
|
boolean[] rivers = new boolean[planeWidth * (depth + 2)];
|
||||||
|
for (int j = -1; j <= depth; j++) {
|
||||||
|
boolean edge = j == -1 || j == depth;
|
||||||
|
int from = edge ? 0 : -1;
|
||||||
|
int to = edge ? width - 1 : width;
|
||||||
|
int row = (j + 1) * planeWidth;
|
||||||
|
for (int i = from; i <= to; i++) {
|
||||||
|
rivers[row + i + 1] = carveWeights.get(x + i, z + j) > 0D;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rivers;
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean skipsHydrologyColumn(boolean[] rivers, int center, int planeWidth) {
|
||||||
|
return rivers[center] || rivers[center + 1] || rivers[center - 1]
|
||||||
|
|| rivers[center + planeWidth] || rivers[center - planeWidth];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Every column reads its own height plus its four neighbours, so adjacent columns would otherwise
|
* Every column reads its own height plus its four neighbours, so adjacent columns would otherwise
|
||||||
* resolve the same height stream entry up to five times. Resolve the padded plane once instead. The
|
* resolve the same height stream entry up to five times. Resolve the padded plane once instead. The
|
||||||
* four diagonal corners are never read, so they are left unresolved.
|
* four diagonal corners are never read, so they are left unresolved.
|
||||||
*/
|
*/
|
||||||
private boolean riverColumn(int x, int z) {
|
|
||||||
ProceduralStream<Double> carveWeights = getComplex().getRiverCarveWeightStream();
|
|
||||||
return skipsHydrologyColumn(new double[] {
|
|
||||||
carveWeights.get(x, z),
|
|
||||||
carveWeights.get(x + 1, z),
|
|
||||||
carveWeights.get(x - 1, z),
|
|
||||||
carveWeights.get(x, z + 1),
|
|
||||||
carveWeights.get(x, z - 1)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static boolean skipsHydrologyColumn(double[] carveWeights) {
|
|
||||||
for (double weight : carveWeights) {
|
|
||||||
if (weight > 0D) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int[] heightPlane(int x, int z, int width, int depth, int planeWidth) {
|
private int[] heightPlane(int x, int z, int width, int depth, int planeWidth) {
|
||||||
int[] heights = new int[planeWidth * (depth + 2)];
|
int[] heights = new int[planeWidth * (depth + 2)];
|
||||||
EngineMantle mantle = getEngine().getMantle();
|
EngineMantle mantle = getEngine().getMantle();
|
||||||
@@ -109,7 +110,7 @@ public class IrisPostModifier extends EngineAssignedModifier<NativeBlockState> {
|
|||||||
return heights;
|
return heights;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void post(int currentPostX, int currentPostZ, Hunk<NativeBlockState> currentData, int x, int z, ChunkContext context, int[] heights, int planeWidth, boolean walls, boolean slabs) {
|
private void post(int currentPostX, int currentPostZ, Hunk<NativeBlockState> currentData, int x, int z, ChunkContext context, int[] heights, boolean[] rivers, int planeWidth, boolean walls, boolean slabs) {
|
||||||
// x/z are world coordinates, the hunk is indexed relative to this chunk origin.
|
// x/z are world coordinates, the hunk is indexed relative to this chunk origin.
|
||||||
int originX = x - currentPostX;
|
int originX = x - currentPostX;
|
||||||
int originZ = z - currentPostZ;
|
int originZ = z - currentPostZ;
|
||||||
@@ -120,7 +121,7 @@ public class IrisPostModifier extends EngineAssignedModifier<NativeBlockState> {
|
|||||||
int hc = heights[center - 1];
|
int hc = heights[center - 1];
|
||||||
int hd = heights[center - planeWidth];
|
int hd = heights[center - planeWidth];
|
||||||
int fluidHeight = (int) Math.round(getComplex().getRiverWaterSurfaceStream().get(x, z));
|
int fluidHeight = (int) Math.round(getComplex().getRiverWaterSurfaceStream().get(x, z));
|
||||||
boolean river = riverColumn(x, z);
|
boolean river = skipsHydrologyColumn(rivers, center, planeWidth);
|
||||||
|
|
||||||
// Floating Nibs
|
// Floating Nibs
|
||||||
int g = 0;
|
int g = 0;
|
||||||
|
|||||||
+71
-4
@@ -1,20 +1,87 @@
|
|||||||
package art.arcane.iris.generation.stage;
|
package art.arcane.iris.generation.stage;
|
||||||
|
|
||||||
|
import art.arcane.volmlib.util.stream.ProceduralStream;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
public class IrisPostModifierHydrologyTest {
|
public class IrisPostModifierHydrologyTest {
|
||||||
@Test
|
@Test
|
||||||
public void columnsTouchingARiverFootprintSkipThePostPasses() {
|
public void columnsTouchingARiverFootprintSkipThePostPasses() {
|
||||||
assertTrue(IrisPostModifier.skipsHydrologyColumn(new double[] {1D, 0D, 0D, 0D, 0D}));
|
for (int index : new int[] {4, 3, 5, 1, 7}) {
|
||||||
assertTrue(IrisPostModifier.skipsHydrologyColumn(new double[] {0D, 0D, 0.5D, 0D, 0D}));
|
boolean[] rivers = new boolean[9];
|
||||||
assertTrue(IrisPostModifier.skipsHydrologyColumn(new double[] {0D, 0D, 0D, 0D, 0.75D}));
|
rivers[index] = true;
|
||||||
|
assertTrue(IrisPostModifier.skipsHydrologyColumn(rivers, 4, 3));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void columnsAwayFromRiversKeepThePostPasses() {
|
public void columnsAwayFromRiversKeepThePostPasses() {
|
||||||
assertFalse(IrisPostModifier.skipsHydrologyColumn(new double[] {0D, 0D, 0D, 0D, 0D}));
|
boolean[] rivers = new boolean[9];
|
||||||
|
rivers[0] = true;
|
||||||
|
rivers[2] = true;
|
||||||
|
rivers[6] = true;
|
||||||
|
rivers[8] = true;
|
||||||
|
assertFalse(IrisPostModifier.skipsHydrologyColumn(rivers, 4, 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void paddedPlaneSamplesEachRequiredCoordinateOnce() {
|
||||||
|
Map<Long, Integer> samples = new HashMap<>();
|
||||||
|
ProceduralStream<Double> stream = ProceduralStream.ofDouble((x, z) -> {
|
||||||
|
long key = ((long) (int) x << 32) | ((int) z & 0xffffffffL);
|
||||||
|
samples.merge(key, 1, Integer::sum);
|
||||||
|
return weight((int) x, (int) z);
|
||||||
|
});
|
||||||
|
boolean[] rivers = IrisPostModifier.riverPlane(stream, -32, 48, 16, 16);
|
||||||
|
assertEquals(320, samples.size());
|
||||||
|
for (int count : samples.values()) {
|
||||||
|
assertEquals(1, count);
|
||||||
|
}
|
||||||
|
assertPlaneMatchesPointSampling(rivers, -32, 48, 16, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void rectangularPlanesPreservePositiveWeightRules() {
|
||||||
|
ProceduralStream<Double> stream = ProceduralStream.ofDouble((x, z) -> weight((int) x, (int) z));
|
||||||
|
for (int width : new int[] {1, 3, 16}) {
|
||||||
|
for (int depth : new int[] {1, 5, 16}) {
|
||||||
|
boolean[] rivers = IrisPostModifier.riverPlane(stream, -19, -37, width, depth);
|
||||||
|
assertPlaneMatchesPointSampling(rivers, -19, -37, width, depth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertPlaneMatchesPointSampling(boolean[] rivers, int x, int z, int width, int depth) {
|
||||||
|
int planeWidth = width + 2;
|
||||||
|
for (int localX = 0; localX < width; localX++) {
|
||||||
|
for (int localZ = 0; localZ < depth; localZ++) {
|
||||||
|
int worldX = x + localX;
|
||||||
|
int worldZ = z + localZ;
|
||||||
|
boolean expected = weight(worldX, worldZ) > 0D || weight(worldX + 1, worldZ) > 0D
|
||||||
|
|| weight(worldX - 1, worldZ) > 0D || weight(worldX, worldZ + 1) > 0D
|
||||||
|
|| weight(worldX, worldZ - 1) > 0D;
|
||||||
|
assertEquals(expected, IrisPostModifier.skipsHydrologyColumn(rivers,
|
||||||
|
(localZ + 1) * planeWidth + localX + 1, planeWidth));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double weight(int x, int z) {
|
||||||
|
return switch (Math.floorMod(x * 31 + z * 17, 8)) {
|
||||||
|
case 0 -> Double.NaN;
|
||||||
|
case 1 -> -1D;
|
||||||
|
case 2 -> 0D;
|
||||||
|
case 3 -> -0D;
|
||||||
|
case 4 -> Double.MIN_VALUE;
|
||||||
|
case 5 -> 1D;
|
||||||
|
case 6 -> Double.POSITIVE_INFINITY;
|
||||||
|
default -> Double.NEGATIVE_INFINITY;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+2
-2
@@ -91,9 +91,9 @@ public class IrisPostModifierSlabSupportTest {
|
|||||||
heights[2 * PLANE_WIDTH + 3] = SURFACE + 1;
|
heights[2 * PLANE_WIDTH + 3] = SURFACE + 1;
|
||||||
|
|
||||||
Method post = IrisPostModifier.class.getDeclaredMethod("post", int.class, int.class, Hunk.class,
|
Method post = IrisPostModifier.class.getDeclaredMethod("post", int.class, int.class, Hunk.class,
|
||||||
int.class, int.class, ChunkContext.class, int[].class, int.class, boolean.class, boolean.class);
|
int.class, int.class, ChunkContext.class, int[].class, boolean[].class, int.class, boolean.class, boolean.class);
|
||||||
post.setAccessible(true);
|
post.setAccessible(true);
|
||||||
post.invoke(modifier, 1, 1, output, 1, 1, context, heights, PLANE_WIDTH, false, true);
|
post.invoke(modifier, 1, 1, output, 1, 1, context, heights, new boolean[heights.length], PLANE_WIDTH, false, true);
|
||||||
return output.get(1, SURFACE + 1, 1);
|
return output.get(1, SURFACE + 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-2
@@ -123,9 +123,10 @@ public class IrisPostModifierWallShoreTest {
|
|||||||
heights[5] = SURFACE - 4;
|
heights[5] = SURFACE - 4;
|
||||||
|
|
||||||
Method post = IrisPostModifier.class.getDeclaredMethod("post", int.class, int.class, Hunk.class,
|
Method post = IrisPostModifier.class.getDeclaredMethod("post", int.class, int.class, Hunk.class,
|
||||||
int.class, int.class, ChunkContext.class, int[].class, int.class, boolean.class, boolean.class);
|
int.class, int.class, ChunkContext.class, int[].class, boolean[].class, int.class, boolean.class, boolean.class);
|
||||||
post.setAccessible(true);
|
post.setAccessible(true);
|
||||||
post.invoke(modifier, 0, 0, data, 0, 0, context, heights, PLANE_WIDTH, walls, false);
|
boolean[] rivers = IrisPostModifier.riverPlane(carveWeights, 0, 0, PLANE_WIDTH - 2, PLANE_WIDTH - 2);
|
||||||
|
post.invoke(modifier, 0, 0, data, 0, 0, context, heights, rivers, PLANE_WIDTH, walls, false);
|
||||||
return data.get(0, SURFACE, 0);
|
return data.get(0, SURFACE, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user