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 d086e3527..4dcb05fac 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 @@ -347,19 +347,17 @@ public class Config .addListener(ReloadLodsConfigEventHandler.DELAYED_INSTANCE) .build(); - // TODO fixme - //public static ConfigEntry lodBiomeBlending = new ConfigEntry.Builder() - // .setMinDefaultMax(0,1,7) - // .comment("" - // + "This is the same as vanilla Biome Blending settings for Lod area. \n" - // + " Note that anything other than '0' will greatly effect Lod building time \n" - // + " and increase triangle count. The cost on chunk generation speed is also \n" - // + " quite large if set too high.\n" - // + "\n" - // + " '0' equals to Vanilla Biome Blending of '1x1' or 'OFF', \n" - // + " '1' equals to Vanilla Biome Blending of '3x3', \n" - // + " '2' equals to Vanilla Biome Blending of '5x5'...") - // .build(); + public static ConfigEntry lodBiomeBlending = new ConfigEntry.Builder() + .setMinDefaultMax(0,3,3) // going higher than 3 causes banding issues for blending across LOD borders and an exponential increase in load times + .comment("" + + "This is the same as vanilla Biome Blending settings for Lod area. \n" + + " Note that anything other than '0' will greatly effect Lod building time. \n" + + "\n" + + " '0' equals to Vanilla Biome Blending of '1x1' or 'OFF', \n" + + " '1' equals to Vanilla Biome Blending of '3x3', \n" + + " '2' equals to Vanilla Biome Blending of '5x5'...") + .addListener(ReloadLodsConfigEventHandler.DELAYED_INSTANCE) + .build(); } public static class Ssao diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/eventHandlers/presets/RenderQualityPresetConfigEventHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/config/eventHandlers/presets/RenderQualityPresetConfigEventHandler.java index bda237249..f089fb96e 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/config/eventHandlers/presets/RenderQualityPresetConfigEventHandler.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/config/eventHandlers/presets/RenderQualityPresetConfigEventHandler.java @@ -114,6 +114,15 @@ public class RenderQualityPresetConfigEventHandler extends AbstractPresetConfigE this.put(EDhApiQualityPreset.HIGH, false); this.put(EDhApiQualityPreset.EXTREME, false); }}); + private final ConfigEntryWithPresetOptions biomeBlending = new ConfigEntryWithPresetOptions<>(Config.Client.Advanced.Graphics.Quality.lodBiomeBlending, + new HashMap() + {{ + this.put(EDhApiQualityPreset.MINIMUM, 0); + this.put(EDhApiQualityPreset.LOW, 1); + this.put(EDhApiQualityPreset.MEDIUM, 3); + this.put(EDhApiQualityPreset.HIGH, 3); + this.put(EDhApiQualityPreset.EXTREME, 3); + }}); @@ -133,6 +142,7 @@ public class RenderQualityPresetConfigEventHandler extends AbstractPresetConfigE this.configList.add(this.vanillaFade); this.configList.add(this.dhDither); this.configList.add(this.caveCulling); + this.configList.add(this.biomeBlending); for (ConfigEntryWithPresetOptions config : this.configList) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/FullDataSourceV1.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/FullDataSourceV1.java index 4f3d31886..3ca54ca4b 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/FullDataSourceV1.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/FullDataSourceV1.java @@ -116,7 +116,7 @@ public class FullDataSourceV1 implements IDataSource public String getKeyDisplayString() { return DhSectionPos.toString(this.pos); } @Override - public Long getPos() { return this.pos; } + public long getPos() { return this.pos; } public void resizeDataStructuresForRepopulation(long pos) { diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/FullDataSourceV2.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/FullDataSourceV2.java index a224bb104..482833d88 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/FullDataSourceV2.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/FullDataSourceV2.java @@ -32,7 +32,9 @@ import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.pooling.AbstractPhantomArrayList; import com.seibel.distanthorizons.core.pooling.PhantomArrayListCheckout; import com.seibel.distanthorizons.core.pooling.PhantomArrayListPool; +import com.seibel.distanthorizons.core.pos.DhLodPos; import com.seibel.distanthorizons.core.pos.DhSectionPos; +import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos; import com.seibel.distanthorizons.core.util.*; import com.seibel.distanthorizons.core.util.objects.DataCorruptedException; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; @@ -281,10 +283,83 @@ public class FullDataSourceV2 //======// - // data // + // getters // //======// - public LongArrayList get(int relX, int relZ) throws IndexOutOfBoundsException { return this.dataPoints[relativePosToIndex(relX, relZ)]; } + public LongArrayList get(int relX, int relZ) throws IndexOutOfBoundsException + { return this.dataPoints[relativePosToIndex(relX, relZ)]; } + + /** + * returns {@link FullDataPointUtil#EMPTY_DATA_POINT} if the given {@link DhBlockPos} + * is outside this data source's boundaries. + */ + public long getAtBlockPos(DhBlockPos blockPos) + { + DhLodPos requestedPos = new DhLodPos(LodUtil.BLOCK_DETAIL_LEVEL, blockPos.getX(), blockPos.getZ()); + + // stop if the requested blockPos is outside this datasource + { + // get the detail levels for this request + byte requestedDetailLevel = requestedPos.detailLevel; + byte requestedSectionDetailLevel = (byte) (requestedDetailLevel + DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL); + + // get the positions for this request + long sectionPos = requestedPos.getSectionPosWithSectionDetailLevel(requestedSectionDetailLevel); + if (!DhSectionPos.contains(this.pos, sectionPos)) + { + return FullDataPointUtil.EMPTY_DATA_POINT; + } + } + + + // get the relative data source position + byte requestDetailLevel = (byte) (DhSectionPos.getDetailLevel(this.pos) - DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL); + DhLodPos relativePos = requestedPos.getDhSectionRelativePositionForDetailLevel(requestDetailLevel); + + // get the data column + LongArrayList dataColumn = this.get(relativePos.x, relativePos.z); + if (dataColumn == null) + { + return FullDataPointUtil.EMPTY_DATA_POINT; + } + + + // search for a datapoint that contains the given block y position + long dataPoint; + for (int i = 0; i < dataColumn.size(); i++) + { + dataPoint = dataColumn.getLong(i); + + // we are looking for a specific datapoint, + // don't look at null ones + if (dataPoint == FullDataPointUtil.EMPTY_DATA_POINT) + { + continue; + } + + + + int requestedY = blockPos.getY(); + int bottomY = FullDataPointUtil.getBottomY(dataPoint) + this.levelMinY; + int height = FullDataPointUtil.getHeight(dataPoint); + int topY = bottomY + height; + + // does this datapoint contain the requested Y position? + if (bottomY <= requestedY + && requestedY < topY) // blockPositions start from the bottom of the block, thus "<=" for bottomY, just "<" for topY + { + return dataPoint; + } + } + + return FullDataPointUtil.EMPTY_DATA_POINT; + } + + + + //==========// + // updating // + //==========// @Override public boolean update(@NotNull FullDataSourceV2 inputDataSource, @Nullable IDhLevel level) { return this.update(inputDataSource); } @@ -991,6 +1066,7 @@ public class FullDataSourceV2 } + //================// // helper methods // //================// @@ -1075,7 +1151,7 @@ public class FullDataSourceV2 //=====================// @Override - public Long getPos() { return this.pos; } + public long getPos() { return this.pos; } @Override public byte getDataDetailLevel() { return (byte) (DhSectionPos.getDetailLevel(this.pos) - DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL); } 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 b56add576..9ec287823 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 @@ -131,7 +131,7 @@ public class FullDataToRenderDataTransformer LongArrayList dataColumn = fullDataSource.get(x, z); updateOrReplaceRenderDataViewColumnWithFullDataColumn( - levelWrapper, fullDataSource.mapping, + levelWrapper, fullDataSource, // bitshift is to account for LODs with a detail level greater than 0 so the block pos is correct baseX + BitShiftUtil.pow(x,dataDetail), baseZ + BitShiftUtil.pow(z,dataDetail), columnArrayView, dataColumn); @@ -145,13 +145,14 @@ public class FullDataToRenderDataTransformer /** Updates the given {@link ColumnArrayView} to match the incoming Full data {@link LongArrayList} */ public static void updateOrReplaceRenderDataViewColumnWithFullDataColumn( - IClientLevelWrapper levelWrapper, - FullDataPointIdMap fullDataMapping, int blockX, int blockZ, + IClientLevelWrapper levelWrapper, + FullDataSourceV2 fullDataSource, 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) + if (fullDataColumn == null + || fullDataColumn.size() == 0) { return; } @@ -160,7 +161,7 @@ public class FullDataToRenderDataTransformer if (fullDataLength <= columnArrayView.verticalSize()) { // Directly use the arrayView since it fits. - setRenderColumnView(levelWrapper, fullDataMapping, blockX, blockZ, columnArrayView, fullDataColumn); + setRenderColumnView(levelWrapper, fullDataSource, blockX, blockZ, columnArrayView, fullDataColumn); } else { @@ -171,7 +172,7 @@ public class FullDataToRenderDataTransformer { // expand the ColumnArrayView to fit the new larger max vertical size ColumnArrayView newColumnArrayView = new ColumnArrayView(dataArrayList, fullDataLength, 0, fullDataLength); - setRenderColumnView(levelWrapper, fullDataMapping, blockX, blockZ, newColumnArrayView, fullDataColumn); + setRenderColumnView(levelWrapper, fullDataSource, blockX, blockZ, newColumnArrayView, fullDataColumn); columnArrayView.changeVerticalSizeFrom(newColumnArrayView); } finally @@ -181,7 +182,7 @@ public class FullDataToRenderDataTransformer } } private static void setRenderColumnView( - IClientLevelWrapper levelWrapper, FullDataPointIdMap fullDataMapping, + IClientLevelWrapper levelWrapper, FullDataSourceV2 fullDataSource, int blockX, int blockZ, ColumnArrayView renderColumnData, LongArrayList fullColumnData) { @@ -222,6 +223,8 @@ public class FullDataToRenderDataTransformer // convert full data to render data // //==================================// + FullDataPointIdMap fullDataMapping = fullDataSource.mapping; + DhBlockPosMutable mutableBlockPos = new DhBlockPosMutable(blockX, 0, blockZ); // goes from the top down @@ -320,11 +323,13 @@ public class FullDataToRenderDataTransformer //=======================// if (ignoreNonCollidingBlocks - && !block.isSolid() && !block.isLiquid() && block.getOpacity() != LodUtil.BLOCK_FULLY_OPAQUE) + && !block.isSolid() + && !block.isLiquid() + && block.getOpacity() != LodUtil.BLOCK_FULLY_OPAQUE) { if (colorBelowWithAvoidedBlocks) { - int tempColor = levelWrapper.getBlockColor(mutableBlockPos, biome, block); + int tempColor = levelWrapper.getBlockColor(mutableBlockPos, biome, fullDataSource, block); // don't transfer the color when alpha is 0 // this prevents issues if grass is transparent @@ -345,7 +350,7 @@ public class FullDataToRenderDataTransformer if (colorToApplyToNextBlock == -1) { // use this block's color - color = levelWrapper.getBlockColor(mutableBlockPos, biome, block); + color = levelWrapper.getBlockColor(mutableBlockPos, biome, fullDataSource, block); } else { diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/IDataSource.java b/core/src/main/java/com/seibel/distanthorizons/core/file/IDataSource.java index 3b855e729..a8c014e70 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/IDataSource.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/IDataSource.java @@ -14,7 +14,7 @@ import com.seibel.distanthorizons.core.sql.dto.IBaseDTO; */ public interface IDataSource extends IBaseDTO, AutoCloseable { - Long getPos(); + long getPos(); /** @return true if the data was changed */ boolean update(FullDataSourceV2 chunkData, TDhLevel level); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java index 29c5ebfff..bf38a563e 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java @@ -221,11 +221,27 @@ public class DhSectionPos byte offset = (byte) (detailLevel - returnDetailLevel); return BitShiftUtil.powerOfTwo(offset); } - - /** @return how wide this section is in blocks */ - public static int getBlockWidth(long pos) { return BitShiftUtil.powerOfTwo(getDetailLevel(pos)); } + + /** @return how wide this section is in chunks */ public static int getChunkWidth(long pos) { return DhSectionPos.getBlockWidth(pos) / LodUtil.CHUNK_WIDTH; } + /** @see DhSectionPos#getDetailLevelWidthInBlocks(byte) */ + public static int getBlockWidth(long pos) { return getDetailLevelWidthInBlocks(getDetailLevel(pos)); } + /** + * Returns how many blocks wide a single LOD at the given detail level would be in blocks.
+ * IE:
+ * + * 0 => 1
+ * 1 => 2
+ * 2 => 4
+ * 3 => 8
+ * 4 => 16
+ * 5 => 32
+ * 6 => 64
+ * etc.
+ *
+ */ + public static int getDetailLevelWidthInBlocks(byte detailLevel) { return BitShiftUtil.powerOfTwo(detailLevel); } public static DhBlockPos2D getCenterBlockPos(long pos) { return new DhBlockPos2D(getCenterBlockPosX(pos), getCenterBlockPosZ(pos)); } 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 edf658d35..d58a8f0c4 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,6 +19,7 @@ package com.seibel.distanthorizons.core.wrapperInterfaces.world; +import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2; import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos; import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper; import org.jetbrains.annotations.Nullable; @@ -34,7 +35,7 @@ public interface IClientLevelWrapper extends ILevelWrapper @Nullable IServerLevelWrapper tryGetServerSideWrapper(); - int getBlockColor(DhBlockPos pos, IBiomeWrapper biome, IBlockStateWrapper blockState); + int getBlockColor(DhBlockPos pos, IBiomeWrapper biome, FullDataSourceV2 fullDataSource, IBlockStateWrapper blockState); /** @return -1 if there was a problem getting the color */ int getDirtBlockColor(); /** @return -1 if there was a problem getting the color */