Reduce memory allocation slightly during LOD loading

This commit is contained in:
James Seibel
2026-02-10 07:32:13 -06:00
parent 4d3242a370
commit 457bbebbdd
7 changed files with 228 additions and 123 deletions
@@ -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;
}
}
}
}
@@ -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)
{
@@ -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)
{
@@ -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<ColumnRenderView> POOL = new ConcurrentLinkedQueue<>();
public LongArrayList data;
/**
* How many data points are currently being represented by this view. <br>
* 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. <Br>
* 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. <br>
* {@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
@@ -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<IBlockStateWrapper> blockStatesToIgnore = WRAPPER_FACTORY.getRendererIgnoredBlocks(levelWrapper);
HashSet<IBlockStateWrapper> caveBlockStatesToIgnore = WRAPPER_FACTORY.getRendererIgnoredCaveBlocks(levelWrapper);
ObjectOpenHashSet<IBlockStateWrapper> blockStatesToIgnore = WRAPPER_FACTORY.getRendererIgnoredBlocks(levelWrapper);
ObjectOpenHashSet<IBlockStateWrapper> caveBlockStatesToIgnore = WRAPPER_FACTORY.getRendererIgnoredCaveBlocks(levelWrapper);
// build snow block cache if needed
if (snowLayerBlockStates == null)
@@ -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}. <Br>
* 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.
@@ -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. <br>
* Generally this contains blocks like: air, barriers, light blocks, etc.
*/
HashSet<IBlockStateWrapper> getRendererIgnoredBlocks(ILevelWrapper levelWrapper);
ObjectOpenHashSet<IBlockStateWrapper> getRendererIgnoredBlocks(ILevelWrapper levelWrapper);
/**
* Returns the set of {@link IBlockStateWrapper}'s that shouldn't be rendered in caves. <br>
* Generally this contains blocks like: air, rails, glow lichen, etc.
*/
HashSet<IBlockStateWrapper> getRendererIgnoredCaveBlocks(ILevelWrapper levelWrapper);
ObjectOpenHashSet<IBlockStateWrapper> getRendererIgnoredCaveBlocks(ILevelWrapper levelWrapper);
/** clears the cached values */
void resetRendererIgnoredCaveBlocks();