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/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/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 1c159e746..8661464fa 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
@@ -43,7 +43,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();
/**
@@ -55,6 +66,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();
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);
}
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 f865f9ec7..3b8206b73 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
@@ -1461,6 +1461,22 @@ public class Config
.addListener(DebugColumnConfigEventHandler.INSTANCE)
.build();
+ public static ConfigEntry columnBuilderDebugXRow = new ConfigEntry.Builder()
+ .set(-1)
+ .setAppearance(EConfigEntryAppearance.ONLY_IN_GUI)
+ .addListener(DebugColumnConfigEventHandler.INSTANCE)
+ .build();
+ public static ConfigEntry columnBuilderDebugZRow = new ConfigEntry.Builder()
+ .set(-1)
+ .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();
+
public static ConfigCategory debugWireframe = new ConfigCategory.Builder()
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..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
@@ -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,
@@ -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..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
@@ -19,29 +19,58 @@
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 org.jetbrains.annotations.NotNull;
+
+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,
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)
{
+ //================//
+ // variable setup //
+ //================//
+
short maxX = (short) (x + xSize);
short maxY = (short) (minY + ySize);
short maxZ = (short) (z + zSize);
@@ -53,33 +82,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 +110,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,409 +127,269 @@ 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?
+ // 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);
}
}
- 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,
- color, adjOverlapNorth, irisBlockMaterialId, skyLightTop, blockLight,
- topData, bottomData);
+ makeAdjVerticalQuad(builder, adjCol, EDhDirection.NORTH, x, minY, z, xSize, ySize,
+ color, irisBlockMaterialId, blockLight);
}
}
- //SOUTH face vertex creation
+ // SOUTH face
{
- ColumnArrayView[] adjDataSouth = adjData[EDhDirection.SOUTH.ordinal() - 2];
- int adjOverlapSouth = ColorUtil.INVISIBLE;
- if (adjDataSouth == null)
+ ColumnArrayView adjCol = adjData[EDhDirection.SOUTH.ordinal() - 2];
+ if (adjCol == 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,
- color, adjOverlapSouth, irisBlockMaterialId, skyLightTop, blockLight,
- topData, bottomData);
+ makeAdjVerticalQuad(builder, adjCol, EDhDirection.SOUTH, x, minY, maxZ, xSize, ySize,
+ color, irisBlockMaterialId, blockLight);
}
}
- //WEST face vertex creation
+ // WEST face
{
- ColumnArrayView[] adjDataWest = adjData[EDhDirection.WEST.ordinal() - 2];
- int adjOverlapWest = ColorUtil.INVISIBLE;
- if (adjDataWest == null)
+ ColumnArrayView adjCol = adjData[EDhDirection.WEST.ordinal() - 2];
+ if (adjCol == 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,
- color, adjOverlapWest, irisBlockMaterialId, skyLightTop, blockLight,
- topData, bottomData);
+ makeAdjVerticalQuad(builder, adjCol, EDhDirection.WEST, x, minY, z, zSize, ySize,
+ color, irisBlockMaterialId, blockLight);
}
}
- //EAST face vertex creation
+ // EAST face
{
- ColumnArrayView[] adjDataEast = adjData[EDhDirection.EAST.ordinal() - 2];
- int adjOverlapEast = ColorUtil.INVISIBLE;
- if (adjData[EDhDirection.EAST.ordinal() - 2] == null)
+ ColumnArrayView adjCol = adjData[EDhDirection.EAST.ordinal() - 2];
+ if (adjCol == 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,
- color, adjOverlapEast, irisBlockMaterialId, skyLightTop, blockLight,
- topData, bottomData);
+ makeAdjVerticalQuad(builder, adjCol, EDhDirection.EAST, maxX, minY, z, zSize, ySize,
+ 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,
+ LodQuadBuilder builder, @NotNull 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 (adjColumnView == null || adjColumnView.size == 0 || RenderDataPointUtil.isVoid(adjColumnView.get(0)))
+ // if there isn't any data adjacent to this LOD,
+ // just add the full vertical quad
+ if (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 != 0)
- {
- 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 != 0)
- {
- 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)
- {
- 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 != 0)
- {
- 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 != 0)
+ // 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);
+ }
+ }
}
}
+
+
}
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..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
@@ -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 64c1abd02..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
@@ -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;
@@ -29,12 +30,13 @@ import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.pos.DhBlockPos;
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;
@@ -59,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)
@@ -81,16 +84,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)
@@ -99,7 +94,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)
@@ -111,8 +106,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)
{
@@ -142,19 +144,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
{
@@ -162,24 +165,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++)
{
- // 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;
-// }
-
-
+ // 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)))
@@ -187,43 +188,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);
+ (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)
{
@@ -231,67 +255,70 @@ public class ColumnRenderBufferBuilder
}
adjDetailLevel = adjRenderSource.getDataDetailLevel();
- if (adjDetailLevel != detailLevel)
- {
- //TODO: Implement this
- }
- else
+ if (adjDetailLevel == thisDetailLevel)
{
+ // 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 (xAdj >= ColumnRenderSource.SECTION_SIZE)
- xAdj -= ColumnRenderSource.SECTION_SIZE;
-
+ }
if (zAdj >= ColumnRenderSource.SECTION_SIZE)
+ {
zAdj -= ColumnRenderSource.SECTION_SIZE;
+ }
}
}
- 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++)
{
- // 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
@@ -304,8 +331,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;
- CubicLodTemplate.addLodToBuffer(data, topDataPoint, bottomDataPoint, adjColumnViews, detailLevel,
- x, z, quadBuilder, debugMode, debugSourceFlag);
+ addLodToBuffer(
+ data, topDataPoint, bottomDataPoint,
+ adjColumnViews,
+ thisDetailLevel, relX, relZ,
+ quadBuilder, debugSourceFlag);
}
}// for z
@@ -313,33 +343,146 @@ public class ColumnRenderBufferBuilder
quadBuilder.finalizeData();
}
-
-
-
- //=================//
- // vbo interaction //
- //=================//
-
- public static GLVertexBuffer[] resizeBuffer(GLVertexBuffer[] vbos, int newSize)
+ private static void addLodToBuffer(
+ long data, long topData, long bottomData,
+ ColumnArrayView[] adjColumnViews,
+ byte detailLevel, int renderSourceOffsetPosX, int renderSourceOffsetPosZ,
+ LodQuadBuilder quadBuilder, ColumnRenderSource.DebugSourceFlag debugSource)
{
- if (vbos.length == newSize)
+ long sectionPos = DhSectionPos.encode(detailLevel, renderSourceOffsetPosX, renderSourceOffsetPosZ);
+
+ short width = (short) BitShiftUtil.powerOfTwo(detailLevel);
+ short x = (short) DhSectionPos.getMinCornerBlockX(sectionPos);
+ short yMin = RenderDataPointUtil.getYMin(data);
+ short z = (short) DhSectionPos.getMinCornerBlockZ(sectionPos);
+ short ySize = (short) (RenderDataPointUtil.getYMax(data) - yMin);
+
+ if (ySize == 0)
{
- return vbos;
+ return;
+ }
+ else if (ySize < 0)
+ {
+ throw new IllegalArgumentException("Negative y size for the data! Data: [" + RenderDataPointUtil.toString(data) + "].");
}
- GLVertexBuffer[] newVbos = new GLVertexBuffer[newSize];
- System.arraycopy(vbos, 0, newVbos, 0, Math.min(vbos.length, newSize));
- if (newSize < vbos.length)
+ byte blockMaterialId = RenderDataPointUtil.getBlockMaterialId(data);
+
+
+
+ int color;
+ boolean fullBright = false;
+ EDhApiDebugRendering debugging = Config.Client.Advanced.Debugging.debugRendering.get();
+ switch (debugging)
{
- for (int i = newSize; i < vbos.length; i++)
+ case OFF:
{
- if (vbos[i] != null)
+ 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)
{
- vbos[i].close();
+ 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);
}
- return newVbos;
+
+ 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
- }
-
-}
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;
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 5c658e232..cbb7c3dc7 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;
+ //==================================//
+ // convert full data to render 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,20 +341,19 @@ 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());
+ renderColumnData.set(0, RenderDataPointUtil.EMPTY_DATA);
}
}
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;
}
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/DhClientLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java
index af69a3d73..02260a3d3 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
@@ -237,7 +237,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 274bc8c39..700826fd8 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);
}
}
@@ -154,8 +154,7 @@ public class DhClientServerLevel extends AbstractDhLevel implements IDhClientLev
public IClientLevelWrapper getClientLevelWrapper() { return MC_CLIENT.getWrappedClientLevel(); }
@Override
- public void clearRenderCache()
- {
+ public void clearRenderCache() {
this.clientside.clearRenderCache();
}
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 0b24aa5c5..a78bc1841 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());
}
@@ -151,7 +148,7 @@ public class LodQuadTree extends QuadTree implements IDebugRen
}
catch (Exception e)
{
- LOGGER.error("Quad Tree tick exception for dimension: " + this.level.getClientLevelWrapper().getDimensionName() + ", exception: " + e.getMessage(), e);
+ LOGGER.error("Quad Tree tick exception for dimension: " + this.level.getLevelWrapper().getDimensionName() + ", exception: " + e.getMessage(), e);
}
finally
{
@@ -293,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)
@@ -615,7 +612,7 @@ public class LodQuadTree extends QuadTree implements IDebugRen
// config listeners //
//==================//
- private void onHorizontalQualityChange() { this.clearRenderDataCache(); }
+ private void onHorizontalQualityChange() { /*this.clearRenderDataCache();*/ }
//===========//
@@ -678,8 +675,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();
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..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);
@@ -188,11 +192,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;
@@ -240,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) {}
@@ -306,6 +318,23 @@ 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;
+ this.uploadRenderDataToGpuFuture = null;
+ if (future != null)
+ {
+ // interrupting the future speeds things up, but also causes
+ // some LODs to never load in properly
+ future.cancel(false);
+ }
+ }
+
+
//========================//
// getters and properties //
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..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;
@@ -110,8 +111,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(
@@ -249,7 +248,7 @@ public class RenderDataPointUtil
getBlue(dataPoint) +
" BL:" + getLightBlock(dataPoint) +
" SL:" + getLightSky(dataPoint) +
- " BID:" + getBlockMaterialId(dataPoint);
+ " MAT:" + getBlockMaterialId(dataPoint) + "["+ EDhApiBlockMaterial.getFromIndex(getBlockMaterialId(dataPoint))+"]";
}
}
@@ -303,352 +302,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
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 c22c4a413..db6b309ae 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,10 +32,10 @@ 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();
+ void clearBlockColorCache();
/** Will return null if there was an issue finding the biome. */
@Nullable
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 31598ea31..9abd4d402 100644
--- a/core/src/main/resources/assets/distanthorizons/lang/en_us.json
+++ b/core/src/main/resources/assets/distanthorizons/lang/en_us.json
@@ -512,14 +512,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":