diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/ColumnRenderSource.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/ColumnRenderSource.java index d49db1793..d7bc9596c 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/ColumnRenderSource.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/ColumnRenderSource.java @@ -24,7 +24,7 @@ import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.util.objects.pooling.AbstractPhantomArrayList; import com.seibel.distanthorizons.core.util.objects.pooling.PhantomArrayListPool; import com.seibel.distanthorizons.core.pos.DhSectionPos; -import com.seibel.distanthorizons.core.dataObjects.render.columnViews.ColumnArrayView; +import com.seibel.distanthorizons.core.dataObjects.render.columnViews.ColumnRenderView; import com.seibel.distanthorizons.core.util.RenderDataPointUtil; import it.unimi.dsi.fastutil.longs.LongArrayList; import com.seibel.distanthorizons.core.logging.DhLogger; @@ -95,23 +95,24 @@ public class ColumnRenderSource extends AbstractPhantomArrayList public long getDataPoint(int posX, int posZ, int verticalIndex) { return this.renderDataContainer.getLong(posX * WIDTH * this.maxVerticalSliceCount + posZ * this.maxVerticalSliceCount + verticalIndex); } - public ColumnArrayView getVerticalDataPointView(int posX, int posZ) + public void populateColumnView(ColumnRenderView view, int posX, int posZ) throws IllegalArgumentException { int offset = posX * WIDTH * this.maxVerticalSliceCount + posZ * this.maxVerticalSliceCount; // don't allow returning views that are outside this render source's bounds if (offset >= this.renderDataContainer.size()) { - return null; + throw new IllegalArgumentException("Column View offset ["+offset+"] greater than parent render data container ["+DhSectionPos.toString(this.pos)+"] size ["+this.renderDataContainer.size()+"]."); } else if (posX < 0 || posX >= WIDTH || posZ < 0 || posZ >= WIDTH) { - return null; + throw new IllegalArgumentException("Column View pos outside valid range ["+posX+","+posZ+"]."); } - return new ColumnArrayView(this.renderDataContainer, this.maxVerticalSliceCount, - offset, this.maxVerticalSliceCount); + view.populate( + this.renderDataContainer, this.maxVerticalSliceCount, + offset, this.maxVerticalSliceCount); } //endregion @@ -139,18 +140,20 @@ public class ColumnRenderSource extends AbstractPhantomArrayList return false; } - - for (int x = 0; x < WIDTH; x++) + try (ColumnRenderView columnView = ColumnRenderView.getPooled()) { - for (int z = 0; z < WIDTH; z++) + for (int x = 0; x < WIDTH; x++) { - ColumnArrayView columnArrayView = this.getVerticalDataPointView(x,z); - for (int i = 0; i < columnArrayView.size; i++) + for (int z = 0; z < WIDTH; z++) { - long dataPoint = columnArrayView.get(i); - if (!RenderDataPointUtil.hasZeroHeight(dataPoint)) + this.populateColumnView(columnView, x, z); + for (int i = 0; i < columnView.size; i++) { - return true; + long dataPoint = columnView.get(i); + if (!RenderDataPointUtil.hasZeroHeight(dataPoint)) + { + return true; + } } } } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnBox.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnBox.java index e12f0be98..726880feb 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnBox.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnBox.java @@ -27,7 +27,7 @@ import com.seibel.distanthorizons.core.util.objects.pooling.PhantomArrayListChec import com.seibel.distanthorizons.core.util.ColorUtil; import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.util.RenderDataPointUtil; -import com.seibel.distanthorizons.core.dataObjects.render.columnViews.ColumnArrayView; +import com.seibel.distanthorizons.core.dataObjects.render.columnViews.ColumnRenderView; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper; import com.seibel.distanthorizons.coreapi.util.MathUtil; import it.unimi.dsi.fastutil.longs.LongArrayList; @@ -54,7 +54,7 @@ public class ColumnBox short width, short yHeight, short minX, short minY, short minZ, int color, byte irisBlockMaterialId, byte skyLight, byte blockLight, - long topData, long bottomData, ColumnArrayView[] adjData, boolean[] isAdjDataSameDetailLevel) + long topData, long bottomData, ColumnRenderView[] adjData, boolean[] isAdjDataSameDetailLevel) { //================// // variable setup // @@ -145,7 +145,7 @@ public class ColumnBox // NORTH face { - ColumnArrayView adjCol = adjData[EDhDirection.NORTH.compassIndex]; + ColumnRenderView adjCol = adjData[EDhDirection.NORTH.compassIndex]; boolean adjSameDetailLevel = isAdjDataSameDetailLevel[EDhDirection.NORTH.compassIndex]; // if the adjacent column is null that generally means the adjacent area hasn't been generated yet if (adjCol == null) @@ -172,7 +172,7 @@ public class ColumnBox // SOUTH face { - ColumnArrayView adjCol = adjData[EDhDirection.SOUTH.compassIndex]; + ColumnRenderView adjCol = adjData[EDhDirection.SOUTH.compassIndex]; boolean adjSameDetailLevel = isAdjDataSameDetailLevel[EDhDirection.SOUTH.compassIndex]; if (adjCol == null) { @@ -197,7 +197,7 @@ public class ColumnBox // WEST face { - ColumnArrayView adjCol = adjData[EDhDirection.WEST.compassIndex]; + ColumnRenderView adjCol = adjData[EDhDirection.WEST.compassIndex]; boolean adjSameDetailLevel = isAdjDataSameDetailLevel[EDhDirection.WEST.compassIndex]; if (adjCol == null) { @@ -222,7 +222,7 @@ public class ColumnBox // EAST face { - ColumnArrayView adjCol = adjData[EDhDirection.EAST.compassIndex]; + ColumnRenderView adjCol = adjData[EDhDirection.EAST.compassIndex]; boolean adjSameDetailLevel = isAdjDataSameDetailLevel[EDhDirection.EAST.compassIndex]; if (adjCol == null) { @@ -248,7 +248,7 @@ public class ColumnBox private static void makeAdjVerticalQuad( LodQuadBuilder builder, PhantomArrayListCheckout phantomArrayCheckout, - @NotNull ColumnArrayView adjColumnView, boolean adjacentIsSameDetailLevel, int caveCullingMaxY, EDhDirection direction, + @NotNull ColumnRenderView adjColumnView, boolean adjacentIsSameDetailLevel, int caveCullingMaxY, EDhDirection direction, short x, short yMin, short z, short horizontalWidth, short ySize, int color, byte irisBlockMaterialId, byte blockLight) { diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnRenderBufferBuilder.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnRenderBufferBuilder.java index 62bed98bb..c762b4c45 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnRenderBufferBuilder.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnRenderBufferBuilder.java @@ -34,7 +34,7 @@ import com.seibel.distanthorizons.core.pos.DhSectionPos; import com.seibel.distanthorizons.core.util.ColorUtil; import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.util.RenderDataPointUtil; -import com.seibel.distanthorizons.core.dataObjects.render.columnViews.ColumnArrayView; +import com.seibel.distanthorizons.core.dataObjects.render.columnViews.ColumnRenderView; import java.util.concurrent.CompletableFuture; @@ -107,17 +107,29 @@ public class ColumnRenderBufferBuilder //===================// // pooled arrays for ColumnBox use - try (PhantomArrayListCheckout phantomArrayCheckout = ARRAY_LIST_POOL.checkoutLongArrays(2)) + try (PhantomArrayListCheckout phantomArrayCheckout = ARRAY_LIST_POOL.checkoutLongArrays(2); + ColumnRenderView columnRenderData = ColumnRenderView.getPooled(); + ColumnRenderView northAdjView = ColumnRenderView.getPooled(); + ColumnRenderView southAdjView = ColumnRenderView.getPooled(); + ColumnRenderView eastAdjView = ColumnRenderView.getPooled(); + ColumnRenderView westAdjView = ColumnRenderView.getPooled()) { + ColumnRenderView[] adjColumnViews = new ColumnRenderView[EDhDirection.CARDINAL_COMPASS.length]; + adjColumnViews[EDhDirection.NORTH.compassIndex] = northAdjView; + adjColumnViews[EDhDirection.SOUTH.compassIndex] = southAdjView; + adjColumnViews[EDhDirection.EAST.compassIndex] = eastAdjView; + adjColumnViews[EDhDirection.WEST.compassIndex] = westAdjView; + + byte thisDetailLevel = renderSource.getDataDetailLevel(); for (int relX = 0; relX < ColumnRenderSource.WIDTH; relX++) { for (int relZ = 0; relZ < ColumnRenderSource.WIDTH; relZ++) { - // ignore empty/null columns - ColumnArrayView columnRenderData = renderSource.getVerticalDataPointView(relX, relZ); - if (columnRenderData == null - || columnRenderData.size == 0 + renderSource.populateColumnView(columnRenderData, relX, relZ); + + // ignore empty columns + if (columnRenderData.size == 0 || !RenderDataPointUtil.doesDataPointExist(columnRenderData.get(0)) || RenderDataPointUtil.hasZeroHeight(columnRenderData.get(0))) { @@ -125,7 +137,6 @@ public class ColumnRenderBufferBuilder } - //=============// // debug limit // //=============// @@ -152,7 +163,6 @@ public class ColumnRenderBufferBuilder // get adjacent render data columns // //==================================// - ColumnArrayView[] adjColumnViews = new ColumnArrayView[EDhDirection.CARDINAL_COMPASS.length]; for (EDhDirection direction : EDhDirection.CARDINAL_COMPASS) { try @@ -160,8 +170,8 @@ public class ColumnRenderBufferBuilder int xAdj = relX + direction.normal.x; int zAdj = relZ + direction.normal.z; boolean isCrossRenderSourceBoundary = - (xAdj < 0 || xAdj >= ColumnRenderSource.WIDTH) || - (zAdj < 0 || zAdj >= ColumnRenderSource.WIDTH); + (xAdj < 0 || xAdj >= ColumnRenderSource.WIDTH) + || (zAdj < 0 || zAdj >= ColumnRenderSource.WIDTH); ColumnRenderSource adjRenderSource; byte adjDetailLevel; @@ -230,7 +240,7 @@ public class ColumnRenderBufferBuilder LodUtil.assertNotReach("Mismatch between adjacent detail level ["+adjDetailLevel+"] and this render source's detail level ["+thisDetailLevel+"]. Detail levels should be adj >= this."); } - adjColumnViews[direction.compassIndex] = adjRenderSource.getVerticalDataPointView(xAdj, zAdj); + adjRenderSource.populateColumnView(adjColumnViews[direction.compassIndex], xAdj, zAdj); } catch (RuntimeException e) { @@ -251,7 +261,7 @@ public class ColumnRenderBufferBuilder { int wantedColumnIndex = Config.Client.Advanced.Debugging.ColumnBuilderDebugging.columnBuilderDebugColumnIndex.get(); if (wantedColumnIndex >= 0 - && i != wantedColumnIndex) + && i != wantedColumnIndex) { continue; } @@ -261,7 +271,7 @@ public class ColumnRenderBufferBuilder // If the data is not render-able (Void or non-existing) we stop since there is // no data left in this position if (RenderDataPointUtil.hasZeroHeight(data) - || !RenderDataPointUtil.doesDataPointExist(data)) + || !RenderDataPointUtil.doesDataPointExist(data)) { break; } @@ -270,13 +280,12 @@ public class ColumnRenderBufferBuilder long bottomDataPoint = (i + 1) < columnRenderData.size ? columnRenderData.get(i + 1) : RenderDataPointUtil.EMPTY_DATA; addRenderDataPointToBuilder( - clientLevel, phantomArrayCheckout, - data, topDataPoint, bottomDataPoint, - adjColumnViews, isSameDetailLevel, - thisDetailLevel, relX, relZ, - quadBuilder); + clientLevel, phantomArrayCheckout, + data, topDataPoint, bottomDataPoint, + adjColumnViews, isSameDetailLevel, + thisDetailLevel, relX, relZ, + quadBuilder); } - }// for z }// for x }// phantom checkout @@ -286,7 +295,7 @@ public class ColumnRenderBufferBuilder private static void addRenderDataPointToBuilder( IDhClientLevel clientLevel, PhantomArrayListCheckout phantomArrayCheckout, long renderData, long topRenderData, long bottomRenderData, - ColumnArrayView[] adjColumnViews, boolean[] isSameDetailLevel, + ColumnRenderView[] adjColumnViews, boolean[] isSameDetailLevel, byte detailLevel, int renderSourceOffsetPosX, int renderSourceOffsetPosZ, LodQuadBuilder quadBuilder) { diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/columnViews/ColumnArrayView.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/columnViews/ColumnRenderView.java similarity index 60% rename from core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/columnViews/ColumnArrayView.java rename to core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/columnViews/ColumnRenderView.java index e16c74d81..749d410d5 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/columnViews/ColumnArrayView.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/columnViews/ColumnRenderView.java @@ -28,28 +28,37 @@ import it.unimi.dsi.fastutil.longs.LongArrayList; import java.util.Arrays; import java.util.ConcurrentModificationException; +import java.util.concurrent.ConcurrentLinkedQueue; -public final class ColumnArrayView +/** + * Maps to part of a {@link ColumnRenderSource} for easier handling. + * + * @see ColumnRenderSource + */ +public final class ColumnRenderView implements AutoCloseable { - public final LongArrayList data; + private static final ConcurrentLinkedQueue POOL = new ConcurrentLinkedQueue<>(); + + + public LongArrayList data; /** * How many data points are currently being represented by this view.
- * Will be equal to or less than {@link ColumnArrayView#maxVerticalSliceCount}. + * Will be equal to or less than {@link ColumnRenderView#maxVerticalSliceCount}. */ - public final int size; + public int size; /** * Vertical size in data points.
* Can be 0 if this column was created for an empty data source. * @see EDhApiVerticalQuality#calculateMaxNumberOfVerticalSlicesAtDetailLevel(byte) */ - public final int maxVerticalSliceCount; + public int maxVerticalSliceCount; /** - * Where the relative starting index is in the {@link ColumnArrayView#data} array + * Where the relative starting index is in the {@link ColumnRenderView#data} array * if this view is representing part of a {@link ColumnRenderSource}. */ - public final int offset; + public int offset; @@ -58,8 +67,38 @@ public final class ColumnArrayView //=============// //region - /** @throws IllegalArgumentException if the offset is greater than the data's size */ - public ColumnArrayView(LongArrayList data, int size, int offset, int maxVerticalSliceCount) throws IllegalArgumentException + private ColumnRenderView() { } + + /** + * returns an un-populated view.
+ * {@link ColumnRenderView#populate(LongArrayList, int, int, int)} must be called before the + * view can be used.s + */ + public static ColumnRenderView getPooled() { return getPooled(null, 0, 0, 0); } + public static ColumnRenderView getPooled(LongArrayList data, int size, int offset, int maxVerticalSliceCount) throws IllegalArgumentException + { + // try getting an existing pooled object first + ColumnRenderView view = POOL.poll(); + if (view == null) + { + // no pooled object + view = new ColumnRenderView(); + } + + // data will be null if the object will be populated at a later date + if (data != null) + { + view.populate(data, size, offset, maxVerticalSliceCount); + } + + return view; + } + + /** + * Mutates this object so the necessary data is visible. + * @throws IllegalArgumentException if the offset is greater than the data's size + */ + public void populate(LongArrayList data, int size, int offset, int maxVerticalSliceCount) throws IllegalArgumentException { this.data = data; this.size = size; @@ -97,16 +136,63 @@ public final class ColumnArrayView } public void set(int index, long value) { this.data.set(index + this.offset, value); } + public void fill(long value) { Arrays.fill(this.data.elements(), this.offset, this.offset + this.size, value); } + + //endregion + + + //=========// + // subview // + //=========// + //region + + /** should be called in a try-finally block for automatic cleanup */ + public ColumnRenderView subView(int dataIndexStart, int dataCount) + { + return ColumnRenderView.getPooled( + this.data, + dataCount * this.maxVerticalSliceCount, + this.offset + dataIndexStart * this.maxVerticalSliceCount, + this.maxVerticalSliceCount); + } + + /** can be used to determine sub-view starting indexes */ public int subViewCount() { return (this.maxVerticalSliceCount != 0) ? (this.size / this.maxVerticalSliceCount) : 0; } - public ColumnArrayView subView(int dataIndexStart, int dataCount) - { return new ColumnArrayView(this.data, dataCount * this.maxVerticalSliceCount, this.offset + dataIndexStart * this.maxVerticalSliceCount, this.maxVerticalSliceCount); } + //endregion - public void fill(long value) { Arrays.fill(this.data.elements(), this.offset, this.offset + this.size, value); } - public void copyFrom(ColumnArrayView source) { this.copyFrom(source, 0); } - public void copyFrom(ColumnArrayView source, int outputDataIndexOffset) + + //======================// + // change vertical size // + //======================// + //region + + public void changeVerticalSizeFrom(ColumnRenderView source, RenderDataPointReducingList reducingList) + { + if (this.subViewCount() != source.subViewCount()) + { + throw new IllegalArgumentException("Cannot copy and resize to views with different dataCounts"); + } + + if (this.maxVerticalSliceCount >= source.maxVerticalSliceCount) + { + this.copyFrom(source, 0); + } + else + { + for (int i = 0; i < this.subViewCount(); i++) + { + try(ColumnRenderView sourceSubView = source.subView(i, 1); + ColumnRenderView thisSubView = this.subView(i, 1)) + { + mergeMultiData(sourceSubView, reducingList, thisSubView); + } + } + } + } + private void copyFrom(ColumnRenderView source, int outputDataIndexOffset) { if (source.maxVerticalSliceCount > this.maxVerticalSliceCount) { @@ -121,9 +207,14 @@ public final class ColumnArrayView for (int i = 0; i < source.subViewCount(); i++) { int outputOffset = this.offset + (outputDataIndexOffset * this.maxVerticalSliceCount) + (i * this.maxVerticalSliceCount); - source.subView(i, 1).copyTo(this.data.elements(), outputOffset, source.maxVerticalSliceCount); - Arrays.fill(this.data.elements(), outputOffset + source.maxVerticalSliceCount, - outputOffset + this.maxVerticalSliceCount, 0); + try(ColumnRenderView subView = source.subView(i, 1)) + { + subView.copyTo(this.data.elements(), outputOffset, source.maxVerticalSliceCount); + Arrays.fill(this.data.elements(), + outputOffset + source.maxVerticalSliceCount, + outputOffset + this.maxVerticalSliceCount, + 0); + } } } else @@ -131,35 +222,14 @@ public final class ColumnArrayView source.copyTo(this.data.elements(), this.offset + outputDataIndexOffset * this.maxVerticalSliceCount, source.size); } } - - public void copyTo(long[] target, int offset, int size) { System.arraycopy(this.data.elements(), this.offset, target, offset, size); } - - public void changeVerticalSizeFrom(ColumnArrayView source) - { - if (this.subViewCount() != source.subViewCount()) - { - throw new IllegalArgumentException("Cannot copy and resize to views with different dataCounts"); - } - - if (this.maxVerticalSliceCount >= source.maxVerticalSliceCount) - { - this.copyFrom(source); - } - else - { - for (int i = 0; i < this.subViewCount(); i++) - { - mergeMultiData(source.subView(i, 1), this.subView(i, 1)); - } - } - } + private void copyTo(long[] target, int offset, int size) { System.arraycopy(this.data.elements(), this.offset, target, offset, size); } /** * This method merge column of multiple data together * * @param sourceData one or more columns of data * @param output one column of space for the result to be written to */ - private static void mergeMultiData(ColumnArrayView sourceData, ColumnArrayView output) + private static void mergeMultiData(ColumnRenderView sourceData, RenderDataPointReducingList reducingList, ColumnRenderView output) { int target = output.maxVerticalSliceCount; if (target <= 0) @@ -179,11 +249,9 @@ public final class ColumnArrayView } else { - try (RenderDataPointReducingList list = new RenderDataPointReducingList(sourceData)) - { - list.reduce(output.maxVerticalSliceCount); - list.copyTo(output); - } + reducingList.populate(sourceData); + reducingList.reduce(output.maxVerticalSliceCount); + reducingList.copyTo(output); } } @@ -218,6 +286,14 @@ public final class ColumnArrayView return sb.toString(); } + @Override + public void close() + { + // no validation is done to make sure this object is only added to the pool once + // please only use this object in a try-finally so the close is handled implicitly + POOL.add(this); + } + //endregion diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/transformers/FullDataToRenderDataTransformer.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/transformers/FullDataToRenderDataTransformer.java index 5ee8e87fc..5b33d3ff8 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/transformers/FullDataToRenderDataTransformer.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/transformers/FullDataToRenderDataTransformer.java @@ -24,13 +24,13 @@ import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.dataObjects.fullData.FullDataPointIdMap; import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2; import com.seibel.distanthorizons.core.dataObjects.render.ColumnRenderSource; -import com.seibel.distanthorizons.core.dataObjects.render.columnViews.ColumnArrayView; +import com.seibel.distanthorizons.core.dataObjects.render.columnViews.ColumnRenderView; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; +import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPosMutable; import com.seibel.distanthorizons.core.util.objects.pooling.PhantomArrayListCheckout; import com.seibel.distanthorizons.core.util.objects.pooling.PhantomArrayListPool; import com.seibel.distanthorizons.core.pos.DhSectionPos; -import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPosMutable; import com.seibel.distanthorizons.core.util.*; import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory; import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper; @@ -40,6 +40,7 @@ import com.seibel.distanthorizons.coreapi.util.BitShiftUtil; import it.unimi.dsi.fastutil.longs.LongArrayList; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import com.seibel.distanthorizons.core.logging.DhLogger; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import org.jetbrains.annotations.Nullable; import java.util.HashSet; @@ -122,30 +123,40 @@ public class FullDataToRenderDataTransformer int baseX = DhSectionPos.getMinCornerBlockX(pos); int baseZ = DhSectionPos.getMinCornerBlockZ(pos); - for (int x = 0; x < FullDataSourceV2.WIDTH; x++) + try(ColumnRenderView columnArrayView = ColumnRenderView.getPooled(); + PhantomArrayListCheckout phantomCheckout = ARRAY_LIST_POOL.checkoutLongArrays(1); + ColumnRenderView tempExpandingColumnView = ColumnRenderView.getPooled(); + RenderDataPointReducingList reducingList = new RenderDataPointReducingList()) { - for (int z = 0; z < FullDataSourceV2.WIDTH; z++) + for (int x = 0; x < FullDataSourceV2.WIDTH; x++) { - ColumnArrayView columnArrayView = columnSource.getVerticalDataPointView(x, z); - LongArrayList dataColumn = fullDataSource.getColumnAtRelPos(x, z); - - updateOrReplaceRenderDataViewColumnWithFullDataColumn( - levelWrapper, fullDataSource, - // bitshift is to account for LODs with a detail level greater than 0 so the block pos is correct - baseX + BitShiftUtil.pow(x,dataDetail), baseZ + BitShiftUtil.pow(z,dataDetail), - columnArrayView, dataColumn); + for (int z = 0; z < FullDataSourceV2.WIDTH; z++) + { + columnSource.populateColumnView(columnArrayView, x, z); + LongArrayList dataColumn = fullDataSource.getColumnAtRelPos(x, z); + + updateOrReplaceRenderDataViewColumnWithFullDataColumn( + levelWrapper, fullDataSource, + // bit shift is to account for LODs with a detail level greater than 0 so the block pos is correct + baseX + BitShiftUtil.pow(x, dataDetail), baseZ + BitShiftUtil.pow(z, dataDetail), + columnArrayView, dataColumn, + // pooled references so we don't need to re-allocate/get them 4000 times per render source + phantomCheckout, tempExpandingColumnView, reducingList); + } } } return columnSource; } - /** Updates the given {@link ColumnArrayView} to match the incoming Full data {@link LongArrayList} */ + /** Updates the given {@link ColumnRenderView} to match the incoming Full data {@link LongArrayList} */ public static void updateOrReplaceRenderDataViewColumnWithFullDataColumn( IClientLevelWrapper levelWrapper, FullDataSourceV2 fullDataSource, int blockX, int blockZ, - ColumnArrayView columnArrayView, - LongArrayList fullDataColumn) + ColumnRenderView columnArrayView, + LongArrayList fullDataColumn, + // pooled references + PhantomArrayListCheckout phantomCheckout, ColumnRenderView tempExpandingColumnView, RenderDataPointReducingList reducingList) { // we can't do anything if the full data is missing or empty if (fullDataColumn == null @@ -162,22 +173,19 @@ public class FullDataToRenderDataTransformer } else { - try(PhantomArrayListCheckout checkout = ARRAY_LIST_POOL.checkoutLongArrays(1)) - { - LongArrayList dataArrayList = checkout.getLongArray(0, fullDataLength); - - // expand the ColumnArrayView to fit the new larger max vertical size - ColumnArrayView newColumnArrayView = new ColumnArrayView(dataArrayList, fullDataLength, 0, fullDataLength); - setRenderColumnView(levelWrapper, fullDataSource, blockX, blockZ, newColumnArrayView, fullDataColumn); - - columnArrayView.changeVerticalSizeFrom(newColumnArrayView); - } + LongArrayList dataArrayList = phantomCheckout.getLongArray(0, fullDataLength); + + // expand the ColumnArrayView to fit the new larger max vertical size + tempExpandingColumnView.populate(dataArrayList, fullDataLength, 0, fullDataLength); + setRenderColumnView(levelWrapper, fullDataSource, blockX, blockZ, tempExpandingColumnView, fullDataColumn); + + columnArrayView.changeVerticalSizeFrom(tempExpandingColumnView, reducingList); } } private static void setRenderColumnView( IClientLevelWrapper levelWrapper, FullDataSourceV2 fullDataSource, int blockX, int blockZ, - ColumnArrayView renderColumnData, LongArrayList fullColumnData) + ColumnRenderView renderColumnData, LongArrayList fullColumnData) { //===============// // config values // @@ -186,8 +194,8 @@ public class FullDataToRenderDataTransformer boolean ignoreNonCollidingBlocks = (Config.Client.Advanced.Graphics.Quality.blocksToIgnore.get() == EDhApiBlocksToAvoid.NON_COLLIDING); boolean colorBelowWithAvoidedBlocks = Config.Client.Advanced.Graphics.Quality.tintWithAvoidedBlocks.get(); - HashSet blockStatesToIgnore = WRAPPER_FACTORY.getRendererIgnoredBlocks(levelWrapper); - HashSet caveBlockStatesToIgnore = WRAPPER_FACTORY.getRendererIgnoredCaveBlocks(levelWrapper); + ObjectOpenHashSet blockStatesToIgnore = WRAPPER_FACTORY.getRendererIgnoredBlocks(levelWrapper); + ObjectOpenHashSet caveBlockStatesToIgnore = WRAPPER_FACTORY.getRendererIgnoredCaveBlocks(levelWrapper); // build snow block cache if needed if (snowLayerBlockStates == null) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/RenderDataPointReducingList.java b/core/src/main/java/com/seibel/distanthorizons/core/util/RenderDataPointReducingList.java index c78f4f011..3bd332676 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/util/RenderDataPointReducingList.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/util/RenderDataPointReducingList.java @@ -20,7 +20,7 @@ package com.seibel.distanthorizons.core.util; import com.google.common.annotations.VisibleForTesting; -import com.seibel.distanthorizons.core.dataObjects.render.columnViews.ColumnArrayView; +import com.seibel.distanthorizons.core.dataObjects.render.columnViews.ColumnRenderView; import com.seibel.distanthorizons.core.util.objects.pooling.AbstractPhantomArrayList; import com.seibel.distanthorizons.core.util.objects.pooling.PhantomArrayListPool; import com.seibel.distanthorizons.core.util.LodUtil.AssertFailureException; @@ -103,7 +103,7 @@ public class RenderDataPointReducingList extends AbstractPhantomArrayList */ private short lowest, highest, smallest, biggest; private short sizeWithAir, sizeWithoutAir; - private final LongArrayList links, data; + private LongArrayList links, data; /** * a temporary array to be used for sorting nodes. * the array is first populated such that every index @@ -112,7 +112,7 @@ public class RenderDataPointReducingList extends AbstractPhantomArrayList * finally, the nodes are re-linked according * to the order of elements in this array. */ - private final ShortArrayList sortingArray; + private ShortArrayList sortingArray; @@ -120,10 +120,18 @@ public class RenderDataPointReducingList extends AbstractPhantomArrayList // constructor // //=============// - public RenderDataPointReducingList(ColumnArrayView view) + public RenderDataPointReducingList() { super(ARRAY_LIST_POOL, 0, 1, 2, 0); - + } + + /** + * Mutates this object so it can be used for the given {@link ColumnRenderView}.
+ * Note: this must be called before this list can be used and this + * object can only be used by one thread at a time. + */ + public void populate(ColumnRenderView view) + { int size = view.size; if (size == 0) { @@ -833,7 +841,7 @@ public class RenderDataPointReducingList extends AbstractPhantomArrayList * * @implNote this method does not allocate any objects. */ - public static long reduceToOne(ColumnArrayView view) + public static long reduceToOne(ColumnRenderView view) { int size = view.size; if (size <= 0) @@ -880,7 +888,7 @@ public class RenderDataPointReducingList extends AbstractPhantomArrayList /** transfers the contents of this list to the provided view, in order of highest to lowest. */ - public void copyTo(ColumnArrayView view) + public void copyTo(ColumnRenderView view) { // reminder: DH explodes horribly when I copy the nodes // from lowest to highest instead of highest to lowest. diff --git a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/IWrapperFactory.java b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/IWrapperFactory.java index 0dc34bec8..13da93aed 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/IWrapperFactory.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/IWrapperFactory.java @@ -27,6 +27,7 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.worldGeneration.IBatchGeneratorEnvironmentWrapper; import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IBindable; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import java.io.IOException; import java.util.HashSet; @@ -81,12 +82,12 @@ public interface IWrapperFactory extends IDhApiWrapperFactory, IBindable * Returns the set of {@link IBlockStateWrapper}'s that shouldn't be rendered.
* Generally this contains blocks like: air, barriers, light blocks, etc. */ - HashSet getRendererIgnoredBlocks(ILevelWrapper levelWrapper); + ObjectOpenHashSet getRendererIgnoredBlocks(ILevelWrapper levelWrapper); /** * Returns the set of {@link IBlockStateWrapper}'s that shouldn't be rendered in caves.
* Generally this contains blocks like: air, rails, glow lichen, etc. */ - HashSet getRendererIgnoredCaveBlocks(ILevelWrapper levelWrapper); + ObjectOpenHashSet getRendererIgnoredCaveBlocks(ILevelWrapper levelWrapper); /** clears the cached values */ void resetRendererIgnoredCaveBlocks();