From 2ee06c59f11f4cfa9a49ddd2cea30089b74ddd89 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Mon, 22 Jul 2024 17:34:04 -0500 Subject: [PATCH 01/22] Add configs for testing the ColumnRenderBufferBuilder --- .../distanthorizons/core/config/Config.java | 20 ++++++++++-- .../ColumnRenderBufferBuilder.java | 31 +++++++++++++------ 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java b/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java index a2c786984..22fb5ce05 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java @@ -1311,12 +1311,28 @@ public class Config .addListener(DebugColumnConfigEventHandler.INSTANCE) .build(); public static ConfigEntry columnBuilderDebugXPos = new ConfigEntry.Builder() - .set(0) + .set(-1) .setAppearance(EConfigEntryAppearance.ONLY_IN_GUI) .addListener(DebugColumnConfigEventHandler.INSTANCE) .build(); public static ConfigEntry columnBuilderDebugZPos = new ConfigEntry.Builder() - .set(0) + .set(-2) + .setAppearance(EConfigEntryAppearance.ONLY_IN_GUI) + .addListener(DebugColumnConfigEventHandler.INSTANCE) + .build(); + + public static ConfigEntry columnBuilderDebugXRow = new ConfigEntry.Builder() + .set(52) + .setAppearance(EConfigEntryAppearance.ONLY_IN_GUI) + .addListener(DebugColumnConfigEventHandler.INSTANCE) + .build(); + public static ConfigEntry columnBuilderDebugZRow = new ConfigEntry.Builder() + .set(14) + .setAppearance(EConfigEntryAppearance.ONLY_IN_GUI) + .addListener(DebugColumnConfigEventHandler.INSTANCE) + .build(); + public static ConfigEntry columnBuilderDebugColumnIndex = new ConfigEntry.Builder() + .set(-1) .setAppearance(EConfigEntryAppearance.ONLY_IN_GUI) .addListener(DebugColumnConfigEventHandler.INSTANCE) .build(); 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 64c1abd02..d6793a34c 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 @@ -167,14 +167,22 @@ public class ColumnRenderBufferBuilder { for (int z = 0; z < ColumnRenderSource.SECTION_SIZE; z++) { - // TODO make a config for this // can be uncommented to limit the buffer building to a specific // relative position in this section. // useful for debugging a single column's rendering -// if (x != 0 || (z != 0 && z != 1)) -// { -// continue; -// } + if (Config.Client.Advanced.Debugging.columnBuilderDebugEnable.get()) + { + int wantedX = Config.Client.Advanced.Debugging.columnBuilderDebugXRow.get(); + if (wantedX >= 0 && x != wantedX) + { + continue; + } + int wantedZ = Config.Client.Advanced.Debugging.columnBuilderDebugZRow.get(); + if (wantedZ >= 0 && z != wantedZ) + { + continue; + } + } UncheckedInterruptedException.throwIfInterrupted(); @@ -286,12 +294,15 @@ public class ColumnRenderBufferBuilder // We only stop when we find a block that is void or non-existing block for (int i = 0; i < columnRenderData.size(); i++) { - // TODO make a config for this // can be uncommented to limit which vertical LOD is generated -// if (i != 0) -// { -// continue; -// } + if (Config.Client.Advanced.Debugging.columnBuilderDebugEnable.get()) + { + int wantedColumnIndex = Config.Client.Advanced.Debugging.columnBuilderDebugColumnIndex.get(); + if (wantedColumnIndex >= 0 && i != wantedColumnIndex) + { + continue; + } + } long data = columnRenderData.get(i); // If the data is not render-able (Void or non-existing) we stop since there is From 448982fbaffc3d1d48d7c9c74067c1a5bbf307a6 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Mon, 22 Jul 2024 19:50:23 -0500 Subject: [PATCH 02/22] refactor FullDataToRenderDataTransformer --- .../render/ColumnRenderSource.java | 2 +- .../FullDataToRenderDataTransformer.java | 71 ++++++++++++------- 2 files changed, 45 insertions(+), 28 deletions(-) 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 a00fb750d..1bed16709 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 @@ -182,7 +182,7 @@ public class ColumnRenderSource implements IDataSource EDhApiWorldGenerationStep worldGenStep = inputFullDataSource.getWorldGenStepAtRelativePos(x, z); if (dataColumn != null && worldGenStep != EDhApiWorldGenerationStep.EMPTY) { - FullDataToRenderDataTransformer.updateRenderDataViewWithFullDataColumn( + FullDataToRenderDataTransformer.updateOrReplaceRenderDataViewColumnWithFullDataColumn( level, inputFullDataSource.mapping, minBlockPos.x + x, minBlockPos.z + z, 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 bbfa76a0b..e41cba5b1 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 @@ -20,7 +20,6 @@ package com.seibel.distanthorizons.core.dataObjects.transformers; import com.seibel.distanthorizons.api.enums.config.EDhApiBlocksToAvoid; -import com.seibel.distanthorizons.api.enums.rendering.EDhApiBlockMaterial; import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.dataObjects.fullData.FullDataPointIdMap; import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2; @@ -122,7 +121,7 @@ public class FullDataToRenderDataTransformer ColumnArrayView columnArrayView = columnSource.getVerticalDataPointView(x, z); LongArrayList dataColumn = fullDataSource.get(x, z); - updateRenderDataViewWithFullDataColumn(level, fullDataSource.mapping, baseX + x, baseZ + z, columnArrayView, dataColumn); + updateOrReplaceRenderDataViewColumnWithFullDataColumn(level, fullDataSource.mapping, baseX + x, baseZ + z, columnArrayView, dataColumn); } } @@ -132,34 +131,41 @@ public class FullDataToRenderDataTransformer } /** Updates the given {@link ColumnArrayView} to match the incoming Full data {@link LongArrayList} */ - public static void updateRenderDataViewWithFullDataColumn( + public static void updateOrReplaceRenderDataViewColumnWithFullDataColumn( IDhClientLevel level, FullDataPointIdMap fullDataMapping, int blockX, int blockZ, ColumnArrayView columnArrayView, LongArrayList fullDataColumn) { + // we can't do anything if the full data is missing or empty if (fullDataColumn == null || fullDataColumn.size() == 0) { return; } - int dataTotalLength = fullDataColumn.size(); - if (dataTotalLength > columnArrayView.verticalSize()) + int fullDataLength = fullDataColumn.size(); + if (fullDataLength <= columnArrayView.verticalSize()) { - ColumnArrayView totalColumnData = new ColumnArrayView(new LongArrayList(new long[dataTotalLength]), dataTotalLength, 0, dataTotalLength); - iterateAndConvert(level, fullDataMapping, blockX, blockZ, totalColumnData, fullDataColumn); - columnArrayView.changeVerticalSizeFrom(totalColumnData); + // Directly use the arrayView since it fits. + setRenderColumnView(level, fullDataMapping, blockX, blockZ, columnArrayView, fullDataColumn); } else { - iterateAndConvert(level, fullDataMapping, blockX, blockZ, columnArrayView, fullDataColumn); //Directly use the arrayView since it fits. + // expand the ColumnArrayView to fit the new larger max vertical size + ColumnArrayView newColumnArrayView = new ColumnArrayView(new LongArrayList(new long[fullDataLength]), fullDataLength, 0, fullDataLength); + setRenderColumnView(level, fullDataMapping, blockX, blockZ, newColumnArrayView, fullDataColumn); + columnArrayView.changeVerticalSizeFrom(newColumnArrayView); } } - private static void iterateAndConvert( + private static void setRenderColumnView( IDhClientLevel level, FullDataPointIdMap fullDataMapping, int blockX, int blockZ, ColumnArrayView renderColumnData, LongArrayList fullColumnData) { + //===============// + // config values // + //===============// + boolean ignoreNonCollidingBlocks = (Config.Client.Advanced.Graphics.Quality.blocksToIgnore.get() == EDhApiBlocksToAvoid.NON_COLLIDING); boolean colorBelowWithAvoidedBlocks = Config.Client.Advanced.Graphics.Quality.tintWithAvoidedBlocks.get(); @@ -176,30 +182,35 @@ public class FullDataToRenderDataTransformer && !level.getLevelWrapper().getDimensionType().isTheEnd() ); - boolean isVoid = true; + boolean isColumnVoid = true; int colorToApplyToNextBlock = -1; int lastColor = 0; - int lastBottom = -10000; + int lastBottom = -10_000; int skylightToApplyToNextBlock = -1; int blocklightToApplyToNextBlock = -1; int columnOffset = 0; - IBiomeWrapper biome = null; - IBlockStateWrapper block = null; + //===========================// + // iterate through full data // + //===========================// + // goes from the top down for (int i = 0; i < fullColumnData.size(); i++) { long fullData = fullColumnData.getLong(i); + int bottomY = FullDataPointUtil.getBottomY(fullData); int blockHeight = FullDataPointUtil.getHeight(fullData); int id = FullDataPointUtil.getId(fullData); int blockLight = FullDataPointUtil.getBlockLight(fullData); int skyLight = FullDataPointUtil.getSkyLight(fullData); + IBiomeWrapper biome; + IBlockStateWrapper block; try { biome = fullDataMapping.getBiomeWrapper(id); @@ -207,7 +218,6 @@ public class FullDataToRenderDataTransformer } catch (IndexOutOfBoundsException e) { - // FIXME sometimes the data map has a length of 0 if (!brokenPos.contains(fullDataMapping.getPos())) { brokenPos.add(fullDataMapping.getPos()); @@ -219,11 +229,12 @@ public class FullDataToRenderDataTransformer "Further errors for this position won't be logged."); } - // skip rendering broken data + // don't render broken data continue; } + //====================// // ignored block and // // cave culling check // @@ -272,27 +283,28 @@ public class FullDataToRenderDataTransformer } - //===================// - // solid block check // - //===================// - if (ignoreNonCollidingBlocks && !block.isSolid() && !block.isLiquid() && block.getOpacity() != LodUtil.BLOCK_FULLY_OPAQUE) + //=======================// + // non-solid block check // + //=======================// + + if (ignoreNonCollidingBlocks + && !block.isSolid() && !block.isLiquid() && block.getOpacity() != LodUtil.BLOCK_FULLY_OPAQUE) { if (colorBelowWithAvoidedBlocks) { int tempColor = level.computeBaseColor(new DhBlockPos(blockX, bottomY + level.getMinY(), blockZ), biome, block); // don't transfer the color when alpha is 0 + // this prevents issues if grass is transparent if (ColorUtil.getAlpha(tempColor) != 0) { - // don't transfer alpha if for some reason grass is semi transparent colorToApplyToNextBlock = ColorUtil.setAlpha(tempColor,255); - skylightToApplyToNextBlock = skyLight; blocklightToApplyToNextBlock = blockLight; } } - // don't add this block + // skip this non-colliding block continue; } @@ -312,7 +324,13 @@ public class FullDataToRenderDataTransformer blockLight = blocklightToApplyToNextBlock; } - //check if they share a top-bottom face and if they have same color + + + //=============================// + // merge same-colored adjacent // + //=============================// + + // check if they share a top-bottom face and if they have same color if (color == lastColor && bottomY + blockHeight == lastBottom && columnOffset > 0) { //replace the previous block with new bottom @@ -323,18 +341,17 @@ public class FullDataToRenderDataTransformer else { // add the block - isVoid = false; + isColumnVoid = false; long columnData = RenderDataPointUtil.createDataPoint(bottomY + blockHeight, bottomY, color, skyLight, blockLight, block.getMaterialId()); renderColumnData.set(columnOffset, columnData); columnOffset++; } lastBottom = bottomY; lastColor = color; - } - if (isVoid) + if (isColumnVoid) { renderColumnData.set(0, RenderDataPointUtil.createVoidDataPoint()); } From 9c25a6450a9d1c810f68921049ea971050d7c43b Mon Sep 17 00:00:00 2001 From: James Seibel Date: Mon, 22 Jul 2024 20:47:34 -0500 Subject: [PATCH 03/22] comment ColumnArrayView --- .../render/columnViews/ColumnArrayView.java | 71 +++++++++++++------ .../FullDataToRenderDataTransformer.java | 6 +- 2 files changed, 52 insertions(+), 25 deletions(-) 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/ColumnArrayView.java index 88bd337b3..a6f807adb 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/ColumnArrayView.java @@ -20,6 +20,7 @@ package com.seibel.distanthorizons.core.dataObjects.render.columnViews; +import com.seibel.distanthorizons.core.dataObjects.render.ColumnRenderSource; import com.seibel.distanthorizons.core.util.RenderDataPointUtil; import it.unimi.dsi.fastutil.longs.LongArrayList; @@ -28,41 +29,60 @@ import java.util.Arrays; public final class ColumnArrayView implements IColumnDataView { public final LongArrayList data; + + /** + * How many data points are currently being represented by this view.
+ * Will be equal to or less than {@link ColumnArrayView#verticalSize}. + */ public final int size; - public final int offset; // offset in longs - /** can be 0 if this column was created for an empty data source */ - public final int vertSize; // vertical size in longs + /** + * Vertical size in data points.
+ * Can be 0 if this column was created for an empty data source. + */ + public final int verticalSize; + + /** + * Where the relative starting index is in the {@link ColumnArrayView#data} array + * if this view is representing part of a {@link ColumnRenderSource}. + */ + public final int offset; - public ColumnArrayView(LongArrayList data, int size, int offset, int vertSize) + //=============// + // constructor // + //=============// + + public ColumnArrayView(LongArrayList data, int size, int offset, int verticalSize) { this.data = data; this.size = size; this.offset = offset; - this.vertSize = vertSize; + this.verticalSize = verticalSize; } + //=====================// + // getters and setters // + //=====================// + @Override public long get(int index) { return data.getLong(index + offset); } - public void set(int index, long value) { data.set(index + offset, value); } @Override public int size() { return size; } + @Override + public int verticalSize() { return verticalSize; } @Override - public int verticalSize() { return vertSize; } - - @Override - public int dataCount() { return (this.vertSize != 0) ? (this.size / this.vertSize) : 0; } + public int dataCount() { return (this.verticalSize != 0) ? (this.size / this.verticalSize) : 0; } // TODO what does the divide by mean? @Override public ColumnArrayView subView(int dataIndexStart, int dataCount) { - return new ColumnArrayView(data, dataCount * vertSize, offset + dataIndexStart * vertSize, vertSize); + return new ColumnArrayView(data, dataCount * verticalSize, offset + dataIndexStart * verticalSize, verticalSize); } public void fill(long value) { Arrays.fill(data.elements(), offset, offset + size, value); } @@ -70,7 +90,7 @@ public final class ColumnArrayView implements IColumnDataView public void copyFrom(IColumnDataView source) { copyFrom(source, 0); } public void copyFrom(IColumnDataView source, int outputDataIndexOffset) { - if (source.verticalSize() > vertSize) + if (source.verticalSize() > verticalSize) { throw new IllegalArgumentException("source verticalSize must be <= self's verticalSize to copy"); } @@ -78,19 +98,19 @@ public final class ColumnArrayView implements IColumnDataView { throw new IllegalArgumentException("dataIndexStart + source.dataCount() must be <= self.dataCount() to copy"); } - else if (source.verticalSize() != vertSize) + else if (source.verticalSize() != verticalSize) { for (int i = 0; i < source.dataCount(); i++) { - int outputOffset = offset + outputDataIndexOffset * vertSize + i * vertSize; + int outputOffset = offset + outputDataIndexOffset * verticalSize + i * verticalSize; source.subView(i, 1).copyTo(data.elements(), outputOffset, source.verticalSize()); Arrays.fill(data.elements(), outputOffset + source.verticalSize(), - outputOffset + vertSize, 0); + outputOffset + verticalSize, 0); } } else { - source.copyTo(data.elements(), offset + outputDataIndexOffset * vertSize, source.size()); + source.copyTo(data.elements(), offset + outputDataIndexOffset * verticalSize, source.size()); } } @@ -103,19 +123,19 @@ public final class ColumnArrayView implements IColumnDataView { throw new IllegalArgumentException("Cannot merge views of different sizes"); } - if (vertSize != source.vertSize) + if (verticalSize != source.verticalSize) { throw new IllegalArgumentException("Cannot merge views of different vertical sizes"); } boolean anyChange = false; - for (int o = 0; o < (source.size() * vertSize); o += vertSize) + for (int o = 0; o < (source.size() * verticalSize); o += verticalSize) { if (override) { if (RenderDataPointUtil.compareDatapointPriority(source.get(o), get(o)) >= 0) { anyChange = true; - System.arraycopy(source.data, source.offset + o, data, offset + o, vertSize); + System.arraycopy(source.data, source.offset + o, data, offset + o, verticalSize); } } else @@ -123,7 +143,7 @@ public final class ColumnArrayView implements IColumnDataView if (RenderDataPointUtil.compareDatapointPriority(source.get(o), get(o)) > 0) { anyChange = true; - System.arraycopy(source.data, source.offset + o, data, offset + o, vertSize); + System.arraycopy(source.data, source.offset + o, data, offset + o, verticalSize); } } } @@ -137,7 +157,7 @@ public final class ColumnArrayView implements IColumnDataView throw new IllegalArgumentException("Cannot copy and resize to views with different dataCounts"); } - if (this.vertSize >= source.verticalSize()) + if (this.verticalSize >= source.verticalSize()) { this.copyFrom(source); } @@ -160,12 +180,18 @@ public final class ColumnArrayView implements IColumnDataView RenderDataPointUtil.mergeMultiData(source, this); } + + + //================// + // base overrides // + //================// + @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("S:").append(size); - sb.append(" V:").append(vertSize); + sb.append(" V:").append(verticalSize); sb.append(" O:").append(offset); sb.append(" ["); @@ -182,6 +208,7 @@ public final class ColumnArrayView implements IColumnDataView return sb.toString(); } + public int getDataHash() { return arrayHash(data, offset, size); 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 e41cba5b1..969354f8f 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 @@ -194,9 +194,9 @@ public class FullDataToRenderDataTransformer - //===========================// - // iterate through full data // - //===========================// + //==================================// + // convert full data to render data // + //==================================// // goes from the top down for (int i = 0; i < fullColumnData.size(); i++) From a9f6b924c26ca7692a55c64998e85a3b5faf71a3 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Tue, 23 Jul 2024 07:05:28 -0500 Subject: [PATCH 04/22] Move CubicLodTemplate to ColumnRenderBufferBuilder --- .../ColumnRenderBufferBuilder.java | 147 +++++++++++++- .../bufferBuilding/CubicLodTemplate.java | 186 ------------------ 2 files changed, 145 insertions(+), 188 deletions(-) delete mode 100644 core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/CubicLodTemplate.java 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 d6793a34c..495864d41 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 @@ -19,6 +19,7 @@ package com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding; +import com.seibel.distanthorizons.api.enums.rendering.EDhApiBlockMaterial; import com.seibel.distanthorizons.api.enums.rendering.EDhApiDebugRendering; import com.seibel.distanthorizons.core.enums.EDhDirection; import com.seibel.distanthorizons.core.config.Config; @@ -27,14 +28,17 @@ import com.seibel.distanthorizons.core.level.IDhClientLevel; import com.seibel.distanthorizons.core.logging.ConfigBasedLogger; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.pos.DhBlockPos; +import com.seibel.distanthorizons.core.pos.DhLodPos; import com.seibel.distanthorizons.core.pos.DhSectionPos; import com.seibel.distanthorizons.core.render.glObject.GLProxy; import com.seibel.distanthorizons.core.render.glObject.buffer.GLVertexBuffer; +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.util.objects.UncheckedInterruptedException; import com.seibel.distanthorizons.core.dataObjects.render.columnViews.ColumnArrayView; import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil; +import com.seibel.distanthorizons.coreapi.util.BitShiftUtil; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -222,7 +226,7 @@ public class ColumnRenderBufferBuilder int zAdj = z + lodDirection.getNormal().z; boolean isCrossRegionBoundary = (xAdj < 0 || xAdj >= ColumnRenderSource.SECTION_SIZE) || - (zAdj < 0 || zAdj >= ColumnRenderSource.SECTION_SIZE); + (zAdj < 0 || zAdj >= ColumnRenderSource.SECTION_SIZE); ColumnRenderSource adjRenderSource; byte adjDetailLevel; @@ -315,7 +319,7 @@ public class ColumnRenderBufferBuilder long topDataPoint = (i - 1) >= 0 ? columnRenderData.get(i - 1) : RenderDataPointUtil.EMPTY_DATA; long bottomDataPoint = (i + 1) < columnRenderData.size() ? columnRenderData.get(i + 1) : RenderDataPointUtil.EMPTY_DATA; - CubicLodTemplate.addLodToBuffer(data, topDataPoint, bottomDataPoint, adjColumnViews, detailLevel, + addLodToBuffer(data, topDataPoint, bottomDataPoint, adjColumnViews, detailLevel, x, z, quadBuilder, debugMode, debugSourceFlag); } @@ -324,6 +328,145 @@ public class ColumnRenderBufferBuilder quadBuilder.finalizeData(); } + private static void addLodToBuffer( + long data, long topData, long bottomData, ColumnArrayView[][] adjColumnViews, + byte detailLevel, int offsetPosX, int offsetOosZ, LodQuadBuilder quadBuilder, + EDhApiDebugRendering debugging, ColumnRenderSource.DebugSourceFlag debugSource) + { + DhLodPos blockOffsetPos = new DhLodPos(detailLevel, offsetPosX, offsetOosZ).convertToDetailLevel(LodUtil.BLOCK_DETAIL_LEVEL); + + short width = (short) BitShiftUtil.powerOfTwo(detailLevel); + short x = (short) blockOffsetPos.x; + short yMin = RenderDataPointUtil.getYMin(data); + short z = (short) (short) blockOffsetPos.z; + short ySize = (short) (RenderDataPointUtil.getYMax(data) - yMin); + + if (ySize == 0) + { + return; + } + else if (ySize < 0) + { + throw new IllegalArgumentException("Negative y size for the data! Data: " + RenderDataPointUtil.toString(data)); + } + + byte blockMaterialId = RenderDataPointUtil.getBlockMaterialId(data); + + + + int color; + boolean fullBright = false; + switch (debugging) + { + case OFF: + { + float saturationMultiplier = Config.Client.Advanced.Graphics.AdvancedGraphics.saturationMultiplier.get().floatValue(); + float brightnessMultiplier = Config.Client.Advanced.Graphics.AdvancedGraphics.brightnessMultiplier.get().floatValue(); + if (saturationMultiplier == 1.0 && brightnessMultiplier == 1.0) + { + color = RenderDataPointUtil.getColor(data); + } + else + { + float[] ahsv = ColorUtil.argbToAhsv(RenderDataPointUtil.getColor(data)); + color = ColorUtil.ahsvToArgb(ahsv[0], ahsv[1], ahsv[2] * saturationMultiplier, ahsv[3] * brightnessMultiplier); + } + break; + } + case SHOW_DETAIL: + { + color = LodUtil.DEBUG_DETAIL_LEVEL_COLORS[detailLevel]; + fullBright = true; + break; + } + case SHOW_BLOCK_MATERIAL: + { + + switch (EDhApiBlockMaterial.getFromIndex(blockMaterialId)) + { + case UNKNOWN: + case AIR: // shouldn't normally be rendered, but just in case + color = ColorUtil.HOT_PINK; + break; + + case LEAVES: + color = ColorUtil.DARK_GREEN; + break; + case STONE: + color = ColorUtil.GRAY; + break; + case WOOD: + color = ColorUtil.BROWN; + break; + case METAL: + color = ColorUtil.DARK_GRAY; + break; + case DIRT: + color = ColorUtil.LIGHT_BROWN; + break; + case LAVA: + color = ColorUtil.ORANGE; + break; + case DEEPSLATE: + color = ColorUtil.BLACK; + break; + case SNOW: + color = ColorUtil.WHITE; + break; + case SAND: + color = ColorUtil.TAN; + break; + case TERRACOTTA: + color = ColorUtil.DARK_ORANGE; + break; + case NETHER_STONE: + color = ColorUtil.DARK_RED; + break; + case WATER: + color = ColorUtil.BLUE; + break; + case GRASS: + color = ColorUtil.GREEN; + break; + case ILLUMINATED: + color = ColorUtil.YELLOW; + break; + + default: + // undefined color + color = ColorUtil.CYAN; + break; + } + + fullBright = true; + break; + } + case SHOW_OVERLAPPING_QUADS: + { + color = ColorUtil.WHITE; + fullBright = true; + break; + } + case SHOW_RENDER_SOURCE_FLAG: + { + color = debugSource == null ? ColorUtil.RED : debugSource.color; + fullBright = true; + break; + } + default: + throw new IllegalArgumentException("Unknown debug mode: " + debugging); + } + + ColumnBox.addBoxQuadsToBuilder( + quadBuilder, // buffer + width, ySize, width, // setWidth + x, yMin, z, // setOffset + color, // setColor + blockMaterialId, // irisBlockMaterialId + RenderDataPointUtil.getLightSky(data), // setSkyLights + fullBright ? 15 : RenderDataPointUtil.getLightBlock(data), // setBlockLights + topData, bottomData, adjColumnViews); // setAdjData + } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/CubicLodTemplate.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/CubicLodTemplate.java deleted file mode 100644 index a45fb2ec4..000000000 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/CubicLodTemplate.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * This file is part of the Distant Horizons mod - * licensed under the GNU LGPL v3 License. - * - * Copyright (C) 2020-2023 James Seibel - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding; - -import com.seibel.distanthorizons.api.enums.rendering.EDhApiBlockMaterial; -import com.seibel.distanthorizons.core.config.Config; -import com.seibel.distanthorizons.core.dataObjects.render.ColumnRenderSource; -import com.seibel.distanthorizons.core.pos.DhLodPos; -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.api.enums.rendering.EDhApiDebugRendering; -import com.seibel.distanthorizons.core.dataObjects.render.columnViews.ColumnArrayView; -import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper; -import com.seibel.distanthorizons.coreapi.util.BitShiftUtil; - -/** - * Builds LODs as rectangular prisms. - * - * @author James Seibel - * @version 2022-1-2 - */ -public class CubicLodTemplate -{ - - public static void addLodToBuffer( - long data, long topData, long bottomData, ColumnArrayView[][] adjColumnViews, - byte detailLevel, int offsetPosX, int offsetOosZ, LodQuadBuilder quadBuilder, - EDhApiDebugRendering debugging, ColumnRenderSource.DebugSourceFlag debugSource) - { - DhLodPos blockOffsetPos = new DhLodPos(detailLevel, offsetPosX, offsetOosZ).convertToDetailLevel(LodUtil.BLOCK_DETAIL_LEVEL); - - short width = (short) BitShiftUtil.powerOfTwo(detailLevel); - short x = (short) blockOffsetPos.x; - short yMin = RenderDataPointUtil.getYMin(data); - short z = (short) (short) blockOffsetPos.z; - short ySize = (short) (RenderDataPointUtil.getYMax(data) - yMin); - - if (ySize == 0) - { - return; - } - else if (ySize < 0) - { - throw new IllegalArgumentException("Negative y size for the data! Data: " + RenderDataPointUtil.toString(data)); - } - - byte blockMaterialId = RenderDataPointUtil.getBlockMaterialId(data); - - - - int color; - boolean fullBright = false; - switch (debugging) - { - case OFF: - { - float saturationMultiplier = Config.Client.Advanced.Graphics.AdvancedGraphics.saturationMultiplier.get().floatValue(); - float brightnessMultiplier = Config.Client.Advanced.Graphics.AdvancedGraphics.brightnessMultiplier.get().floatValue(); - if (saturationMultiplier == 1.0 && brightnessMultiplier == 1.0) - { - color = RenderDataPointUtil.getColor(data); - } - else - { - float[] ahsv = ColorUtil.argbToAhsv(RenderDataPointUtil.getColor(data)); - color = ColorUtil.ahsvToArgb(ahsv[0], ahsv[1], ahsv[2] * saturationMultiplier, ahsv[3] * brightnessMultiplier); - //ApiShared.LOGGER.info("Raw color:[{}], AHSV:{}, Out color:[{}]", - // ColorUtil.toString(DataPointUtil.getColor(data)), - // ahsv, ColorUtil.toString(color)); - } - break; - } - case SHOW_DETAIL: - { - color = LodUtil.DEBUG_DETAIL_LEVEL_COLORS[detailLevel]; - fullBright = true; - break; - } - case SHOW_BLOCK_MATERIAL: - { - - switch (EDhApiBlockMaterial.getFromIndex(blockMaterialId)) - { - case UNKNOWN: - case AIR: // shouldn't normally be rendered, but just in case - color = ColorUtil.HOT_PINK; - break; - - case LEAVES: - color = ColorUtil.DARK_GREEN; - break; - case STONE: - color = ColorUtil.GRAY; - break; - case WOOD: - color = ColorUtil.BROWN; - break; - case METAL: - color = ColorUtil.DARK_GRAY; - break; - case DIRT: - color = ColorUtil.LIGHT_BROWN; - break; - case LAVA: - color = ColorUtil.ORANGE; - break; - case DEEPSLATE: - color = ColorUtil.BLACK; - break; - case SNOW: - color = ColorUtil.WHITE; - break; - case SAND: - color = ColorUtil.TAN; - break; - case TERRACOTTA: - color = ColorUtil.DARK_ORANGE; - break; - case NETHER_STONE: - color = ColorUtil.DARK_RED; - break; - case WATER: - color = ColorUtil.BLUE; - break; - case GRASS: - color = ColorUtil.GREEN; - break; - case ILLUMINATED: - color = ColorUtil.YELLOW; - break; - - default: - // undefined color - color = ColorUtil.CYAN; - break; - } - - fullBright = true; - break; - } - case SHOW_OVERLAPPING_QUADS: - { - color = ColorUtil.WHITE; - fullBright = true; - break; - } - case SHOW_RENDER_SOURCE_FLAG: - { - color = debugSource == null ? ColorUtil.RED : debugSource.color; - fullBright = true; - break; - } - default: - throw new IllegalArgumentException("Unknown debug mode: " + debugging); - } - - ColumnBox.addBoxQuadsToBuilder( - quadBuilder, // buffer - width, ySize, width, // setWidth - x, yMin, z, // setOffset - color, // setColor - blockMaterialId, // irisBlockMaterialId - RenderDataPointUtil.getLightSky(data), // setSkyLights - fullBright ? 15 : RenderDataPointUtil.getLightBlock(data), // setBlockLights - topData, bottomData, adjColumnViews); // setAdjData - } - -} From b70c090e946c97032ebc26511197555f126f7a33 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Tue, 23 Jul 2024 19:39:44 -0500 Subject: [PATCH 05/22] Refactor and cleanup buffer building --- .../render/ColumnRenderSource.java | 2 +- .../render/bufferBuilding/ColumnBox.java | 55 +--- .../bufferBuilding/ColumnRenderBuffer.java | 43 ++- .../ColumnRenderBufferBuilder.java | 253 +++++++++--------- 4 files changed, 168 insertions(+), 185 deletions(-) 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 1bed16709..2ede2327c 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 @@ -288,7 +288,7 @@ public class ColumnRenderSource implements IDataSource String SUBDATA_DELIMITER = ","; StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.append(this.pos); + stringBuilder.append(DhSectionPos.toString(this.pos)); stringBuilder.append(LINE_DELIMITER); int size = 1; 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 0cc51e422..700baa3d8 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 @@ -40,7 +40,7 @@ public class ColumnBox short xSize, short ySize, short zSize, short x, short minY, short z, int color, byte irisBlockMaterialId, byte skyLight, byte blockLight, - long topData, long bottomData, ColumnArrayView[][] adjData) + long topData, long bottomData, ColumnArrayView[] adjData) { short maxX = (short) (x + xSize); short maxY = (short) (minY + ySize); @@ -119,7 +119,7 @@ public class ColumnBox // TODO merge duplicate code //NORTH face vertex creation { - ColumnArrayView[] adjDataNorth = adjData[EDhDirection.NORTH.ordinal() - 2]; // TODO can we use something other than ordinal-2? + ColumnArrayView adjDataNorth = adjData[EDhDirection.NORTH.ordinal() - 2]; // TODO can we use something other than ordinal-2? int adjOverlapNorth = ColorUtil.INVISIBLE; if (adjDataNorth == null) { @@ -129,18 +129,9 @@ public class ColumnBox builder.addQuadAdj(EDhDirection.NORTH, x, minY, z, xSize, ySize, color, irisBlockMaterialId, LodUtil.MAX_MC_LIGHT, blockLight); } } - else if (adjDataNorth.length == 1) - { - makeAdjVerticalQuad(builder, adjDataNorth[0], EDhDirection.NORTH, x, minY, z, xSize, ySize, - color, adjOverlapNorth, irisBlockMaterialId, skyLightTop, blockLight, - topData, bottomData); - } else { - makeAdjVerticalQuad(builder, adjDataNorth[0], EDhDirection.NORTH, x, minY, z, (short) (xSize / 2), ySize, - color, adjOverlapNorth, irisBlockMaterialId, skyLightTop, blockLight, - topData, bottomData); - makeAdjVerticalQuad(builder, adjDataNorth[1], EDhDirection.NORTH, (short) (x + xSize / 2), minY, z, (short) (xSize / 2), ySize, + makeAdjVerticalQuad(builder, adjDataNorth, EDhDirection.NORTH, x, minY, z, xSize, ySize, color, adjOverlapNorth, irisBlockMaterialId, skyLightTop, blockLight, topData, bottomData); } @@ -148,26 +139,16 @@ public class ColumnBox //SOUTH face vertex creation { - ColumnArrayView[] adjDataSouth = adjData[EDhDirection.SOUTH.ordinal() - 2]; + ColumnArrayView adjDataSouth = adjData[EDhDirection.SOUTH.ordinal() - 2]; int adjOverlapSouth = ColorUtil.INVISIBLE; if (adjDataSouth == null) { if (!isTransparent || overVoid) builder.addQuadAdj(EDhDirection.SOUTH, x, minY, maxZ, xSize, ySize, color, irisBlockMaterialId, LodUtil.MAX_MC_LIGHT, blockLight); } - else if (adjDataSouth.length == 1) - { - makeAdjVerticalQuad(builder, adjDataSouth[0], EDhDirection.SOUTH, x, minY, maxZ, xSize, ySize, - color, adjOverlapSouth, irisBlockMaterialId, skyLightTop, blockLight, - topData, bottomData); - } else { - makeAdjVerticalQuad(builder, adjDataSouth[0], EDhDirection.SOUTH, x, minY, maxZ, (short) (xSize / 2), ySize, - color, adjOverlapSouth, irisBlockMaterialId, skyLightTop, blockLight, - topData, bottomData); - - makeAdjVerticalQuad(builder, adjDataSouth[1], EDhDirection.SOUTH, (short) (x + xSize / 2), minY, maxZ, (short) (xSize / 2), ySize, + makeAdjVerticalQuad(builder, adjDataSouth, EDhDirection.SOUTH, x, minY, maxZ, xSize, ySize, color, adjOverlapSouth, irisBlockMaterialId, skyLightTop, blockLight, topData, bottomData); } @@ -175,25 +156,16 @@ public class ColumnBox //WEST face vertex creation { - ColumnArrayView[] adjDataWest = adjData[EDhDirection.WEST.ordinal() - 2]; + ColumnArrayView adjDataWest = adjData[EDhDirection.WEST.ordinal() - 2]; int adjOverlapWest = ColorUtil.INVISIBLE; if (adjDataWest == null) { if (!isTransparent || overVoid) builder.addQuadAdj(EDhDirection.WEST, x, minY, z, zSize, ySize, color, irisBlockMaterialId, LodUtil.MAX_MC_LIGHT, blockLight); } - else if (adjDataWest.length == 1) - { - makeAdjVerticalQuad(builder, adjDataWest[0], EDhDirection.WEST, x, minY, z, zSize, ySize, - color, adjOverlapWest, irisBlockMaterialId, skyLightTop, blockLight, - topData, bottomData); - } else { - makeAdjVerticalQuad(builder, adjDataWest[0], EDhDirection.WEST, x, minY, z, (short) (zSize / 2), ySize, - color, adjOverlapWest, irisBlockMaterialId, skyLightTop, blockLight, - topData, bottomData); - makeAdjVerticalQuad(builder, adjDataWest[1], EDhDirection.WEST, x, minY, (short) (z + zSize / 2), (short) (zSize / 2), ySize, + makeAdjVerticalQuad(builder, adjDataWest, EDhDirection.WEST, x, minY, z, zSize, ySize, color, adjOverlapWest, irisBlockMaterialId, skyLightTop, blockLight, topData, bottomData); } @@ -201,25 +173,16 @@ public class ColumnBox //EAST face vertex creation { - ColumnArrayView[] adjDataEast = adjData[EDhDirection.EAST.ordinal() - 2]; + ColumnArrayView adjDataEast = adjData[EDhDirection.EAST.ordinal() - 2]; int adjOverlapEast = ColorUtil.INVISIBLE; if (adjData[EDhDirection.EAST.ordinal() - 2] == null) { if (!isTransparent || overVoid) builder.addQuadAdj(EDhDirection.EAST, maxX, minY, z, zSize, ySize, color, irisBlockMaterialId, LodUtil.MAX_MC_LIGHT, blockLight); } - else if (adjDataEast.length == 1) - { - makeAdjVerticalQuad(builder, adjDataEast[0], EDhDirection.EAST, maxX, minY, z, zSize, ySize, - color, adjOverlapEast, irisBlockMaterialId, skyLightTop, blockLight, - topData, bottomData); - } else { - makeAdjVerticalQuad(builder, adjDataEast[0], EDhDirection.EAST, maxX, minY, z, (short) (zSize / 2), ySize, - color, adjOverlapEast, irisBlockMaterialId, skyLightTop, blockLight, - topData, bottomData); - makeAdjVerticalQuad(builder, adjDataEast[1], EDhDirection.EAST, maxX, minY, (short) (z + zSize / 2), (short) (zSize / 2), ySize, + makeAdjVerticalQuad(builder, adjDataEast, EDhDirection.EAST, maxX, minY, z, zSize, ySize, color, adjOverlapEast, irisBlockMaterialId, skyLightTop, blockLight, topData, bottomData); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnRenderBuffer.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnRenderBuffer.java index 8a95bc2c7..81694c8a6 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnRenderBuffer.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnRenderBuffer.java @@ -146,7 +146,7 @@ public class ColumnRenderBuffer implements AutoCloseable { // opaque vbos // - this.vbos = ColumnRenderBufferBuilder.resizeBuffer(this.vbos, builder.getCurrentNeededOpaqueVertexBufferCount()); + this.vbos = resizeBuffer(this.vbos, builder.getCurrentNeededOpaqueVertexBufferCount()); for (int i = 0; i < this.vbos.length; i++) { if (this.vbos[i] == null) @@ -163,7 +163,7 @@ public class ColumnRenderBuffer implements AutoCloseable // transparent vbos // - this.vbosTransparent = ColumnRenderBufferBuilder.resizeBuffer(this.vbosTransparent, builder.getCurrentNeededTransparentVertexBufferCount()); + this.vbosTransparent = resizeBuffer(this.vbosTransparent, builder.getCurrentNeededTransparentVertexBufferCount()); for (int i = 0; i < this.vbosTransparent.length; i++) { if (this.vbosTransparent[i] == null) @@ -180,10 +180,10 @@ public class ColumnRenderBuffer implements AutoCloseable private void uploadBuffersDirect(LodQuadBuilder builder, EDhApiGpuUploadMethod method) throws InterruptedException { - this.vbos = ColumnRenderBufferBuilder.resizeBuffer(this.vbos, builder.getCurrentNeededOpaqueVertexBufferCount()); + this.vbos = resizeBuffer(this.vbos, builder.getCurrentNeededOpaqueVertexBufferCount()); uploadBuffersDirect(this.vbos, builder.makeOpaqueVertexBuffers(), method); - this.vbosTransparent = ColumnRenderBufferBuilder.resizeBuffer(this.vbosTransparent, builder.getCurrentNeededTransparentVertexBufferCount()); + this.vbosTransparent = resizeBuffer(this.vbosTransparent, builder.getCurrentNeededTransparentVertexBufferCount()); uploadBuffersDirect(this.vbosTransparent, builder.makeTransparentVertexBuffers(), method); } private static void uploadBuffersDirect(GLVertexBuffer[] vbos, Iterator iter, EDhApiGpuUploadMethod method) throws InterruptedException @@ -318,9 +318,9 @@ public class ColumnRenderBuffer implements AutoCloseable - //==============// - // misc methods // - //==============// + //================// + // helper methods // + //================// /** can be used when debugging */ public boolean hasNonNullVbos() { return this.vbos != null || this.vbosTransparent != null; } @@ -366,6 +366,35 @@ public class ColumnRenderBuffer implements AutoCloseable } } + public static GLVertexBuffer[] resizeBuffer(GLVertexBuffer[] vbos, int newSize) + { + if (vbos.length == newSize) + { + return vbos; + } + + GLVertexBuffer[] newVbos = new GLVertexBuffer[newSize]; + System.arraycopy(vbos, 0, newVbos, 0, Math.min(vbos.length, newSize)); + if (newSize < vbos.length) + { + for (int i = newSize; i < vbos.length; i++) + { + if (vbos[i] != null) + { + vbos[i].close(); + } + } + } + return newVbos; + } + + + + + //================// + // base overrides // + //================// + /** * This method is called when object is no longer in use. * Called either after uploadBuffers() returned false (On buffer Upload 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 495864d41..a398448d8 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 @@ -85,16 +85,8 @@ public class ColumnRenderBufferBuilder try { boolean enableTransparency = Config.Client.Advanced.Graphics.Quality.transparency.get().transparencyEnabled; - - long builderStartTime = System.currentTimeMillis(); - LodQuadBuilder builder = new LodQuadBuilder(enableTransparency, clientLevel.getClientLevelWrapper()); makeLodRenderData(builder, renderSource, adjData); - - long builderEndTime = System.currentTimeMillis(); - long buildMs = builderEndTime - builderStartTime; - //LOGGER.debug("RenderRegion end QuadBuild @ " + renderSource.pos + " took: " + buildMs); - return builder; } catch (UncheckedInterruptedException e) @@ -146,19 +138,20 @@ public class ColumnRenderBufferBuilder } private static void makeLodRenderData(LodQuadBuilder quadBuilder, ColumnRenderSource renderSource, ColumnRenderSource[] adjRegions) { - // Variable initialization - EDhApiDebugRendering debugMode = Config.Client.Advanced.Debugging.debugRendering.get(); + //=============// + // debug check // + //=============// // can be used to limit which section positions are build and thus, rendered // useful when debugging a specific section - boolean enableColumnBufferLimit = Config.Client.Advanced.Debugging.columnBuilderDebugEnable.get(); - if (enableColumnBufferLimit) + boolean columnBuilderDebugEnabled = Config.Client.Advanced.Debugging.columnBuilderDebugEnable.get(); + if (columnBuilderDebugEnabled) { if (DhSectionPos.getDetailLevel(renderSource.pos) == Config.Client.Advanced.Debugging.columnBuilderDebugDetailLevel.get() && DhSectionPos.getX(renderSource.pos) == Config.Client.Advanced.Debugging.columnBuilderDebugXPos.get() && DhSectionPos.getZ(renderSource.pos) == Config.Client.Advanced.Debugging.columnBuilderDebugZPos.get()) { - int test = 0; + int breakpoint = 0; } else { @@ -166,32 +159,22 @@ public class ColumnRenderBufferBuilder } } - byte detailLevel = renderSource.getDataDetailLevel(); - for (int x = 0; x < ColumnRenderSource.SECTION_SIZE; x++) + + + //===================// + // build each column // + //===================// + + byte thisDetailLevel = renderSource.getDataDetailLevel(); + for (int relX = 0; relX < ColumnRenderSource.SECTION_SIZE; relX++) { - for (int z = 0; z < ColumnRenderSource.SECTION_SIZE; z++) + for (int relZ = 0; relZ < ColumnRenderSource.SECTION_SIZE; relZ++) { - // can be uncommented to limit the buffer building to a specific - // relative position in this section. - // useful for debugging a single column's rendering - if (Config.Client.Advanced.Debugging.columnBuilderDebugEnable.get()) - { - int wantedX = Config.Client.Advanced.Debugging.columnBuilderDebugXRow.get(); - if (wantedX >= 0 && x != wantedX) - { - continue; - } - int wantedZ = Config.Client.Advanced.Debugging.columnBuilderDebugZRow.get(); - if (wantedZ >= 0 && z != wantedZ) - { - continue; - } - } - - + // stop the builder if requested UncheckedInterruptedException.throwIfInterrupted(); - ColumnArrayView columnRenderData = renderSource.getVerticalDataPointView(x, z); + // ignore empty/null columns + ColumnArrayView columnRenderData = renderSource.getVerticalDataPointView(relX, relZ); if (columnRenderData.size() == 0 || !RenderDataPointUtil.doesDataPointExist(columnRenderData.get(0)) || RenderDataPointUtil.isVoid(columnRenderData.get(0))) @@ -199,43 +182,66 @@ public class ColumnRenderBufferBuilder continue; } - ColumnRenderSource.DebugSourceFlag debugSourceFlag = renderSource.debugGetFlag(x, z); - - ColumnArrayView[][] adjColumnViews = new ColumnArrayView[4][]; - // We extract the adj data in the four cardinal direction - - // we first reset the adjShadeDisabled. This is used to disable the shade on the - // border when we have transparent block like water or glass - // to avoid having a "darker border" underground - // Arrays.fill(adjShadeDisabled, false); - // We check every adj block in each direction + //=============// + // debug limit // + //=============// - // If the adj block is rendered in the same region and with same detail - // and is positioned in a place that is not going to be rendered by vanilla game - // then we can set this position as adj - // We avoid cases where the adjPosition is in player chunk while the position is - // not - // to always have a wall underwater + // can be used to limit the buffer building to a specific relative position. + // useful for debugging a single column + if (columnBuilderDebugEnabled) + { + int wantedX = Config.Client.Advanced.Debugging.columnBuilderDebugXRow.get(); + if (wantedX >= 0 && relX != wantedX) + { + continue; + } + int wantedZ = Config.Client.Advanced.Debugging.columnBuilderDebugZRow.get(); + if (wantedZ >= 0 && relZ != wantedZ) + { + continue; + } + } + + + + //==================================// + // get adjacent render data columns // + //==================================// + + ColumnArrayView[] adjColumnViews = new ColumnArrayView[EDhDirection.ADJ_DIRECTIONS.length]; for (EDhDirection lodDirection : EDhDirection.ADJ_DIRECTIONS) { try { - int xAdj = x + lodDirection.getNormal().x; - int zAdj = z + lodDirection.getNormal().z; - boolean isCrossRegionBoundary = + int xAdj = relX + lodDirection.getNormal().x; + int zAdj = relZ + lodDirection.getNormal().z; + boolean isCrossRenderSourceBoundary = (xAdj < 0 || xAdj >= ColumnRenderSource.SECTION_SIZE) || (zAdj < 0 || zAdj >= ColumnRenderSource.SECTION_SIZE); ColumnRenderSource adjRenderSource; byte adjDetailLevel; - //we check if the detail of the adjPos is equal to the correct one (region border fix) - //or if the detail is wrong by 1 value (region+circle border fix) - if (isCrossRegionBoundary) + + + //=========================// + // get the adjacent render // + // source if present // + //=========================// + + if (!isCrossRenderSourceBoundary) { - //we compute at which detail that position should be rendered + // the adjacent position is inside this same render source + adjRenderSource = renderSource; + adjDetailLevel = thisDetailLevel; + } + else + { + // the adjacent position is outside this render source + + // skip empty sections adjRenderSource = adjRegions[lodDirection.ordinal() - 2]; if (adjRenderSource == null) { @@ -243,57 +249,65 @@ public class ColumnRenderBufferBuilder } adjDetailLevel = adjRenderSource.getDataDetailLevel(); - if (adjDetailLevel != detailLevel) + if (adjDetailLevel == thisDetailLevel) { - //TODO: Implement this + // if the adjacent position is outside this render source, + // wrap the position around so it's inside the adjacent source + + if (xAdj < 0) + { + xAdj += ColumnRenderSource.SECTION_SIZE; + } + if (xAdj >= ColumnRenderSource.SECTION_SIZE) + { + xAdj -= ColumnRenderSource.SECTION_SIZE; + } + + if (zAdj < 0) + { + zAdj += ColumnRenderSource.SECTION_SIZE; + } + if (zAdj >= ColumnRenderSource.SECTION_SIZE) + { + zAdj -= ColumnRenderSource.SECTION_SIZE; + } } else { - if (xAdj < 0) - xAdj += ColumnRenderSource.SECTION_SIZE; - - if (zAdj < 0) - zAdj += ColumnRenderSource.SECTION_SIZE; - - if (xAdj >= ColumnRenderSource.SECTION_SIZE) - xAdj -= ColumnRenderSource.SECTION_SIZE; - - if (zAdj >= ColumnRenderSource.SECTION_SIZE) - zAdj -= ColumnRenderSource.SECTION_SIZE; + // TODO: handle adjacent sections with a lower detail level + // if not handled sometimes holes will appear on the boarder + // between high and low detail sections, + // since the low detail section assumes it is next to another + // low detail section that would cover the hole. } } - else - { - adjRenderSource = renderSource; - adjDetailLevel = detailLevel; - } - if (adjDetailLevel < detailLevel - 1 || adjDetailLevel > detailLevel + 1) - { - continue; - } - if (adjDetailLevel == detailLevel || adjDetailLevel > detailLevel) - { - adjColumnViews[lodDirection.ordinal() - 2] = new ColumnArrayView[1]; - adjColumnViews[lodDirection.ordinal() - 2][0] = adjRenderSource.getVerticalDataPointView(xAdj, zAdj); - } - else - { - adjColumnViews[lodDirection.ordinal() - 2] = new ColumnArrayView[2]; - adjColumnViews[lodDirection.ordinal() - 2][0] = adjRenderSource.getVerticalDataPointView(xAdj, zAdj); - adjColumnViews[lodDirection.ordinal() - 2][1] = adjRenderSource.getVerticalDataPointView( - xAdj + (lodDirection.getAxis() == EDhDirection.Axis.X ? 0 : 1), - zAdj + (lodDirection.getAxis() == EDhDirection.Axis.Z ? 0 : 1)); - } + + //========================// + // get the adjacent views // + //========================// + + // the old logic handled additional cases, but they never appeared to fire, + // so just these two cases should be fine + LodUtil.assertTrue(adjDetailLevel == thisDetailLevel || adjDetailLevel > thisDetailLevel); + + adjColumnViews[lodDirection.ordinal() - 2] = adjRenderSource.getVerticalDataPointView(xAdj, zAdj); } catch (RuntimeException e) { - EVENT_LOGGER.warn("Failed to get adj data for [" + detailLevel + ":" + x + "," + z + "] at [" + lodDirection + "], Error: "+e.getMessage(), e); + EVENT_LOGGER.warn("Failed to get adj data for relative pos: [" + thisDetailLevel + ":" + relX + "," + relZ + "] at [" + lodDirection + "], Error: "+e.getMessage(), e); } } // for adjacent directions + + //==========================// + // build this render column // + //==========================// + + ColumnRenderSource.DebugSourceFlag debugSourceFlag = renderSource.debugGetFlag(relX, relZ); + // We render every vertical lod present in this position // We only stop when we find a block that is void or non-existing block for (int i = 0; i < columnRenderData.size(); i++) @@ -319,8 +333,11 @@ public class ColumnRenderBufferBuilder long topDataPoint = (i - 1) >= 0 ? columnRenderData.get(i - 1) : RenderDataPointUtil.EMPTY_DATA; long bottomDataPoint = (i + 1) < columnRenderData.size() ? columnRenderData.get(i + 1) : RenderDataPointUtil.EMPTY_DATA; - addLodToBuffer(data, topDataPoint, bottomDataPoint, adjColumnViews, detailLevel, - x, z, quadBuilder, debugMode, debugSourceFlag); + addLodToBuffer( + data, topDataPoint, bottomDataPoint, + adjColumnViews, + thisDetailLevel, relX, relZ, + quadBuilder, debugSourceFlag); } }// for z @@ -329,16 +346,17 @@ public class ColumnRenderBufferBuilder quadBuilder.finalizeData(); } private static void addLodToBuffer( - long data, long topData, long bottomData, ColumnArrayView[][] adjColumnViews, - byte detailLevel, int offsetPosX, int offsetOosZ, LodQuadBuilder quadBuilder, - EDhApiDebugRendering debugging, ColumnRenderSource.DebugSourceFlag debugSource) + long data, long topData, long bottomData, + ColumnArrayView[] adjColumnViews, + byte detailLevel, int renderSourceOffsetPosX, int renderSourceOffsetPosZ, + LodQuadBuilder quadBuilder, ColumnRenderSource.DebugSourceFlag debugSource) { - DhLodPos blockOffsetPos = new DhLodPos(detailLevel, offsetPosX, offsetOosZ).convertToDetailLevel(LodUtil.BLOCK_DETAIL_LEVEL); + long sectionPos = DhSectionPos.encode(detailLevel, renderSourceOffsetPosX, renderSourceOffsetPosZ); short width = (short) BitShiftUtil.powerOfTwo(detailLevel); - short x = (short) blockOffsetPos.x; + short x = (short) DhSectionPos.getMinCornerBlockX(sectionPos); short yMin = RenderDataPointUtil.getYMin(data); - short z = (short) (short) blockOffsetPos.z; + short z = (short) DhSectionPos.getMinCornerBlockZ(sectionPos); short ySize = (short) (RenderDataPointUtil.getYMax(data) - yMin); if (ySize == 0) @@ -347,7 +365,7 @@ public class ColumnRenderBufferBuilder } else if (ySize < 0) { - throw new IllegalArgumentException("Negative y size for the data! Data: " + RenderDataPointUtil.toString(data)); + throw new IllegalArgumentException("Negative y size for the data! Data: [" + RenderDataPointUtil.toString(data) + "]."); } byte blockMaterialId = RenderDataPointUtil.getBlockMaterialId(data); @@ -356,6 +374,7 @@ public class ColumnRenderBufferBuilder int color; boolean fullBright = false; + EDhApiDebugRendering debugging = Config.Client.Advanced.Debugging.debugRendering.get(); switch (debugging) { case OFF: @@ -468,32 +487,4 @@ public class ColumnRenderBufferBuilder topData, bottomData, adjColumnViews); // setAdjData } - - - //=================// - // vbo interaction // - //=================// - - public static GLVertexBuffer[] resizeBuffer(GLVertexBuffer[] vbos, int newSize) - { - if (vbos.length == newSize) - { - return vbos; - } - - GLVertexBuffer[] newVbos = new GLVertexBuffer[newSize]; - System.arraycopy(vbos, 0, newVbos, 0, Math.min(vbos.length, newSize)); - if (newSize < vbos.length) - { - for (int i = newSize; i < vbos.length; i++) - { - if (vbos[i] != null) - { - vbos[i].close(); - } - } - } - return newVbos; - } - } From 586531739418328d165c1fc2ec2073afe36be823 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Tue, 23 Jul 2024 19:53:13 -0500 Subject: [PATCH 06/22] Remove deprecated LodQuadBuilder code --- .../render/bufferBuilding/ColumnBox.java | 79 +++++++++---------- .../render/bufferBuilding/LodQuadBuilder.java | 28 +------ 2 files changed, 40 insertions(+), 67 deletions(-) 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 700baa3d8..ee61960e6 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 @@ -35,6 +35,8 @@ public class ColumnBox { private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class); + + public static void addBoxQuadsToBuilder( LodQuadBuilder builder, short xSize, short ySize, short zSize, @@ -42,6 +44,10 @@ public class ColumnBox int color, byte irisBlockMaterialId, byte skyLight, byte blockLight, long topData, long bottomData, ColumnArrayView[] adjData) { + //================// + // variable setup // + //================// + short maxX = (short) (x + xSize); short maxY = (short) (minY + ySize); short maxZ = (short) (z + zSize); @@ -53,33 +59,15 @@ public class ColumnBox boolean isTopTransparent = RenderDataPointUtil.getAlpha(topData) < 255 && LodRenderer.transparencyEnabled; boolean isBottomTransparent = RenderDataPointUtil.getAlpha(bottomData) < 255 && LodRenderer.transparencyEnabled; + // if there isn't any data below this LOD, make this LOD's color opaque to prevent seeing void through transparent blocks // Note: this LOD should still be considered transparent for this method's checks, otherwise rendering bugs may occur - // FIXME this transparency change should be applied before this point since this could affect other areas - // This may also be better than handling the LOD as transparent, but that is TBD if (!RenderDataPointUtil.doesDataPointExist(bottomData)) { color = ColorUtil.setAlpha(color, 255); } - // cave culling prevention - // prevents certain faces from being culled underground that should be allowed - if (builder.skipQuadsWithZeroSkylight - && 0 == skyLight - && builder.skyLightCullingBelow > maxY - && ( - (RenderDataPointUtil.getAlpha(topData) < 255 && RenderDataPointUtil.getYMax(topData) >= builder.skyLightCullingBelow) - || (RenderDataPointUtil.getYMin(topData) >= builder.skyLightCullingBelow) - || !RenderDataPointUtil.doesDataPointExist(topData) - ) - ) - { - maxY = builder.skyLightCullingBelow; - } - - - // fake ocean transparency if (LodRenderer.transparencyEnabled && LodRenderer.fakeOceanFloor) { @@ -99,7 +87,9 @@ public class ColumnBox - // add top and bottom faces if requested // + //==========================// + // add top and bottom faces // + //==========================// boolean skipTop = RenderDataPointUtil.doesDataPointExist(topData) && (RenderDataPointUtil.getYMin(topData) == maxY) && !isTopTransparent; if (!skipTop) @@ -114,14 +104,16 @@ public class ColumnBox } - // add North, south, east, and west faces if requested // - // TODO merge duplicate code - //NORTH face vertex creation + //========================================// + // add North, south, east, and west faces // + //========================================// + + // NORTH face { - ColumnArrayView adjDataNorth = adjData[EDhDirection.NORTH.ordinal() - 2]; // TODO can we use something other than ordinal-2? - int adjOverlapNorth = ColorUtil.INVISIBLE; - if (adjDataNorth == null) + ColumnArrayView adjCol = adjData[EDhDirection.NORTH.ordinal() - 2]; // TODO can we use something other than ordinal-2? + int adjOverlapNorth = ColorUtil.INVISIBLE; // can be set to a non-invisible color for debugging overlapping quads for a specific face + if (adjCol == null) { // add an adjacent face if this is opaque face or transparent over the void if (!isTransparent || overVoid) @@ -131,49 +123,49 @@ public class ColumnBox } else { - makeAdjVerticalQuad(builder, adjDataNorth, EDhDirection.NORTH, x, minY, z, xSize, ySize, + makeAdjVerticalQuad(builder, adjCol, EDhDirection.NORTH, x, minY, z, xSize, ySize, color, adjOverlapNorth, irisBlockMaterialId, skyLightTop, blockLight, topData, bottomData); } } - //SOUTH face vertex creation + // SOUTH face { - ColumnArrayView adjDataSouth = adjData[EDhDirection.SOUTH.ordinal() - 2]; + ColumnArrayView adjCol = adjData[EDhDirection.SOUTH.ordinal() - 2]; int adjOverlapSouth = ColorUtil.INVISIBLE; - if (adjDataSouth == null) + if (adjCol == null) { if (!isTransparent || overVoid) builder.addQuadAdj(EDhDirection.SOUTH, x, minY, maxZ, xSize, ySize, color, irisBlockMaterialId, LodUtil.MAX_MC_LIGHT, blockLight); } else { - makeAdjVerticalQuad(builder, adjDataSouth, EDhDirection.SOUTH, x, minY, maxZ, xSize, ySize, + makeAdjVerticalQuad(builder, adjCol, EDhDirection.SOUTH, x, minY, maxZ, xSize, ySize, color, adjOverlapSouth, irisBlockMaterialId, skyLightTop, blockLight, topData, bottomData); } } - //WEST face vertex creation + // WEST face { - ColumnArrayView adjDataWest = adjData[EDhDirection.WEST.ordinal() - 2]; + ColumnArrayView adjCol = adjData[EDhDirection.WEST.ordinal() - 2]; int adjOverlapWest = ColorUtil.INVISIBLE; - if (adjDataWest == null) + if (adjCol == null) { if (!isTransparent || overVoid) builder.addQuadAdj(EDhDirection.WEST, x, minY, z, zSize, ySize, color, irisBlockMaterialId, LodUtil.MAX_MC_LIGHT, blockLight); } else { - makeAdjVerticalQuad(builder, adjDataWest, EDhDirection.WEST, x, minY, z, zSize, ySize, + makeAdjVerticalQuad(builder, adjCol, EDhDirection.WEST, x, minY, z, zSize, ySize, color, adjOverlapWest, irisBlockMaterialId, skyLightTop, blockLight, topData, bottomData); } } - //EAST face vertex creation + // EAST face { - ColumnArrayView adjDataEast = adjData[EDhDirection.EAST.ordinal() - 2]; + ColumnArrayView adjCol = adjData[EDhDirection.EAST.ordinal() - 2]; int adjOverlapEast = ColorUtil.INVISIBLE; if (adjData[EDhDirection.EAST.ordinal() - 2] == null) { @@ -182,7 +174,7 @@ public class ColumnBox } else { - makeAdjVerticalQuad(builder, adjDataEast, EDhDirection.EAST, maxX, minY, z, zSize, ySize, + makeAdjVerticalQuad(builder, adjCol, EDhDirection.EAST, maxX, minY, z, zSize, ySize, color, adjOverlapEast, irisBlockMaterialId, skyLightTop, blockLight, topData, bottomData); } @@ -356,7 +348,7 @@ public class ColumnBox if (yMax <= adjYMax) { // The input face is completely inside the adj's face, don't render it - if (debugOverlapColor != 0) + if (debugOverlapColor != ColorUtil.INVISIBLE) { builder.addQuadAdj(direction, x, yMin, z, horizontalWidth, ySize, debugOverlapColor, irisBlockMaterialId, LodUtil.MAX_MC_LIGHT, LodUtil.MAX_MC_LIGHT); } @@ -365,7 +357,7 @@ public class ColumnBox { // the adj data intersects the lower part of the input data, don't render below the intersection - if (adjYMax > yMin && debugOverlapColor != 0) + if (adjYMax > yMin && debugOverlapColor != ColorUtil.INVISIBLE) { builder.addQuadAdj(direction, x, yMin, z, horizontalWidth, (short) (adjYMax - yMin), debugOverlapColor, irisBlockMaterialId, LodUtil.MAX_MC_LIGHT, LodUtil.MAX_MC_LIGHT); } @@ -374,6 +366,9 @@ public class ColumnBox // if there was another face finish the last one and then break if (firstFace) { + // TODO sections next to transparent (water) need to be split up + // everything works correctly with opaque water + builder.addQuadAdj(direction, x, adjYMax, z, horizontalWidth, (short) (yMax - adjYMax), color, irisBlockMaterialId, RenderDataPointUtil.getLightSky(adjPoint), blockLight); } @@ -411,7 +406,7 @@ public class ColumnBox // Basically: y _______ < yMax <= height // _______&&: y < depth < yMax // the adj data intersects the higher part of the current data - if (debugOverlapColor != 0) + if (debugOverlapColor != ColorUtil.INVISIBLE) { builder.addQuadAdj(direction, x, adjYMin, z, horizontalWidth, (short) (yMax - adjYMin), debugOverlapColor, irisBlockMaterialId, LodUtil.MAX_MC_LIGHT, LodUtil.MAX_MC_LIGHT); } @@ -422,7 +417,7 @@ public class ColumnBox { // Otherwise: y < _____ height < yMax // _______&&: y < depth ______ < yMax - if (debugOverlapColor != 0) + if (debugOverlapColor != ColorUtil.INVISIBLE) { builder.addQuadAdj(direction, x, adjYMin, z, horizontalWidth, (short) (adjYMax - adjYMin), debugOverlapColor, irisBlockMaterialId, LodUtil.MAX_MC_LIGHT, LodUtil.MAX_MC_LIGHT); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/LodQuadBuilder.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/LodQuadBuilder.java index ab3605bdd..b9db5c836 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/LodQuadBuilder.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/LodQuadBuilder.java @@ -39,8 +39,6 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapp import com.seibel.distanthorizons.coreapi.util.MathUtil; import org.apache.logging.log4j.Logger; -//TODO: Recheck this class for refactoring - /** * Used to create the quads before they are converted to render-able buffers.

* @@ -51,11 +49,6 @@ public class LodQuadBuilder private static final Logger LOGGER = DhLoggerBuilder.getLogger(); private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class); - @Deprecated - public final boolean skipQuadsWithZeroSkylight; - @Deprecated - public final short skyLightCullingBelow; - @SuppressWarnings("unchecked") private final ArrayList[] opaqueQuads = (ArrayList[]) new ArrayList[6]; @SuppressWarnings("unchecked") @@ -134,8 +127,6 @@ public class LodQuadBuilder this.transparentQuads[i] = new ArrayList<>(); } - this.skipQuadsWithZeroSkylight = false; - this.skyLightCullingBelow = 0; this.clientLevelWrapper = clientLevelWrapper; this.debugRenderingMode = Config.Client.Advanced.Debugging.debugRendering.get(); @@ -159,11 +150,6 @@ public class LodQuadBuilder throw new IllegalArgumentException("addQuadAdj() is only for adj direction! Not UP or Down!"); } - if (this.skipQuadsWithZeroSkylight && skyLight == 0 && y + widthNorthSouthOrUpDown < this.skyLightCullingBelow) - { - return; - } - BufferQuad quad = new BufferQuad(x, y, z, widthEastWest, widthNorthSouthOrUpDown, color, irisBlockMaterialId, skyLight, blockLight, dir); ArrayList quadList = (this.doTransparency && ColorUtil.getAlpha(color) < 255) ? this.transparentQuads[dir.ordinal()] : this.opaqueQuads[dir.ordinal()]; if (!quadList.isEmpty() && @@ -182,12 +168,6 @@ public class LodQuadBuilder // XZ public void addQuadUp(short x, short maxY, short z, short widthEastWest, short widthNorthSouthOrUpDown, int color, byte irisBlockMaterialId, byte skylight, byte blocklight) // TODO argument names are wrong { - // cave culling - if (this.skipQuadsWithZeroSkylight && skylight == 0 && maxY < this.skyLightCullingBelow) - { - return; - } - BufferQuad quad = new BufferQuad(x, maxY, z, widthEastWest, widthNorthSouthOrUpDown, color, irisBlockMaterialId, skylight, blocklight, EDhDirection.UP); boolean isTransparent = (this.doTransparency && ColorUtil.getAlpha(color) < 255); ArrayList quadList = isTransparent ? this.transparentQuads[EDhDirection.UP.ordinal()] : this.opaqueQuads[EDhDirection.UP.ordinal()]; @@ -209,15 +189,13 @@ public class LodQuadBuilder public void addQuadDown(short x, short y, short z, short width, short wz, int color, byte irisBlockMaterialId, byte skylight, byte blocklight) { - if (skipQuadsWithZeroSkylight && skylight == 0 && y < skyLightCullingBelow) - return; BufferQuad quad = new BufferQuad(x, y, z, width, wz, color, irisBlockMaterialId, skylight, blocklight, EDhDirection.DOWN); ArrayList qs = (doTransparency && ColorUtil.getAlpha(color) < 255) ? transparentQuads[EDhDirection.DOWN.ordinal()] : opaqueQuads[EDhDirection.DOWN.ordinal()]; - if (!qs.isEmpty() && - (qs.get(qs.size() - 1).tryMerge(quad, BufferMergeDirectionEnum.EastWest) + if (!qs.isEmpty() + && (qs.get(qs.size() - 1).tryMerge(quad, BufferMergeDirectionEnum.EastWest) || qs.get(qs.size() - 1).tryMerge(quad, BufferMergeDirectionEnum.NorthSouthOrUpDown)) - ) + ) { premergeCount++; return; From b4b1a2a5494136dbcf1c558c4a3babb330e4f4de Mon Sep 17 00:00:00 2001 From: James Seibel Date: Tue, 23 Jul 2024 20:05:41 -0500 Subject: [PATCH 07/22] remove deprecated RenderDataPointUtil logic --- .../FullDataToRenderDataTransformer.java | 2 +- .../util/RenderDataPointReducingList.java | 6 +- .../core/util/RenderDataPointUtil.java | 348 ------------------ 3 files changed, 4 insertions(+), 352 deletions(-) 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 969354f8f..08fd5c8b5 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 @@ -353,7 +353,7 @@ public class FullDataToRenderDataTransformer if (isColumnVoid) { - renderColumnData.set(0, RenderDataPointUtil.createVoidDataPoint()); + renderColumnData.set(0, RenderDataPointUtil.EMPTY_DATA); } } 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 773707bad..f401cf272 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 @@ -829,7 +829,7 @@ public class RenderDataPointReducingList int size = view.size(); if (size <= 0) { - return RenderDataPointUtil.createVoidDataPoint(); + return RenderDataPointUtil.EMPTY_DATA; } long highestDataPoint; @@ -849,7 +849,7 @@ public class RenderDataPointReducingList } } //no visible segments, return void. - return RenderDataPointUtil.createVoidDataPoint(); + return RenderDataPointUtil.EMPTY_DATA; } //second loop: merge the rest of the segments. @@ -889,7 +889,7 @@ public class RenderDataPointReducingList // so, if we didn't set any data points, add a void data point. if (writeIndex == 0) { - view.set(writeIndex++, RenderDataPointUtil.createVoidDataPoint()); + view.set(writeIndex++, RenderDataPointUtil.EMPTY_DATA); } for (int size = view.size(); writeIndex < size; writeIndex++) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/RenderDataPointUtil.java b/core/src/main/java/com/seibel/distanthorizons/core/util/RenderDataPointUtil.java index 757aec211..042021ef8 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/util/RenderDataPointUtil.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/util/RenderDataPointUtil.java @@ -110,8 +110,6 @@ public class RenderDataPointUtil // datapoint manipulation // //========================// - public static long createVoidDataPoint() { return EMPTY_DATA; } - public static long createDataPoint(int height, int depth, int color, int lightSky, int lightBlock, int irisBlockMaterialId) { return createDataPoint( @@ -303,352 +301,6 @@ public class RenderDataPointUtil list.reduce(output.verticalSize()); list.copyTo(output); } - - - //old logic left here in case it's ever needed again. - /* - if (output.dataCount() != 1) - { - throw new IllegalArgumentException("output must be only reserved for one datapoint!"); - } - - int inputVerticalSize = sourceData.verticalSize(); - int outputVerticalSize = output.verticalSize(); - output.fill(0); - - //dataCount indicate how many position we are merging in one position - int dataCount = sourceData.dataCount(); - - // We initialize the arrays that are going to be used - int heightAndDepthLength = (MAX_WORLD_Y_SIZE / 2 + 16) * 2; - short[] heightAndDepth = tLocalHeightAndDepth.get(); - if (heightAndDepth == null || heightAndDepth.length != heightAndDepthLength) - { - heightAndDepth = new short[heightAndDepthLength]; - tLocalHeightAndDepth.set(heightAndDepth); - } - - byte genMode = getGenerationMode(sourceData.get(0)); - if (genMode == 0) - { - genMode = 1; // FIXME: Hack to make the version 10 genMode never be 0. - } - - boolean allEmpty = true; - boolean allVoid = true; - boolean limited = false; - boolean allDefault; - long singleData; - - short yMin; - short yMax; - int count = 0; - int i; - int ii; - - int[] indices = tLocalIndices.get(); - if (indices == null || indices.length != dataCount) - { - indices = new int[dataCount]; - tLocalIndices.set(indices); - } - Arrays.fill(indices, 0); - - boolean[] increaseIndex = tLocalIncreaseIndex.get(); - if (increaseIndex == null || increaseIndex.length != dataCount) - { - increaseIndex = new boolean[dataCount]; - tLocalIncreaseIndex.set(increaseIndex); - } - - boolean[] indexHandled = tLocalIndexHandled.get(); - if (indexHandled == null || indexHandled.length != dataCount) - { - indexHandled = new boolean[dataCount]; - tLocalIndexHandled.set(indexHandled); - } - - long tempData; - for (int index = 0; index < dataCount; index++) - { - tempData = sourceData.get(index * inputVerticalSize); - allVoid = allVoid && RenderDataPointUtil.isVoid(tempData); - allEmpty = allEmpty && !RenderDataPointUtil.doesDataPointExist(tempData); - } - - //We check if there is any data that's not empty or void - if (allEmpty) - { - return; - } - else if (allVoid) - { - output.set(0, createVoidDataPoint(genMode)); - return; - } - - //this check is used only to see if we have checked all the values in the array - boolean stillHasDataToCheck = true; - short prevDepth; - - while (stillHasDataToCheck) - { - Arrays.fill(indexHandled, false); - boolean connected = true; - int newHeight = -10000; - int newDepth = -10000; - int tempYMax; - int tempYMin; - while (connected) - { - Arrays.fill(increaseIndex, false); - for (int index = 0; index < dataCount; index++) - { - if (indices[index] < inputVerticalSize) - { - tempData = sourceData.get(index * inputVerticalSize + indices[index]); - if (!RenderDataPointUtil.isVoid(tempData) && RenderDataPointUtil.doesDataPointExist(tempData)) - { - tempYMax = RenderDataPointUtil.getYMax(tempData); - tempYMin = RenderDataPointUtil.getYMin(tempData); - if (tempYMin >= newHeight) - { - //First case - //the column we are checking is higher than the current column - newDepth = tempYMin; - newHeight = tempYMax; - Arrays.fill(increaseIndex, false); - Arrays.fill(indexHandled, false); - increaseIndex[index] = true; - indexHandled[index] = true; - } - else if ((tempYMin >= newDepth) && (tempYMax <= newHeight)) - { - //the column we are checking is contained in the current column - //we simply increase this index - increaseIndex[index] = true; - indexHandled[index] = true; - } - else if (tempYMax > newHeight && tempYMin <= newDepth) - { - newDepth = tempYMin; - newHeight = tempYMax; - increaseIndex[index] = true; - indexHandled[index] = true; - } - else if (tempYMax > newDepth && tempYMax <= newHeight) - { - //the column we are checking touches the current column from the bottom - //for this reason we extend what's below - - //We want to avoid to expend this column if it has already been expanded by - //this index - if (!indexHandled[index]) - { - newDepth = tempYMin; - increaseIndex[index] = true; - indexHandled[index] = true; - } - - } - else if (tempYMin < newHeight && tempYMin > newDepth) - { - //the column we are checking touches the current column from the top - //for this reason we extend the top - newHeight = tempYMax; - increaseIndex[index] = true; - } - } - else - { - indexHandled[index] = true; - } - } - } - - //if we added any new data there is a chance that we could add more - //for this reason we would continue - //if no data is added than the column hasn't changed. - //for this reason we can start working on a new column - connected = false; - for (int index = 0; index < dataCount; index++) - { - if (increaseIndex[index]) - { - connected = true; - indices[index]++; - } - } - } - - //Now we add the height and depth data we extracted to the heightAndDepth array - if (newDepth != newHeight) - { - if (count != 0) - { - prevDepth = heightAndDepth[(count - 1) * 2 + 1]; - if (newHeight > prevDepth) - { - newHeight = (short) Math.min(newHeight, prevDepth); - } - } - heightAndDepth[count * 2] = (short) newHeight; - heightAndDepth[count * 2 + 1] = (short) newDepth; - count++; - } - - //Here we check the condition that makes the loop continue - //We stop the loop only if there is no more data to check - stillHasDataToCheck = false; - for (int index = 0; index < dataCount; index++) - { - if (indices[index] < inputVerticalSize) - { - tempData = sourceData.get(index * inputVerticalSize + indices[index]); - stillHasDataToCheck |= !RenderDataPointUtil.isVoid(tempData) && RenderDataPointUtil.doesDataPointExist(tempData); - } - } - } - - //we limit the vertical portion to maxVerticalData - int j = 0; - while (count > outputVerticalSize) - { - limited = true; - ii = MAX_WORLD_Y_SIZE; - for (i = 0; i < count - 1; i++) - { - if (heightAndDepth[i * 2 + 1] - heightAndDepth[(i + 1) * 2] <= ii) - { - ii = heightAndDepth[i * 2 + 1] - heightAndDepth[(i + 1) * 2]; - j = i; - } - } - - heightAndDepth[j * 2 + 1] = heightAndDepth[(j + 1) * 2 + 1]; - for (i = j + 1; i < count - 1; i++) - { - heightAndDepth[i * 2] = heightAndDepth[(i + 1) * 2]; - heightAndDepth[i * 2 + 1] = heightAndDepth[(i + 1) * 2 + 1]; - } - - //System.arraycopy(heightAndDepth, j + 1, heightAndDepth, j, count - j - 1); - count--; - } - //As standard the vertical lods are ordered from top to bottom - - if (!limited && dataCount == 1) // This mean source vertSize < output vertSize AND both dataCount == 1 - { - sourceData.copyTo(output.data, output.offset, output.vertSize); - } - else - { - - //We want to efficiently memorize indexes - int[] dataIndexesCache = tDataIndexCache.get(); - if (dataIndexesCache == null || dataIndexesCache.length != dataCount) - { - dataIndexesCache = new int[dataCount]; - tDataIndexCache.set(dataIndexesCache); - } - Arrays.fill(dataIndexesCache, 0); - - - //For each lod height-depth value we have found we now want to generate the rest of the data - //by merging all lods at lower level that are contained inside the new ones - for (j = 0; j < count; j++) - { - //We firstly collect height and depth data - //this will be added to each realtive long DataPoint - yMax = heightAndDepth[j * 2]; - yMin = heightAndDepth[j * 2 + 1]; - - //if both height and depth are at 0 then we finished - if ((yMin == 0 && yMax == 0) || j >= heightAndDepth.length / 2) - { - break; - } - - //We initialize data useful for the merge - int numberOfChildren = 0; - allEmpty = true; - allVoid = true; - - //We initialize all the new values that we are going to put in the dataPoint - int tempAlpha = 0; - int tempRed = 0; - int tempGreen = 0; - int tempBlue = 0; - int tempLightBlock = 0; - int tempLightSky = 0; - long data = 0; - - //For each position that we want to merge - for (int index = 0; index < dataCount; index++) - { - //we scan the lods in the position from top to bottom - while (dataIndexesCache[index] < inputVerticalSize) - { - singleData = sourceData.get(index * inputVerticalSize + dataIndexesCache[index]); - if (doesDataPointExist(singleData) && !isVoid(singleData)) - { - dataIndexesCache[index]++; - if ((yMin <= getYMin(singleData) && getYMin(singleData) < yMax) - || (yMin < getYMax(singleData) && getYMax(singleData) <= yMax)) - { - data = singleData; - break; - } - } - else - { - break; - } - } - - if (!doesDataPointExist(data)) - { - data = createVoidDataPoint(genMode); - } - - if (doesDataPointExist(data)) - { - allEmpty = false; - if (!isVoid(data)) - { - numberOfChildren++; - allVoid = false; - tempAlpha = Math.max(getAlpha(data), tempAlpha); - tempRed += getRed(data) * getRed(data); - tempGreen += getGreen(data) * getGreen(data); - tempBlue += getBlue(data) * getBlue(data); - tempLightBlock += getLightBlock(data); - tempLightSky += getLightSky(data); - } - } - } - - //we have at least 1 child - if (dataCount != 1) - { - tempRed = tempRed / numberOfChildren; - tempGreen = tempGreen / numberOfChildren; - tempBlue = tempBlue / numberOfChildren; - tempLightBlock = tempLightBlock / numberOfChildren; - tempLightSky = tempLightSky / numberOfChildren; - } - - //data = createDataPoint(tempAlpha, tempRed, tempGreen, tempBlue, height, depth, tempLightSky, tempLightBlock, tempGenMode, allDefault); - //if (j > 0 && getColor(data) == getColor(dataPoint[j])) - //{ - // add simplification at the end due to color - //} - - output.set(j, createDataPoint(tempAlpha, (int) Math.sqrt(tempRed), (int) Math.sqrt(tempGreen), (int) Math.sqrt(tempBlue), yMax, yMin, tempLightSky, tempLightBlock, genMode)); - - } - } - */ } } \ No newline at end of file From 2763a7ca751cf13e9626cd2b57a5c4c0ef29d20d Mon Sep 17 00:00:00 2001 From: James Seibel Date: Tue, 23 Jul 2024 20:41:22 -0500 Subject: [PATCH 08/22] add missing brackets --- .../core/dataObjects/render/bufferBuilding/ColumnBox.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) 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 ee61960e6..7f068cab5 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 @@ -136,7 +136,9 @@ public class ColumnBox if (adjCol == null) { if (!isTransparent || overVoid) + { builder.addQuadAdj(EDhDirection.SOUTH, x, minY, maxZ, xSize, ySize, color, irisBlockMaterialId, LodUtil.MAX_MC_LIGHT, blockLight); + } } else { @@ -153,7 +155,9 @@ public class ColumnBox if (adjCol == null) { if (!isTransparent || overVoid) + { builder.addQuadAdj(EDhDirection.WEST, x, minY, z, zSize, ySize, color, irisBlockMaterialId, LodUtil.MAX_MC_LIGHT, blockLight); + } } else { @@ -170,7 +174,9 @@ public class ColumnBox if (adjData[EDhDirection.EAST.ordinal() - 2] == null) { if (!isTransparent || overVoid) + { builder.addQuadAdj(EDhDirection.EAST, maxX, minY, z, zSize, ySize, color, irisBlockMaterialId, LodUtil.MAX_MC_LIGHT, blockLight); + } } else { @@ -181,7 +187,7 @@ public class ColumnBox } } - // the overlap color can be used to see faces that shouldn't be rendered + /** the overlap color can be used to see faces that shouldn't be rendered */ private static void makeAdjVerticalQuad( LodQuadBuilder builder, ColumnArrayView adjColumnView, EDhDirection direction, short x, short yMin, short z, short horizontalWidth, short ySize, From b1b487e63f41bd3efc8e282499a3050cba07895c Mon Sep 17 00:00:00 2001 From: James Seibel Date: Wed, 24 Jul 2024 06:46:28 -0500 Subject: [PATCH 09/22] Improve RenderDataPointUtil toString() --- .../seibel/distanthorizons/core/util/RenderDataPointUtil.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/RenderDataPointUtil.java b/core/src/main/java/com/seibel/distanthorizons/core/util/RenderDataPointUtil.java index 042021ef8..fb8faa06c 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/util/RenderDataPointUtil.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/util/RenderDataPointUtil.java @@ -19,6 +19,7 @@ package com.seibel.distanthorizons.core.util; +import com.seibel.distanthorizons.api.enums.rendering.EDhApiBlockMaterial; import com.seibel.distanthorizons.core.level.AbstractDhLevel; import com.seibel.distanthorizons.core.logging.SpamReducedLogger; import com.seibel.distanthorizons.core.dataObjects.render.columnViews.ColumnArrayView; @@ -247,7 +248,7 @@ public class RenderDataPointUtil getBlue(dataPoint) + " BL:" + getLightBlock(dataPoint) + " SL:" + getLightSky(dataPoint) + - " BID:" + getBlockMaterialId(dataPoint); + " MAT:" + getBlockMaterialId(dataPoint) + "["+ EDhApiBlockMaterial.getFromIndex(getBlockMaterialId(dataPoint))+"]"; } } From 1ed6c619d9a33ac344175d5de64e542b56117139 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 27 Jul 2024 08:26:46 -0500 Subject: [PATCH 10/22] Add localization for new column builder debug options --- .../assets/distanthorizons/lang/en_us.json | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/core/src/main/resources/assets/distanthorizons/lang/en_us.json b/core/src/main/resources/assets/distanthorizons/lang/en_us.json index 8918f8820..6399f811a 100644 --- a/core/src/main/resources/assets/distanthorizons/lang/en_us.json +++ b/core/src/main/resources/assets/distanthorizons/lang/en_us.json @@ -491,14 +491,20 @@ "distanthorizons.config.client.advanced.debugging.allowUnsafeValues.@tooltip": "If enabled, very limited config input validation will be performed. \n\nWarning: enabling this can cause instability or crashing, use at your own risk. \nNote: this option isn't saved between sessions.", - "distanthorizons.config.client.advanced.debugging.columnBuilderDebugEnable": + "distanthorizons.config.client.advanced.debugging.columnBuilderDebugEnable": "Enable Column Builder Limiting", - "distanthorizons.config.client.advanced.debugging.columnBuilderDebugDetailLevel": + "distanthorizons.config.client.advanced.debugging.columnBuilderDebugDetailLevel": "Column Builder Limit - Detail Level", - "distanthorizons.config.client.advanced.debugging.columnBuilderDebugXPos": + "distanthorizons.config.client.advanced.debugging.columnBuilderDebugXPos": "Column Builder Limit - X Pos", - "distanthorizons.config.client.advanced.debugging.columnBuilderDebugZPos": + "distanthorizons.config.client.advanced.debugging.columnBuilderDebugZPos": "Column Builder Limit - Z Pos", + "distanthorizons.config.client.advanced.debugging.columnBuilderDebugXRow": + "Column Builder Limit - X Row", + "distanthorizons.config.client.advanced.debugging.columnBuilderDebugZRow": + "Column Builder Limit - Z Row", + "distanthorizons.config.client.advanced.debugging.columnBuilderDebugColumnIndex": + "Column Builder Limit - Col Index", "distanthorizons.config.client.advanced.buffers": From 479ce8093e774ce8500f72d42c706dc6283d8c15 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 27 Jul 2024 08:28:31 -0500 Subject: [PATCH 11/22] minor cleanup/refactor --- .../core/dataObjects/render/bufferBuilding/ColumnBox.java | 2 +- .../render/bufferBuilding/ColumnRenderBufferBuilder.java | 2 +- .../core/dataObjects/transformers/LodDataBuilder.java | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) 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 7f068cab5..f859bbd4b 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 @@ -171,7 +171,7 @@ public class ColumnBox { ColumnArrayView adjCol = adjData[EDhDirection.EAST.ordinal() - 2]; int adjOverlapEast = ColorUtil.INVISIBLE; - if (adjData[EDhDirection.EAST.ordinal() - 2] == null) + if (adjCol == null) { if (!isTransparent || overVoid) { 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 a398448d8..9da52fa93 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 @@ -95,7 +95,7 @@ public class ColumnRenderBufferBuilder } catch (Throwable e3) { - LOGGER.error("\"LodNodeBufferBuilder\" was unable to build quads: ", e3); + LOGGER.error("LodNodeBufferBuilder was unable to build quads for pos ["+DhSectionPos.toString(renderSource.pos)+"], error: ["+ e3.getMessage()+"].", e3); throw e3; } }, bufferBuilderExecutor) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/transformers/LodDataBuilder.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/transformers/LodDataBuilder.java index 917aad07e..6b4d1861e 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/transformers/LodDataBuilder.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/transformers/LodDataBuilder.java @@ -152,8 +152,8 @@ public class LodDataBuilder else { //we are at the height limit. There are no torches here, and sky is not obscured. - blockLight = 0; - skyLight = 15; + blockLight = LodUtil.MIN_MC_LIGHT; + skyLight = LodUtil.MAX_MC_LIGHT; } From adba3e4c15c3eeaa7adda90efbe151d9b0a27296 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 27 Jul 2024 08:40:59 -0500 Subject: [PATCH 12/22] clear testing default debug config values --- .../com/seibel/distanthorizons/core/config/Config.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java b/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java index 22fb5ce05..ec0ad8a45 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java @@ -1311,23 +1311,23 @@ public class Config .addListener(DebugColumnConfigEventHandler.INSTANCE) .build(); public static ConfigEntry columnBuilderDebugXPos = new ConfigEntry.Builder() - .set(-1) + .set(0) .setAppearance(EConfigEntryAppearance.ONLY_IN_GUI) .addListener(DebugColumnConfigEventHandler.INSTANCE) .build(); public static ConfigEntry columnBuilderDebugZPos = new ConfigEntry.Builder() - .set(-2) + .set(0) .setAppearance(EConfigEntryAppearance.ONLY_IN_GUI) .addListener(DebugColumnConfigEventHandler.INSTANCE) .build(); public static ConfigEntry columnBuilderDebugXRow = new ConfigEntry.Builder() - .set(52) + .set(-1) .setAppearance(EConfigEntryAppearance.ONLY_IN_GUI) .addListener(DebugColumnConfigEventHandler.INSTANCE) .build(); public static ConfigEntry columnBuilderDebugZRow = new ConfigEntry.Builder() - .set(14) + .set(-1) .setAppearance(EConfigEntryAppearance.ONLY_IN_GUI) .addListener(DebugColumnConfigEventHandler.INSTANCE) .build(); From 19d8c89bd8d5e157d8ce8dfe6e19a99fcec0835c Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 27 Jul 2024 09:30:41 -0500 Subject: [PATCH 13/22] Fix ice/water vertical LOD lighting --- .../render/bufferBuilding/ColumnBox.java | 425 +++++++----------- 1 file changed, 165 insertions(+), 260 deletions(-) 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 f859bbd4b..7b2037f35 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 @@ -19,23 +19,45 @@ package com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding; -import com.seibel.distanthorizons.api.enums.rendering.EDhApiBlockMaterial; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.enums.EDhDirection; 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.wrapperInterfaces.block.IBlockStateWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; import com.seibel.distanthorizons.core.dataObjects.render.columnViews.ColumnArrayView; import com.seibel.distanthorizons.core.render.renderer.LodRenderer; import com.seibel.distanthorizons.coreapi.util.MathUtil; +import java.util.Arrays; + public class ColumnBox { private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class); + /** + * if the skylight has this value that means + * no data is expected + */ + private static final byte SKYLIGHT_EMPTY = -1; + /** + * if the skylight has this value that means + * that block position is covered/occuled by an adjacent block/column. + */ + private static final byte SKYLIGHT_COVERED = -2; + private static final ThreadLocal THREAD_LOCAL_SKY_LIGHT_ARRAY = ThreadLocal.withInitial(() -> + { + byte[] array = new byte[RenderDataPointUtil.MAX_WORLD_Y_SIZE]; + Arrays.fill(array, SKYLIGHT_EMPTY); + return array; + }); + + + + //=========// + // builder // + //=========// public static void addBoxQuadsToBuilder( LodQuadBuilder builder, @@ -112,7 +134,6 @@ public class ColumnBox // NORTH face { ColumnArrayView adjCol = adjData[EDhDirection.NORTH.ordinal() - 2]; // TODO can we use something other than ordinal-2? - int adjOverlapNorth = ColorUtil.INVISIBLE; // can be set to a non-invisible color for debugging overlapping quads for a specific face if (adjCol == null) { // add an adjacent face if this is opaque face or transparent over the void @@ -124,15 +145,13 @@ public class ColumnBox else { makeAdjVerticalQuad(builder, adjCol, EDhDirection.NORTH, x, minY, z, xSize, ySize, - color, adjOverlapNorth, irisBlockMaterialId, skyLightTop, blockLight, - topData, bottomData); + color, irisBlockMaterialId, blockLight); } } // SOUTH face { ColumnArrayView adjCol = adjData[EDhDirection.SOUTH.ordinal() - 2]; - int adjOverlapSouth = ColorUtil.INVISIBLE; if (adjCol == null) { if (!isTransparent || overVoid) @@ -143,15 +162,13 @@ public class ColumnBox else { makeAdjVerticalQuad(builder, adjCol, EDhDirection.SOUTH, x, minY, maxZ, xSize, ySize, - color, adjOverlapSouth, irisBlockMaterialId, skyLightTop, blockLight, - topData, bottomData); + color, irisBlockMaterialId, blockLight); } } // WEST face { ColumnArrayView adjCol = adjData[EDhDirection.WEST.ordinal() - 2]; - int adjOverlapWest = ColorUtil.INVISIBLE; if (adjCol == null) { if (!isTransparent || overVoid) @@ -162,15 +179,13 @@ public class ColumnBox else { makeAdjVerticalQuad(builder, adjCol, EDhDirection.WEST, x, minY, z, zSize, ySize, - color, adjOverlapWest, irisBlockMaterialId, skyLightTop, blockLight, - topData, bottomData); + color, irisBlockMaterialId, blockLight); } } // EAST face { ColumnArrayView adjCol = adjData[EDhDirection.EAST.ordinal() - 2]; - int adjOverlapEast = ColorUtil.INVISIBLE; if (adjCol == null) { if (!isTransparent || overVoid) @@ -181,306 +196,196 @@ public class ColumnBox else { makeAdjVerticalQuad(builder, adjCol, EDhDirection.EAST, maxX, minY, z, zSize, ySize, - color, adjOverlapEast, irisBlockMaterialId, skyLightTop, blockLight, - topData, bottomData); + color, irisBlockMaterialId, blockLight); } } } - /** the overlap color can be used to see faces that shouldn't be rendered */ private static void makeAdjVerticalQuad( LodQuadBuilder builder, ColumnArrayView adjColumnView, EDhDirection direction, short x, short yMin, short z, short horizontalWidth, short ySize, - int color, int debugOverlapColor, byte irisBlockMaterialId, byte skyLightTop, byte blockLight, - long topData, long bottomData) + int color, byte irisBlockMaterialId, byte blockLight) { + //==================// + // create face with // + // no adjacent data // + //==================// + color = ColorUtil.applyShade(color, MC.getShade(direction)); + // if there isn't any data adjacent to this LOD, + // just add the full vertical quad if (adjColumnView == null || adjColumnView.size == 0 || RenderDataPointUtil.isVoid(adjColumnView.get(0))) { - // there isn't any data adjacent to this LOD, add the vertical quad + builder.addQuadAdj(direction, x, yMin, z, horizontalWidth, ySize, color, irisBlockMaterialId, LodUtil.MAX_MC_LIGHT, blockLight); return; } - int yMax = yMin + ySize; - int adjIndex; - boolean firstFace = true; - boolean inputAboveAdjLods = true; - short previousAdjDepth = -1; - byte nextTopSkyLight = skyLightTop; - boolean inputTransparent = ColorUtil.getAlpha(color) < 255 && LodRenderer.transparencyEnabled; - boolean lastAdjWasTransparent = false; + //===========================// + // Determine face visibility // + // based on it's neighbors // + //===========================// + short yMax = (short) (yMin + ySize); // min is inclusive, max is exclusive + byte[] skyLightAtInputPos = THREAD_LOCAL_SKY_LIGHT_ARRAY.get(); - - if (!RenderDataPointUtil.doesDataPointExist(bottomData)) + try { - // there isn't anything under this LOD, - // to prevent seeing through the world, make it opaque - color = ColorUtil.setAlpha(color, 255); - } - - - // Add adjacent faces if this LOD is surrounded by transparent LODs - // (prevents invisible sides underwater) - int adjCount = adjColumnView.size(); - for (adjIndex = 0; // iterates top down - adjIndex < adjCount - && RenderDataPointUtil.doesDataPointExist(adjColumnView.get(adjIndex)) - && !RenderDataPointUtil.isVoid(adjColumnView.get(adjIndex)); - adjIndex++) - { - long adjPoint = adjColumnView.get(adjIndex); + // set the initial sky-lights for this face, + // if nothing overlaps or overhangs the face should have max sky light + Arrays.fill(skyLightAtInputPos, yMin, yMax, LodUtil.MAX_MC_LIGHT); - // if the adjacent data point is over the void - // don't consider it as transparent - // FIXME this transparency change should be applied before this point since this could affect other areas - boolean adjOverVoid = false; - if (adjIndex > 0) + // iterate top down + int adjCount = adjColumnView.size(); + for (int adjIndex = 0; adjIndex < adjCount; adjIndex++) { - long adjBellowPoint = adjColumnView.get(adjIndex-1); - adjOverVoid = !RenderDataPointUtil.doesDataPointExist(adjBellowPoint); - } - boolean adjTransparent = !adjOverVoid && RenderDataPointUtil.getAlpha(adjPoint) < 255 && LodRenderer.transparencyEnabled; - - - // continue if this data point is transparent or the adjacent point is not - if (inputTransparent || !adjTransparent) // TODO inputIsTransparent may be unnecessary - { - short adjYMin = RenderDataPointUtil.getYMin(adjPoint); - short adjYMax = RenderDataPointUtil.getYMax(adjPoint); + long adjPoint = adjColumnView.get(adjIndex); + short adjMinY = RenderDataPointUtil.getYMin(adjPoint); + short adjMaxY = RenderDataPointUtil.getYMax(adjPoint); - - // if fake transparency is enabled, allow for 1 block of transparency, - // everything under that should be opaque - if (LodRenderer.transparencyEnabled && LodRenderer.fakeOceanFloor) + // skip empty adjacent datapoints + if (!RenderDataPointUtil.doesDataPointExist(adjPoint) + || RenderDataPointUtil.isVoid(adjPoint)) { - if (lastAdjWasTransparent && !adjTransparent) - { - adjYMax = (short) (RenderDataPointUtil.getYMax(adjColumnView.get(adjIndex - 1)) - 1); - } - else if (adjTransparent && (adjIndex + 1) < adjCount) - { - if (RenderDataPointUtil.getAlpha(adjColumnView.get(adjIndex + 1)) == 255) - { - adjYMin = (short) (adjYMax - 1); - } - } - } - - - if (yMax <= adjYMin) - { - // the adjacent LOD is above the input LOD and won't affect its rendering, - // skip to the next adjacent continue; } - inputAboveAdjLods = false; - - if (adjYMax < yMin) + // skip this adjacent datapoint if it's above the input datapoint (since it can't affect the input data point) + if (yMax <= adjMinY) { - // the adjacent LOD is below the input LOD - - // getting the skylight is more complicated - // since LODs can be adjacent to water, which changes how skylight works - byte skyLight; - if (adjIndex == 0) - { - // this adj LOD is at the highest position, - // its sky lighting won't be affected by anything above it - skyLight = RenderDataPointUtil.getLightSky(adjPoint); - } - else - { - // TODO improve the comments here, this is a bit confusing - long aboveAdjPoint = adjColumnView.get(adjIndex - 1); - if (RenderDataPointUtil.getAlpha(aboveAdjPoint) != 255) - { - // above adjacent LOD is transparent... - - boolean inputMaxHigherThanAboveAdj = yMax > RenderDataPointUtil.getYMax(aboveAdjPoint); - if (inputMaxHigherThanAboveAdj) - { - // ...and higher than the input yMax, - // use its sky light - skyLight = RenderDataPointUtil.getLightSky(aboveAdjPoint); - } - else - { - // ...and at or below the input yMax, - skyLight = RenderDataPointUtil.getLightSky(adjPoint); - } - } - else - { - // LOD above adjacent is opaque, use the adj LOD's skylight - skyLight = RenderDataPointUtil.getLightSky(adjPoint); - } - } - - - if (firstFace) - { - builder.addQuadAdj(direction, x, yMin, z, horizontalWidth, ySize, color, irisBlockMaterialId, skyLight, blockLight); - } - else - { - // Now: adjMaxHeight < y < previousAdjDepth < yMax - if (previousAdjDepth == -1) - { - // TODO why is this an error? - throw new RuntimeException("Loop error"); - } - - builder.addQuadAdj(direction, x, yMin, z, horizontalWidth, (short) (previousAdjDepth - yMin), color, irisBlockMaterialId, skyLight, blockLight); - - previousAdjDepth = -1; - } - - - // TODO why break here? - break; + continue; } - if (adjYMin <= yMin) + long adjAbovePoint = (adjIndex != 0) ? adjColumnView.get(adjIndex - 1) : RenderDataPointUtil.EMPTY_DATA; + long adjBelowPoint = (adjIndex + 1 < adjCount) ? adjColumnView.get(adjIndex + 1) : RenderDataPointUtil.EMPTY_DATA; + + // if the adjacent data point is over the void + // don't consider it as transparent + boolean adjOverVoid = !RenderDataPointUtil.doesDataPointExist(adjBelowPoint); + boolean adjTransparent = !adjOverVoid && RenderDataPointUtil.getAlpha(adjPoint) < 255 && LodRenderer.transparencyEnabled; + + + + //=================================// + // set sky light based on adjacent // + //=================================// + + // set light based on overlapping adjacent + if (!adjTransparent) { - // the adjacent LOD's base is at or below the input's base - - if (yMax <= adjYMax) + // adj opaque + // mark positions adjacent is covering + for (int i = adjMinY; i < adjMaxY; i++) { - // The input face is completely inside the adj's face, don't render it - if (debugOverlapColor != ColorUtil.INVISIBLE) - { - builder.addQuadAdj(direction, x, yMin, z, horizontalWidth, ySize, debugOverlapColor, irisBlockMaterialId, LodUtil.MAX_MC_LIGHT, LodUtil.MAX_MC_LIGHT); - } + byte skyLightAtPos = skyLightAtInputPos[i]; + skyLightAtInputPos[i] = (byte) Math.min(SKYLIGHT_COVERED, skyLightAtPos); } - else - { - // the adj data intersects the lower part of the input data, don't render below the intersection - - if (adjYMax > yMin && debugOverlapColor != ColorUtil.INVISIBLE) - { - builder.addQuadAdj(direction, x, yMin, z, horizontalWidth, (short) (adjYMax - yMin), debugOverlapColor, irisBlockMaterialId, LodUtil.MAX_MC_LIGHT, LodUtil.MAX_MC_LIGHT); - } - - // if this is the only face, use the yMax and break, - // if there was another face finish the last one and then break - if (firstFace) - { - // TODO sections next to transparent (water) need to be split up - // everything works correctly with opaque water - - builder.addQuadAdj(direction, x, adjYMax, z, horizontalWidth, (short) (yMax - adjYMax), color, irisBlockMaterialId, - RenderDataPointUtil.getLightSky(adjPoint), blockLight); - } - else - { - // Now: depth <= y <= height <= previousAdjDepth < yMax - if (previousAdjDepth == -1) - { - // TODO why is this an error? - throw new RuntimeException("Loop error"); - } - - if (previousAdjDepth > adjYMax) - { - builder.addQuadAdj(direction, x, adjYMax, z, horizontalWidth, (short) (previousAdjDepth - adjYMax), color, irisBlockMaterialId, - RenderDataPointUtil.getLightSky(adjPoint), blockLight); - } - previousAdjDepth = -1; - } - } - - - // we don't need to check any other adjacent LODs - // since this one completely covers the input - break; - } - - - - // In here always true: y < adjYMin < yMax - // _________________&&: y < ________ (height and yMax) - - if (adjYMax >= yMax) - { - // Basically: y _______ < yMax <= height - // _______&&: y < depth < yMax - // the adj data intersects the higher part of the current data - if (debugOverlapColor != ColorUtil.INVISIBLE) - { - builder.addQuadAdj(direction, x, adjYMin, z, horizontalWidth, (short) (yMax - adjYMin), debugOverlapColor, irisBlockMaterialId, LodUtil.MAX_MC_LIGHT, LodUtil.MAX_MC_LIGHT); - } - - // we start the creation of a new face } else { - // Otherwise: y < _____ height < yMax - // _______&&: y < depth ______ < yMax - if (debugOverlapColor != ColorUtil.INVISIBLE) + // adjacent is transparent, + // use datapoint below adjacent for lighting + byte belowSkyLight = RenderDataPointUtil.getLightSky(adjBelowPoint); + for (int i = adjMinY; i < adjMaxY; i++) { - builder.addQuadAdj(direction, x, adjYMin, z, horizontalWidth, (short) (adjYMax - adjYMin), debugOverlapColor, irisBlockMaterialId, LodUtil.MAX_MC_LIGHT, LodUtil.MAX_MC_LIGHT); - } - - if (firstFace) - { - builder.addQuadAdj(direction, x, adjYMax, z, horizontalWidth, (short) (yMax - adjYMax), color, irisBlockMaterialId, - RenderDataPointUtil.getLightSky(adjPoint), blockLight); - } - else - { - // Now: y < depth < height <= previousAdjDepth < yMax - if (previousAdjDepth == -1) - throw new RuntimeException("Loop error"); - if (previousAdjDepth > adjYMax) - { - if (irisBlockMaterialId == EDhApiBlockMaterial.GRASS.index) - { - // this LOD is underneath another, grass will never show here - irisBlockMaterialId = EDhApiBlockMaterial.DIRT.index; - } - - builder.addQuadAdj(direction, x, adjYMax, z, horizontalWidth, (short) (previousAdjDepth - adjYMax), color, irisBlockMaterialId, - RenderDataPointUtil.getLightSky(adjPoint), blockLight); - } - previousAdjDepth = -1; + byte skyLightAtPos = skyLightAtInputPos[i]; + skyLightAtInputPos[i] = (byte) Math.min(belowSkyLight, skyLightAtPos); } } - // set next top as current depth - previousAdjDepth = adjYMin; - firstFace = false; - nextTopSkyLight = skyLightTop; - - if (adjIndex + 1 < adjColumnView.size() && RenderDataPointUtil.doesDataPointExist(adjColumnView.get(adjIndex + 1))) + // fill in sky light up to the next DP, + // this is done to handle overhangs + byte adjSkyLight = RenderDataPointUtil.getLightSky(adjPoint); + int adjAboveMinY = RenderDataPointUtil.getYMin(adjAbovePoint); + for (int i = adjMaxY; i < adjAboveMinY; i++) { - nextTopSkyLight = RenderDataPointUtil.getLightSky(adjColumnView.get(adjIndex + 1)); + byte skyLightAtPos = skyLightAtInputPos[i]; + skyLightAtInputPos[i] = (byte) Math.min(adjSkyLight, skyLightAtPos); + } + } + + + + //=======================// + // create vertical faces // + //=======================// + + boolean inputTransparent = ColorUtil.getAlpha(color) < 255 && LodRenderer.transparencyEnabled; + byte lastSkyLight = skyLightAtInputPos[yMin]; + int quadBottomY = yMin; + int quadTopY = -1; + + // walk up the sky lights and create a new face + // whenever the light changes to different valid value + for (int i = yMin; i < yMax; i++) + { + byte skyLight = skyLightAtInputPos[i]; + if (skyLight != lastSkyLight) + { + // the sky light changed, create the in-progress face + tryAddVerticalFaceWithSkyLightToBuilder( + builder, direction, + x, z, horizontalWidth, + color, irisBlockMaterialId, blockLight, + lastSkyLight, inputTransparent, quadTopY, quadBottomY + ); + + lastSkyLight = skyLight; + quadBottomY = i; } - lastAdjWasTransparent = adjTransparent; + quadTopY = (i + 1); + } + + // add the in-progress face if present + if (quadTopY != -1) + { + tryAddVerticalFaceWithSkyLightToBuilder( + builder, direction, + x, z, horizontalWidth, + color, irisBlockMaterialId, blockLight, + lastSkyLight, inputTransparent, quadTopY, quadBottomY + ); } } - - - - if (inputAboveAdjLods) + finally { - // the input LOD is above all adjacent LODs and won't be affected - // by them, add the vertical quad using the input's lighting and height - builder.addQuadAdj(direction, x, yMin, z, horizontalWidth, ySize, color, irisBlockMaterialId, skyLightTop, blockLight); + // clean up the array before the next thread uses it + // (may be unnecessary since we only work between the yMin-yMax anyway, but is helpful for debugging) + Arrays.fill(skyLightAtInputPos, yMin, yMax, SKYLIGHT_EMPTY); } - else if (previousAdjDepth != -1) + } + private static void tryAddVerticalFaceWithSkyLightToBuilder( + LodQuadBuilder builder, EDhDirection direction, + short x, short z, short horizontalWidth, + int color, byte irisBlockMaterialId, byte blockLight, + byte lastSkyLight, boolean inputTransparent, int quadTopY, int quadBottomY + ) + { + // invalid positions will have a negative skylight + if (lastSkyLight >= 0) { - // We need to finish the last quad. - builder.addQuadAdj(direction, x, yMin, z, horizontalWidth, (short) (previousAdjDepth - yMin), color, irisBlockMaterialId, nextTopSkyLight, blockLight); + // Don't add transparent vertical faces + // unless the adjacent position is empty. + // This is done to prevent walls between water blocks in the ocean. + if (!inputTransparent + || (lastSkyLight == LodUtil.MAX_MC_LIGHT)) + { + // don't add negative/empty height faces + short height = (short) (quadTopY - quadBottomY); + if (height > 0) + { + builder.addQuadAdj(direction, x, (short) quadBottomY, z, horizontalWidth, height, color, irisBlockMaterialId, lastSkyLight, blockLight); + } + } } } + + } From 56303dd82aa579c6dd05cea2e10e6cabf338b700 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 27 Jul 2024 16:51:08 -0500 Subject: [PATCH 14/22] level wrapper renamings --- .../com/seibel/distanthorizons/core/level/DhClientLevel.java | 2 +- .../distanthorizons/core/level/DhClientServerLevel.java | 2 +- .../core/wrapperInterfaces/world/IClientLevelWrapper.java | 4 +--- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java index f29b35f21..0b5555b30 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java @@ -110,7 +110,7 @@ public class DhClientLevel extends AbstractDhLevel implements IDhClientLevel //================// @Override - public int computeBaseColor(DhBlockPos pos, IBiomeWrapper biome, IBlockStateWrapper block) { return this.levelWrapper.computeBaseColor(pos, biome, block); } + public int computeBaseColor(DhBlockPos pos, IBiomeWrapper biome, IBlockStateWrapper block) { return this.levelWrapper.getBlockColor(pos, biome, block); } @Override public IClientLevelWrapper getClientLevelWrapper() { return this.levelWrapper; } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientServerLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientServerLevel.java index c2f925bad..9d2b28bd7 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientServerLevel.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientServerLevel.java @@ -146,7 +146,7 @@ public class DhClientServerLevel extends AbstractDhLevel implements IDhClientLev } else { - return clientLevel.computeBaseColor(pos, biome, block); + return clientLevel.getBlockColor(pos, biome, block); } } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/world/IClientLevelWrapper.java b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/world/IClientLevelWrapper.java index e21cf6a8e..2870f51d4 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/world/IClientLevelWrapper.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/world/IClientLevelWrapper.java @@ -19,8 +19,6 @@ package com.seibel.distanthorizons.core.wrapperInterfaces.world; -import com.seibel.distanthorizons.core.level.IDhClientLevel; -import com.seibel.distanthorizons.core.level.IDhLevel; import com.seibel.distanthorizons.core.pos.DhBlockPos; import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper; import org.jetbrains.annotations.Nullable; @@ -34,7 +32,7 @@ public interface IClientLevelWrapper extends ILevelWrapper @Nullable IServerLevelWrapper tryGetServerSideWrapper(); - int computeBaseColor(DhBlockPos pos, IBiomeWrapper biome, IBlockStateWrapper blockState); + int getBlockColor(DhBlockPos pos, IBiomeWrapper biome, IBlockStateWrapper blockState); /** @return -1 if there was a problem getting the color */ int getDirtBlockColor(); From 53300a3028cb76907f62605e0f25a17e13599bed Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 27 Jul 2024 17:36:40 -0500 Subject: [PATCH 15/22] Update IDhApiRenderProxy.clearRenderDataCache() to also clear cached block colors --- .../api/interfaces/render/IDhApiRenderProxy.java | 8 +++----- .../core/level/ClientLevelModule.java | 2 ++ .../core/level/DhClientServerLevel.java | 5 +---- .../distanthorizons/core/render/LodQuadTree.java | 10 +++++++--- .../core/render/LodRenderSection.java | 14 ++++++++++++++ .../world/IClientLevelWrapper.java | 2 +- 6 files changed, 28 insertions(+), 13 deletions(-) diff --git a/api/src/main/java/com/seibel/distanthorizons/api/interfaces/render/IDhApiRenderProxy.java b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/render/IDhApiRenderProxy.java index 3401835d9..fc5243575 100644 --- a/api/src/main/java/com/seibel/distanthorizons/api/interfaces/render/IDhApiRenderProxy.java +++ b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/render/IDhApiRenderProxy.java @@ -26,7 +26,7 @@ import com.seibel.distanthorizons.api.objects.DhApiResult; * Used to interact with Distant Horizons' rendering system. * * @author James Seibel - * @version 2023-10-13 + * @version 2024-7-27 * @since API 1.0.0 */ public interface IDhApiRenderProxy @@ -39,10 +39,8 @@ public interface IDhApiRenderProxy * If this is called on a dedicated server it won't do anything and will return {@link DhApiResult#success} = false

* * Background:
- * Distant Horizons has two different file formats: Full data and Render data.
- * - Full data files store the block, biome, etc. information and is the result of loading or generating new chunks.
- * - Render data files store LOD colors and are created using the Full data and currently loaded resource packs.
- * This is the data cleared by this method. + * When rendering Distant Horizons bakes each block's color into the geometry that's rendered.
+ * This improves rendering speed and VRAM size, but prevents dynamically changing LOD colors.
*/ DhApiResult clearRenderDataCache(); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/ClientLevelModule.java b/core/src/main/java/com/seibel/distanthorizons/core/level/ClientLevelModule.java index 99dd8fcf7..3ad478be2 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/ClientLevelModule.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/ClientLevelModule.java @@ -258,6 +258,8 @@ public class ClientLevelModule implements Closeable, AbstractDataSourceHandler.I public void clearRenderCache() { + this.clientLevel.getClientLevelWrapper().clearBlockColorCache(); + ClientRenderState ClientRenderState = this.ClientRenderStateRef.get(); if (ClientRenderState != null && ClientRenderState.quadtree != null) { diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientServerLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientServerLevel.java index 9d2b28bd7..b9357e6ff 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientServerLevel.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientServerLevel.java @@ -154,10 +154,7 @@ public class DhClientServerLevel extends AbstractDhLevel implements IDhClientLev public IClientLevelWrapper getClientLevelWrapper() { return MC_CLIENT.getWrappedClientLevel(); } @Override - public void clearRenderCache() - { - clientside.clearRenderCache(); - } + public void clearRenderCache() { this.clientside.clearRenderCache(); } @Override public IServerLevelWrapper getServerLevelWrapper() { return serverLevelWrapper; } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/LodQuadTree.java b/core/src/main/java/com/seibel/distanthorizons/core/render/LodQuadTree.java index ffadc3c9d..943f688c3 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/LodQuadTree.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/LodQuadTree.java @@ -151,7 +151,7 @@ public class LodQuadTree extends QuadTree implements IDebugRen } catch (Exception e) { - LOGGER.error("Quad Tree tick exception for dimension: " + this.level.getClientLevelWrapper().getDimensionType().getDimensionName() + ", exception: " + e.getMessage(), e); + LOGGER.error("Quad Tree tick exception for dimension: " + this.level.getLevelWrapper().getDimensionType().getDimensionName() + ", exception: " + e.getMessage(), e); } finally { @@ -515,8 +515,12 @@ public class LodQuadTree extends QuadTree implements IDebugRen QuadNode quadNode = nodeIterator.next(); if (quadNode.value != null) { - quadNode.value.close(); - quadNode.value = null; + if (quadNode.value.renderingEnabled) + { + quadNode.value.cancelGpuUpload(); + quadNode.value.uploadRenderDataToGpuAsync(); + } + } } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/LodRenderSection.java b/core/src/main/java/com/seibel/distanthorizons/core/render/LodRenderSection.java index bacd2eb7b..bfb93eccf 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/LodRenderSection.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/LodRenderSection.java @@ -306,6 +306,20 @@ public class LodRenderSection implements IDebugRenderable, AutoCloseable } + /** + * Note: can cause issues with neighboring LOD sections + * if only some (vs all) futures are canceled. + */ + public void cancelGpuUpload() + { + CompletableFuture future = this.uploadRenderDataToGpuFuture; + if (future != null) + { + future.cancel(true); + } + } + + //========================// // getters and properties // diff --git a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/world/IClientLevelWrapper.java b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/world/IClientLevelWrapper.java index 2870f51d4..742cefea0 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/world/IClientLevelWrapper.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/world/IClientLevelWrapper.java @@ -33,9 +33,9 @@ public interface IClientLevelWrapper extends ILevelWrapper IServerLevelWrapper tryGetServerSideWrapper(); int getBlockColor(DhBlockPos pos, IBiomeWrapper biome, IBlockStateWrapper blockState); - /** @return -1 if there was a problem getting the color */ int getDirtBlockColor(); + void clearBlockColorCache(); /** Will return null if there was an issue finding the biome. */ @Nullable From d0dd1f38ffaa9f5d319e4f59ddca3d2a83114e54 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 27 Jul 2024 20:11:00 -0500 Subject: [PATCH 16/22] Fix LODs flashing twice when changing configs --- .../seibel/distanthorizons/core/render/LodQuadTree.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/LodQuadTree.java b/core/src/main/java/com/seibel/distanthorizons/core/render/LodQuadTree.java index 943f688c3..8fff11828 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/LodQuadTree.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/LodQuadTree.java @@ -74,7 +74,6 @@ public class LodQuadTree extends QuadTree implements IDebugRen */ private final ConcurrentLinkedQueue sectionsToReload = new ConcurrentLinkedQueue<>(); private final IDhClientLevel level; //FIXME: Proper hierarchy to remove this reference! - private final ConfigChangeListener horizontalScaleChangeListener; private final ReentrantLock treeReadWriteLock = new ReentrantLock(); private final AtomicBoolean fullDataRetrievalQueueRunning = new AtomicBoolean(false); @@ -110,8 +109,6 @@ public class LodQuadTree extends QuadTree implements IDebugRen this.level = level; this.fullDataSourceProvider = fullDataSourceProvider; this.blockRenderDistanceDiameter = viewDiameterInBlocks; - - this.horizontalScaleChangeListener = new ConfigChangeListener<>(Config.Client.Advanced.Graphics.Quality.horizontalQuality, (newHorizontalScale) -> this.onHorizontalQualityChange()); } @@ -619,7 +616,7 @@ public class LodQuadTree extends QuadTree implements IDebugRen // config listeners // //==================// - private void onHorizontalQualityChange() { this.clearRenderDataCache(); } + private void onHorizontalQualityChange() { /*this.clearRenderDataCache();*/ } //===========// @@ -682,8 +679,6 @@ public class LodQuadTree extends QuadTree implements IDebugRen { LOGGER.info("Shutting down " + LodQuadTree.class.getSimpleName() + "..."); - this.horizontalScaleChangeListener.close(); - DebugRenderer.unregister(this, Config.Client.Advanced.Debugging.DebugWireframe.showQuadTreeRenderStatus); Iterator> nodeIterator = this.nodeIterator(); From d3d166dd0277e7042786d6694fa07a5820446452 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 27 Jul 2024 20:11:28 -0500 Subject: [PATCH 17/22] Undo experimental change to LOD reloading --- .../seibel/distanthorizons/core/render/LodQuadTree.java | 8 ++------ .../distanthorizons/core/render/LodRenderSection.java | 5 ++++- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/LodQuadTree.java b/core/src/main/java/com/seibel/distanthorizons/core/render/LodQuadTree.java index 8fff11828..3bbeda893 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/LodQuadTree.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/LodQuadTree.java @@ -512,12 +512,8 @@ public class LodQuadTree extends QuadTree implements IDebugRen QuadNode quadNode = nodeIterator.next(); if (quadNode.value != null) { - if (quadNode.value.renderingEnabled) - { - quadNode.value.cancelGpuUpload(); - quadNode.value.uploadRenderDataToGpuAsync(); - } - + quadNode.value.close(); + quadNode.value = null; } } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/LodRenderSection.java b/core/src/main/java/com/seibel/distanthorizons/core/render/LodRenderSection.java index bfb93eccf..6946365ab 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/LodRenderSection.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/LodRenderSection.java @@ -313,9 +313,12 @@ public class LodRenderSection implements IDebugRenderable, AutoCloseable public void cancelGpuUpload() { CompletableFuture future = this.uploadRenderDataToGpuFuture; + this.uploadRenderDataToGpuFuture = null; if (future != null) { - future.cancel(true); + // interrupting the future speeds things up, but also causes + // some LODs to never load in properly + future.cancel(false); } } From dbe0461d5f34545514d38b92f348d23337e7843b Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 27 Jul 2024 20:25:55 -0500 Subject: [PATCH 18/22] Fix LOD upload warning --- .../render/bufferBuilding/ColumnRenderBuffer.java | 4 ++-- .../bufferBuilding/ColumnRenderBufferBuilder.java | 13 +++++++++---- .../core/render/LodRenderSection.java | 5 +++-- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnRenderBuffer.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnRenderBuffer.java index 81694c8a6..cea580bc5 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnRenderBuffer.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnRenderBuffer.java @@ -19,6 +19,7 @@ package com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding; +import com.seibel.distanthorizons.api.DhApi; import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam; import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; @@ -30,7 +31,6 @@ import com.seibel.distanthorizons.core.render.renderer.LodRenderer; import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.util.objects.StatsMap; import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod; -import com.seibel.distanthorizons.core.util.*; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; import org.apache.logging.log4j.Logger; @@ -91,7 +91,7 @@ public class ColumnRenderBuffer implements AutoCloseable /** Should be run on a DH thread. */ public void uploadBuffer(LodQuadBuilder builder, EDhApiGpuUploadMethod gpuUploadMethod) throws InterruptedException { - LodUtil.assertTrue(Thread.currentThread().getName().startsWith(ThreadUtil.THREAD_NAME_PREFIX), "Buffer uploading needs to be done on a DH thread to prevent locking up any MC threads."); + LodUtil.assertTrue(DhApi.isDhThread(), "Buffer uploading needs to be done on a DH thread to prevent locking up any MC threads."); // upload on MC's render thread 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 9da52fa93..377da1971 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 @@ -28,10 +28,8 @@ import com.seibel.distanthorizons.core.level.IDhClientLevel; import com.seibel.distanthorizons.core.logging.ConfigBasedLogger; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.pos.DhBlockPos; -import com.seibel.distanthorizons.core.pos.DhLodPos; import com.seibel.distanthorizons.core.pos.DhSectionPos; import com.seibel.distanthorizons.core.render.glObject.GLProxy; -import com.seibel.distanthorizons.core.render.glObject.buffer.GLVertexBuffer; import com.seibel.distanthorizons.core.util.ColorUtil; import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.util.RenderDataPointUtil; @@ -107,8 +105,15 @@ public class ColumnRenderBufferBuilder try { buffer.uploadBuffer(quadBuilder, GLProxy.getInstance().getGpuUploadMethod()); - LodUtil.assertTrue(buffer.buffersUploaded); - return buffer; + if (buffer.buffersUploaded) + { + return buffer; + } + else + { + buffer.close(); + return null; + } } catch (Exception e) { diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/LodRenderSection.java b/core/src/main/java/com/seibel/distanthorizons/core/render/LodRenderSection.java index 6946365ab..5ebda91bf 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/LodRenderSection.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/LodRenderSection.java @@ -188,11 +188,12 @@ public class LodRenderSection implements IDebugRenderable, AutoCloseable { adjacentRenderSections[i] = adjLoadRefFutures[i].future.getNow(null); } - ColumnRenderBufferBuilder.buildAndUploadBuffersAsync(this.level, renderSource, adjacentRenderSections).thenAccept((buffer) -> + ColumnRenderBufferBuilder.buildAndUploadBuffersAsync(this.level, renderSource, adjacentRenderSections) + .thenAccept((buffer) -> { // upload complete, clean up the old data if this.renderBuffer = buffer; - this.canRender = true; + this.canRender = (buffer != null); this.uploadRenderDataToGpuFuture = null; From 882c5399bdab14496104a63f71600e465da69e9e Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 27 Jul 2024 21:06:50 -0500 Subject: [PATCH 19/22] Fix holes in LODs boarding different detail levels --- .../render/bufferBuilding/ColumnBox.java | 10 +++++++--- .../ColumnRenderBufferBuilder.java | 9 +-------- .../core/render/LodQuadTree.java | 2 +- .../core/render/LodRenderSection.java | 17 ++++++++++++++--- 4 files changed, 23 insertions(+), 15 deletions(-) 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 7b2037f35..1e063355f 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 @@ -28,6 +28,7 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftCli import com.seibel.distanthorizons.core.dataObjects.render.columnViews.ColumnArrayView; import com.seibel.distanthorizons.core.render.renderer.LodRenderer; import com.seibel.distanthorizons.coreapi.util.MathUtil; +import org.jetbrains.annotations.NotNull; import java.util.Arrays; @@ -134,9 +135,12 @@ public class ColumnBox // NORTH face { ColumnArrayView adjCol = adjData[EDhDirection.NORTH.ordinal() - 2]; // TODO can we use something other than ordinal-2? + // if the adjacent column is null that generally means it's representing a different detail level if (adjCol == null) { - // add an adjacent face if this is opaque face or transparent over the void + // Add an adjacent face if this is opaque face or transparent over the void. + // By skipping transparent faces that aren't over the void we prevent adding ocean faces + // between detail levels. if (!isTransparent || overVoid) { builder.addQuadAdj(EDhDirection.NORTH, x, minY, z, xSize, ySize, color, irisBlockMaterialId, LodUtil.MAX_MC_LIGHT, blockLight); @@ -202,7 +206,7 @@ public class ColumnBox } private static void makeAdjVerticalQuad( - LodQuadBuilder builder, ColumnArrayView adjColumnView, EDhDirection direction, + LodQuadBuilder builder, @NotNull ColumnArrayView adjColumnView, EDhDirection direction, short x, short yMin, short z, short horizontalWidth, short ySize, int color, byte irisBlockMaterialId, byte blockLight) { @@ -215,7 +219,7 @@ public class ColumnBox // if there isn't any data adjacent to this LOD, // just add the full vertical quad - if (adjColumnView == null || adjColumnView.size == 0 || RenderDataPointUtil.isVoid(adjColumnView.get(0))) + if (adjColumnView.size == 0 || RenderDataPointUtil.isVoid(adjColumnView.get(0))) { builder.addQuadAdj(direction, x, yMin, z, horizontalWidth, ySize, color, irisBlockMaterialId, LodUtil.MAX_MC_LIGHT, 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 377da1971..def8f252c 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 @@ -61,6 +61,7 @@ public class ColumnRenderBufferBuilder // vbo building // //==============// + /** @link adjData should be null for adjacent sections that cross detail level boundaries */ public static CompletableFuture buildAndUploadBuffersAsync( IDhClientLevel clientLevel, ColumnRenderSource renderSource, ColumnRenderSource[] adjData) @@ -277,14 +278,6 @@ public class ColumnRenderBufferBuilder zAdj -= ColumnRenderSource.SECTION_SIZE; } } - else - { - // TODO: handle adjacent sections with a lower detail level - // if not handled sometimes holes will appear on the boarder - // between high and low detail sections, - // since the low detail section assumes it is next to another - // low detail section that would cover the hole. - } } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/LodQuadTree.java b/core/src/main/java/com/seibel/distanthorizons/core/render/LodQuadTree.java index 3bbeda893..0ac323dab 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/LodQuadTree.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/LodQuadTree.java @@ -290,7 +290,7 @@ public class LodQuadTree extends QuadTree implements IDebugRen //byte expectedDetailLevel = DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL + 3; // can be used instead of the following logic for testing byte expectedDetailLevel = this.calculateExpectedDetailLevel(playerPos, sectionPos); expectedDetailLevel = (byte) Math.min(expectedDetailLevel, this.minRenderDetailLevel); - expectedDetailLevel += DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL; + expectedDetailLevel += DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL; if (DhSectionPos.getDetailLevel(sectionPos) > expectedDetailLevel) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/LodRenderSection.java b/core/src/main/java/com/seibel/distanthorizons/core/render/LodRenderSection.java index 5ebda91bf..8a58e76f5 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/LodRenderSection.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/LodRenderSection.java @@ -24,16 +24,19 @@ import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSour import com.seibel.distanthorizons.core.dataObjects.render.ColumnRenderSource; import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.ColumnRenderBufferBuilder; import com.seibel.distanthorizons.core.dataObjects.transformers.FullDataToRenderDataTransformer; +import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.enums.EDhDirection; import com.seibel.distanthorizons.core.file.fullDatafile.FullDataSourceProviderV2; import com.seibel.distanthorizons.core.level.IDhClientLevel; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; +import com.seibel.distanthorizons.core.pos.DhBlockPos2D; import com.seibel.distanthorizons.core.pos.DhSectionPos; import com.seibel.distanthorizons.core.render.glObject.GLProxy; import com.seibel.distanthorizons.core.render.renderer.IDebugRenderable; import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.ColumnRenderBuffer; import com.seibel.distanthorizons.core.render.renderer.DebugRenderer; import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; import it.unimi.dsi.fastutil.longs.LongArrayList; import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.Nullable; @@ -54,6 +57,7 @@ import java.util.concurrent.locks.ReentrantLock; public class LodRenderSection implements IDebugRenderable, AutoCloseable { private static final Logger LOGGER = DhLoggerBuilder.getLogger(); + private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class); @@ -241,10 +245,17 @@ public class LodRenderSection implements IDebugRenderable, AutoCloseable long adjPos = DhSectionPos.getAdjacentPos(this.pos, direction); try { - LodRenderSection adjRenderSection = this.quadTree.getValue(adjPos); - if (adjRenderSection != null) + // ignore adjacent positions that aren't the same detail level + // since the LodDataBuilder can't handle different detail levels + byte detailLevel = this.quadTree.calculateExpectedDetailLevel(new DhBlockPos2D(MC.getPlayerBlockPos()), adjPos); + detailLevel += DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL; + if (detailLevel == DhSectionPos.getDetailLevel(this.pos)) { - futureArray[arrayIndex] = adjRenderSection.getRenderSourceAsync(); + LodRenderSection adjRenderSection = this.quadTree.getValue(adjPos); + if (adjRenderSection != null) + { + futureArray[arrayIndex] = adjRenderSection.getRenderSourceAsync(); + } } } catch (IndexOutOfBoundsException ignore) {} From fbe81021c0775ad58191adb8847709cd6242cf5c Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sun, 28 Jul 2024 08:55:35 -0500 Subject: [PATCH 20/22] Update API javadocs --- .../distanthorizons/api/enums/EDhApiDetailLevel.java | 2 +- .../api/enums/rendering/EDhApiBlockMaterial.java | 1 + .../api/interfaces/block/IDhApiBlockStateWrapper.java | 7 ++++++- .../api/interfaces/world/IDhApiLevelWrapper.java | 4 +++- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/api/src/main/java/com/seibel/distanthorizons/api/enums/EDhApiDetailLevel.java b/api/src/main/java/com/seibel/distanthorizons/api/enums/EDhApiDetailLevel.java index 46a68b531..9721c68e6 100644 --- a/api/src/main/java/com/seibel/distanthorizons/api/enums/EDhApiDetailLevel.java +++ b/api/src/main/java/com/seibel/distanthorizons/api/enums/EDhApiDetailLevel.java @@ -24,7 +24,7 @@ package com.seibel.distanthorizons.api.enums; * CHUNK - Detail Level: 4, width 16 block,
* REGION - Detail Level: 9, width 512 block

* - * Detail levels in Distant Horizons represent how large a section (of either LODs or MC chunks) + * Detail levels in Distant Horizons represent how large a LOD * is, with the smallest being 0 (1 block wide).
* The width of a detail level can be calculated by putting the detail level to the power of 2.
* Example for the chunk detail level (4): 2^4 = 16 blocks wide

diff --git a/api/src/main/java/com/seibel/distanthorizons/api/enums/rendering/EDhApiBlockMaterial.java b/api/src/main/java/com/seibel/distanthorizons/api/enums/rendering/EDhApiBlockMaterial.java index dfedf3278..a3dbb674b 100644 --- a/api/src/main/java/com/seibel/distanthorizons/api/enums/rendering/EDhApiBlockMaterial.java +++ b/api/src/main/java/com/seibel/distanthorizons/api/enums/rendering/EDhApiBlockMaterial.java @@ -21,6 +21,7 @@ package com.seibel.distanthorizons.api.enums.rendering; * AIR,
* ILLUMINATED,
* + * @author IMS * @author James Seibel * @since API 3.0.0 * @version 2024-7-11 diff --git a/api/src/main/java/com/seibel/distanthorizons/api/interfaces/block/IDhApiBlockStateWrapper.java b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/block/IDhApiBlockStateWrapper.java index 8a71a090f..7539fbb1d 100644 --- a/api/src/main/java/com/seibel/distanthorizons/api/interfaces/block/IDhApiBlockStateWrapper.java +++ b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/block/IDhApiBlockStateWrapper.java @@ -19,6 +19,7 @@ package com.seibel.distanthorizons.api.interfaces.block; +import com.seibel.distanthorizons.api.enums.rendering.EDhApiBlockMaterial; import com.seibel.distanthorizons.api.interfaces.IDhApiUnsafeWrapper; /** @@ -44,7 +45,11 @@ public interface IDhApiBlockStateWrapper extends IDhApiUnsafeWrapper * @since API 3.0.0 */ String getSerialString(); - /** @since API 3.0.0 */ + /** + * Returns the byte value representing the {@link EDhApiBlockMaterial} enum. + * @see EDhApiBlockMaterial + * @since API 3.0.0 + */ byte getMaterialId(); } diff --git a/api/src/main/java/com/seibel/distanthorizons/api/interfaces/world/IDhApiLevelWrapper.java b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/world/IDhApiLevelWrapper.java index ee28ad06a..4513b6a82 100644 --- a/api/src/main/java/com/seibel/distanthorizons/api/interfaces/world/IDhApiLevelWrapper.java +++ b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/world/IDhApiLevelWrapper.java @@ -28,7 +28,7 @@ import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderRegist * A level is equivalent to a dimension in vanilla Minecraft. * * @author James Seibel - * @version 2022-7-14 + * @version 2024-7-28 * @since API 1.0.0 */ public interface IDhApiLevelWrapper extends IDhApiUnsafeWrapper @@ -53,6 +53,8 @@ public interface IDhApiLevelWrapper extends IDhApiUnsafeWrapper /** * Will return null if called on the server, * or if called before the renderer has been set up. + * + * @since API 3.0.0 */ IDhApiCustomRenderRegister getRenderRegister(); From 752008e8ac1e965eeb6122adcfeb4506da6c2aea Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sun, 28 Jul 2024 08:55:54 -0500 Subject: [PATCH 21/22] Re-add deprecated IDhApiLevelWrapper.getHeight() --- .../api/interfaces/world/IDhApiLevelWrapper.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/com/seibel/distanthorizons/api/interfaces/world/IDhApiLevelWrapper.java b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/world/IDhApiLevelWrapper.java index 4513b6a82..45bfdb4cb 100644 --- a/api/src/main/java/com/seibel/distanthorizons/api/interfaces/world/IDhApiLevelWrapper.java +++ b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/world/IDhApiLevelWrapper.java @@ -41,7 +41,18 @@ public interface IDhApiLevelWrapper extends IDhApiUnsafeWrapper boolean hasSkyLight(); - /** Returns the max block height of the level(?) */ + /** + * Deprecated, use {@link IDhApiLevelWrapper#getMaxHeight} instead.
+ * Returns the max block height of the level. + * + * @see IDhApiLevelWrapper#getMaxHeight + */ + @Deprecated + default int getHeight() { return this.getMaxHeight(); } + /** + * Returns the max block height of the level + * @since API 3.0.0 + */ int getMaxHeight(); /** From 9834b20a9fda0ff4444ca46b6b413961948cee81 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sun, 28 Jul 2024 08:56:18 -0500 Subject: [PATCH 22/22] Revert and Deprecate DhApiChunk and DhApiTerrainDataPoint constructors --- .../api/objects/data/DhApiChunk.java | 22 ++++++- .../objects/data/DhApiTerrainDataPoint.java | 57 ++++++++++++++++++- .../methods/data/DhApiTerrainDataRepo.java | 5 +- 3 files changed, 80 insertions(+), 4 deletions(-) diff --git a/api/src/main/java/com/seibel/distanthorizons/api/objects/data/DhApiChunk.java b/api/src/main/java/com/seibel/distanthorizons/api/objects/data/DhApiChunk.java index 8bbed6ded..70535e5e8 100644 --- a/api/src/main/java/com/seibel/distanthorizons/api/objects/data/DhApiChunk.java +++ b/api/src/main/java/com/seibel/distanthorizons/api/objects/data/DhApiChunk.java @@ -52,7 +52,27 @@ public class DhApiChunk // constructors // //==============// - public DhApiChunk(int chunkPosX, int chunkPosZ, int bottomYBlockPos, int topYBlockPos) + /** + * Deprecated due to the topYBlockPos and bottomYBlockPos variables being put in the wrong order. + * They should have been in bottom -> top order. + * + * @see DhApiChunk#create(int, int, int, int) + */ + @Deprecated + public DhApiChunk(int chunkPosX, int chunkPosZ, int topYBlockPos, int bottomYBlockPos) + { this(chunkPosX, chunkPosZ, bottomYBlockPos, topYBlockPos, false); } + + /** + * @since API 3.0.0 + */ + public static DhApiChunk create(int chunkPosX, int chunkPosZ, int bottomYBlockPos, int topYBlockPos) + { return new DhApiChunk(chunkPosX, chunkPosZ, topYBlockPos, bottomYBlockPos, false); } + + /** + * Only visible to internal DH methods + * @param ignoredParameter is only present to differentiate the two constructors and isn't actually used + */ + private DhApiChunk(int chunkPosX, int chunkPosZ, int bottomYBlockPos, int topYBlockPos, boolean ignoredParameter) { this.chunkPosX = chunkPosX; this.chunkPosZ = chunkPosZ; diff --git a/api/src/main/java/com/seibel/distanthorizons/api/objects/data/DhApiTerrainDataPoint.java b/api/src/main/java/com/seibel/distanthorizons/api/objects/data/DhApiTerrainDataPoint.java index ab2cb9f01..caae71320 100644 --- a/api/src/main/java/com/seibel/distanthorizons/api/objects/data/DhApiTerrainDataPoint.java +++ b/api/src/main/java/com/seibel/distanthorizons/api/objects/data/DhApiTerrainDataPoint.java @@ -19,9 +19,12 @@ package com.seibel.distanthorizons.api.objects.data; +import com.seibel.distanthorizons.api.enums.EDhApiDetailLevel; import com.seibel.distanthorizons.api.interfaces.block.IDhApiBiomeWrapper; import com.seibel.distanthorizons.api.interfaces.block.IDhApiBlockStateWrapper; +import java.util.ArrayList; + /** * Holds a single datapoint of terrain data. * @@ -37,6 +40,8 @@ public class DhApiTerrainDataPoint * 2 = 4x4 blocks
* 4 = chunk (16x16 blocks)
* 9 = region (512x512 blocks)
+ * + * @see EDhApiDetailLevel */ public final byte detailLevel; @@ -50,7 +55,57 @@ public class DhApiTerrainDataPoint - public DhApiTerrainDataPoint(byte detailLevel, int blockLightLevel, int skyLightLevel, int bottomYBlockPos, int topYBlockPos, IDhApiBlockStateWrapper blockStateWrapper, IDhApiBiomeWrapper biomeWrapper) + //==============// + // constructors // + //==============// + + /** + * Deprecated due to the topYBlockPos and bottomYBlockPos variables being put in the wrong order. + * They should have been in bottom -> top order. + * + * @see DhApiTerrainDataPoint#create(byte, int, int, int, int, IDhApiBlockStateWrapper, IDhApiBiomeWrapper) + */ + @Deprecated + public DhApiTerrainDataPoint( + byte detailLevel, + int blockLightLevel, int skyLightLevel, + int topYBlockPos, int bottomYBlockPos, + IDhApiBlockStateWrapper blockStateWrapper, IDhApiBiomeWrapper biomeWrapper) + { + this(detailLevel, blockLightLevel, skyLightLevel, + bottomYBlockPos, topYBlockPos, + blockStateWrapper, biomeWrapper, + false); + } + + /** + * @since API 3.0.0 + */ + public static DhApiTerrainDataPoint create( + byte detailLevel, + int blockLightLevel, int skyLightLevel, + int bottomYBlockPos, int topYBlockPos, + IDhApiBlockStateWrapper blockStateWrapper, IDhApiBiomeWrapper biomeWrapper + ) + { + return new DhApiTerrainDataPoint( + detailLevel, blockLightLevel, skyLightLevel, + bottomYBlockPos, topYBlockPos, + blockStateWrapper, biomeWrapper, + false); + } + + /** + * Only visible to internal DH methods + * @param ignoredParameter is only present to differentiate the two constructors and isn't actually used + */ + private DhApiTerrainDataPoint( + byte detailLevel, + int blockLightLevel, int skyLightLevel, + int bottomYBlockPos, int topYBlockPos, + IDhApiBlockStateWrapper blockStateWrapper, IDhApiBiomeWrapper biomeWrapper, + boolean ignoredParameter + ) { this.detailLevel = detailLevel; diff --git a/core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/data/DhApiTerrainDataRepo.java b/core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/data/DhApiTerrainDataRepo.java index cf7d337c0..1d4f3331f 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/data/DhApiTerrainDataRepo.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/data/DhApiTerrainDataRepo.java @@ -326,9 +326,10 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo int height = FullDataPointUtil.getHeight(dataPoint); int topY = bottomY + height; - return new DhApiTerrainDataPoint(detailLevel, + return DhApiTerrainDataPoint.create( + detailLevel, FullDataPointUtil.getBlockLight(dataPoint), FullDataPointUtil.getSkyLight(dataPoint), - topY, bottomY, + bottomY, topY, blockState, biomeWrapper); }