This commit is contained in:
s809
2023-07-23 11:08:31 +05:00
37 changed files with 923 additions and 214 deletions
@@ -52,7 +52,7 @@ public class DhApiWorldGenerationConfig implements IDhApiWorldGenerationConfig
@Override
public IDhApiConfigValue<ELightGenerationMode> lightingEngine()
{ return new DhApiConfigValue<>(WorldGenerator.lightingEngine); }
{ return new DhApiConfigValue<>(WorldGenerator.worldGenLightingEngine); }
}
@@ -23,6 +23,7 @@ import com.seibel.distanthorizons.api.methods.events.abstractEvents.*;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
import com.seibel.distanthorizons.core.level.IServerKeyedClientLevel;
import com.seibel.distanthorizons.core.level.IKeyedClientLevelManager;
import com.seibel.distanthorizons.core.pos.DhChunkPos;
import com.seibel.distanthorizons.core.world.*;
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
import com.seibel.distanthorizons.core.level.IDhClientLevel;
@@ -133,29 +134,41 @@ public class ClientApi
}
}
public void clientChunkLoadEvent(IChunkWrapper chunk, IClientLevelWrapper level)
public void clientChunkLoadEvent(IChunkWrapper chunk, IClientLevelWrapper level) { this.applyChunkUpdate(chunk, level); }
public void clientChunkSaveEvent(IChunkWrapper chunk, IClientLevelWrapper level) { this.applyChunkUpdate(chunk, level); }
private void applyChunkUpdate(IChunkWrapper chunk, IClientLevelWrapper level)
{
if (SharedApi.getEnvironment() == EWorldEnvironment.Client_Only)
// if the user is in a single player world the chunk updates are handled on the server side
if (SharedApi.getEnvironment() != EWorldEnvironment.Client_Only)
{
IDhLevel dhLevel = SharedApi.getAbstractDhWorld().getLevel(level);
if (dhLevel != null)
return;
}
// only continue if the level is still loaded
IDhLevel dhLevel = SharedApi.getAbstractDhWorld().getLevel(level);
if (dhLevel == null)
{
return;
}
dhLevel.updateChunkAsync(chunk);
// also update any existing neighbour chunks so lighting changes are propagated correctly
for (int xOffset = -1; xOffset <= 1; xOffset++)
{
for (int zOffset = -1; zOffset <= 1; zOffset++)
{
dhLevel.updateChunkAsync(chunk);
}
}
}
public void clientChunkSaveEvent(IChunkWrapper chunk, IClientLevelWrapper level)
{
if (SharedApi.getEnvironment() == EWorldEnvironment.Client_Only)
{
IDhLevel dhLevel = SharedApi.getAbstractDhWorld().getLevel(level);
if (dhLevel != null)
{
dhLevel.updateChunkAsync(chunk);
DhChunkPos neighbourPos = new DhChunkPos(chunk.getChunkPos().x+xOffset, chunk.getChunkPos().z+zOffset);
IChunkWrapper neighbourChunk = dhLevel.getLevelWrapper().tryGetChunk(neighbourPos);
if (neighbourChunk != null)
{
dhLevel.updateChunkAsync(neighbourChunk);
}
}
}
}
public void clientLevelUnloadEvent(IClientLevelWrapper level)
{
@@ -644,19 +644,28 @@ public class Config
*/
.build();
public static ConfigEntry<ELightGenerationMode> lightingEngine = new ConfigEntry.Builder<ELightGenerationMode>()
.set(ELightGenerationMode.MINECRAFT)
public static ConfigEntry<ELightGenerationMode> worldGenLightingEngine = new ConfigEntry.Builder<ELightGenerationMode>()
.set(ELightGenerationMode.DISTANT_HORIZONS)
.comment(""
+ " How should distant generation chunk lighting be generated? \n"
+ " How should Distant Horizons world generation chunk lighting be handled? \n"
+ "\n"
+ ELightGenerationMode.MINECRAFT + ": Use Minecraft's lighting engine to generate chunk lighting. \n"
+ " Generally higher quality; but may crash MC's lighting engine if there is an issue. \n"
+ ELightGenerationMode.DISTANT_HORIZONS + ": Uses Distant Horizons' lighting engine to estimate chunk lighting. \n"
+ " Generally lower quality; but more stable for large numbers of world generator threads. \n"
+ ELightGenerationMode.DISTANT_HORIZONS + ": Uses Distant Horizons' lighting engine to generate chunk lighting. \n"
+ " May not exactly match MC's, but is more stable for large numbers of world generator threads. \n"
+ "\n"
+ "This will effect generation speed, but not rendering performance.")
.build();
public static ConfigEntry<Integer> worldGenerationTimeoutLengthInSeconds = new ConfigEntry.Builder<Integer>()
.setMinDefaultMax(5, 60, 60*10/*10 minutes*/)
.comment(""
+ "How long should a world generator thread run for before timing out? \n"
+ "Note: If you are experiencing timeout errors it is better to lower your CPU usage first \n"
+ "via the thread config before changing this value. \n"
+ "")
.build();
// deprecated and not implemented, can be made public if we ever re-implement it
@Deprecated
private static ConfigEntry<EGenerationPriority> generationPriority = new ConfigEntry.Builder<EGenerationPriority>()
@@ -25,6 +25,9 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
*/
public class FullDataPointIdMap
{
public static final String SEPARATOR_STRING = "_DH-BSW_";
// FIXME: Improve performance maybe?
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
@@ -157,11 +160,11 @@ public class FullDataPointIdMap
}
public String serialize() { return this.biome.serialize() + " " + this.blockState.serialize(); }
public String serialize() { return this.biome.serialize() + SEPARATOR_STRING + this.blockState.serialize(); }
public static Entry deserialize(String str) throws IOException, InterruptedException
{
String[] stringArray = str.split(" ");
String[] stringArray = str.split(SEPARATOR_STRING);
if (stringArray.length != 2)
{
throw new IOException("Failed to deserialize BiomeBlockStateEntry");
@@ -37,7 +37,7 @@ public class CompleteFullDataSource extends FullDataArrayAccessor implements IFu
/** measured in dataPoints */
public static final int WIDTH = BitShiftUtil.powerOfTwo(SECTION_SIZE_OFFSET);
public static final byte DATA_FORMAT_VERSION = 0;
public static final byte DATA_FORMAT_VERSION = 1;
/** written to the binary file to mark what {@link IFullDataSource} the binary file corresponds to */
public static final long TYPE_ID = "CompleteFullDataSource".hashCode();
@@ -51,7 +51,7 @@ public class HighDetailIncompleteFullDataSource implements IIncompleteFullDataSo
/** aka max detail level */
public static final byte MAX_SECTION_DETAIL = SECTION_SIZE_OFFSET + SPARSE_UNIT_DETAIL;
public static final byte DATA_FORMAT_VERSION = 0;
public static final byte DATA_FORMAT_VERSION = 1;
/** written to the binary file to mark what {@link IFullDataSource} the binary file corresponds to */
public static final long TYPE_ID = "HighDetailIncompleteFullDataSource".hashCode();
@@ -42,7 +42,7 @@ public class LowDetailIncompleteFullDataSource extends FullDataArrayAccessor imp
/** measured in dataPoints */
public static final int WIDTH = BitShiftUtil.powerOfTwo(SECTION_SIZE_OFFSET);
public static final byte DATA_FORMAT_VERSION = 0; // TODO rename to data format version
public static final byte DATA_FORMAT_VERSION = 1;
/** written to the binary file to mark what {@link IFullDataSource} the binary file corresponds to */
public static final long TYPE_ID = "LowDetailIncompleteFullDataSource".hashCode();
@@ -20,8 +20,8 @@
package com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.enums.EDhDirection;
import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.enums.ELodDirection;
/** Represents a render-able quad. */
public final class BufferQuad
@@ -56,7 +56,7 @@ public final class BufferQuad
public final byte skyLight;
public final byte blockLight;
public final ELodDirection direction;
public final EDhDirection direction;
public boolean hasError = false;
@@ -64,7 +64,7 @@ public final class BufferQuad
BufferQuad(short x, short y, short z, short widthEastWest, short widthNorthSouthOrUpDown,
int color, byte skylight, byte blockLight,
ELodDirection direction)
EDhDirection direction)
{
if (widthEastWest == 0 || widthNorthSouthOrUpDown == 0)
throw new IllegalArgumentException("Size 0 quad!");
@@ -20,12 +20,12 @@
package com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding;
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.RenderDataPointUtil;
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.core.enums.ELodDirection;
import com.seibel.distanthorizons.coreapi.util.MathUtil;
public class ColumnBox
@@ -100,13 +100,13 @@ public class ColumnBox
boolean skipTop = RenderDataPointUtil.doesDataPointExist(topData) && (RenderDataPointUtil.getYMin(topData) == maxY) && !isTopTransparent;
if (!skipTop)
{
builder.addQuadUp(x, maxY, z, xSize, zSize, ColorUtil.applyShade(color, MC.getShade(ELodDirection.UP)), skyLightTop, blockLight);
builder.addQuadUp(x, maxY, z, xSize, zSize, ColorUtil.applyShade(color, MC.getShade(EDhDirection.UP)), skyLightTop, blockLight);
}
boolean skipBottom = RenderDataPointUtil.doesDataPointExist(bottomData) && (RenderDataPointUtil.getYMax(bottomData) == minY) && !isBottomTransparent;
if (!skipBottom)
{
builder.addQuadDown(x, minY, z, xSize, zSize, ColorUtil.applyShade(color, MC.getShade(ELodDirection.DOWN)), skyLightBot, blockLight);
builder.addQuadDown(x, minY, z, xSize, zSize, ColorUtil.applyShade(color, MC.getShade(EDhDirection.DOWN)), skyLightBot, blockLight);
}
@@ -115,28 +115,28 @@ public class ColumnBox
// TODO merge duplicate code
//NORTH face vertex creation
{
ColumnArrayView[] adjDataNorth = adjData[ELodDirection.NORTH.ordinal() - 2]; // TODO can we use something other than ordinal-2?
ColumnArrayView[] adjDataNorth = adjData[EDhDirection.NORTH.ordinal() - 2]; // TODO can we use something other than ordinal-2?
int adjOverlapNorth = ColorUtil.INVISIBLE;
if (adjDataNorth == null)
{
// add an adjacent face if this is opaque face or transparent over the void
if (!isTransparent || overVoid)
{
builder.addQuadAdj(ELodDirection.NORTH, x, minY, z, xSize, ySize, color, (byte) 15, blockLight);
builder.addQuadAdj(EDhDirection.NORTH, x, minY, z, xSize, ySize, color, (byte) 15, blockLight);
}
}
else if (adjDataNorth.length == 1)
{
makeAdjVerticalQuad(builder, adjDataNorth[0], ELodDirection.NORTH, x, minY, z, xSize, ySize,
makeAdjVerticalQuad(builder, adjDataNorth[0], EDhDirection.NORTH, x, minY, z, xSize, ySize,
color, adjOverlapNorth, skyLightTop, blockLight,
topData, bottomData);
}
else
{
makeAdjVerticalQuad(builder, adjDataNorth[0], ELodDirection.NORTH, x, minY, z, (short) (xSize / 2), ySize,
makeAdjVerticalQuad(builder, adjDataNorth[0], EDhDirection.NORTH, x, minY, z, (short) (xSize / 2), ySize,
color, adjOverlapNorth, skyLightTop, blockLight,
topData, bottomData);
makeAdjVerticalQuad(builder, adjDataNorth[1], ELodDirection.NORTH, (short) (x + xSize / 2), minY, z, (short) (xSize / 2), ySize,
makeAdjVerticalQuad(builder, adjDataNorth[1], EDhDirection.NORTH, (short) (x + xSize / 2), minY, z, (short) (xSize / 2), ySize,
color, adjOverlapNorth, skyLightTop, blockLight,
topData, bottomData);
}
@@ -144,26 +144,26 @@ public class ColumnBox
//SOUTH face vertex creation
{
ColumnArrayView[] adjDataSouth = adjData[ELodDirection.SOUTH.ordinal() - 2];
ColumnArrayView[] adjDataSouth = adjData[EDhDirection.SOUTH.ordinal() - 2];
int adjOverlapSouth = ColorUtil.INVISIBLE;
if (adjDataSouth == null)
{
if (!isTransparent || overVoid)
builder.addQuadAdj(ELodDirection.SOUTH, x, minY, maxZ, xSize, ySize, color, (byte) 15, blockLight);
builder.addQuadAdj(EDhDirection.SOUTH, x, minY, maxZ, xSize, ySize, color, (byte) 15, blockLight);
}
else if (adjDataSouth.length == 1)
{
makeAdjVerticalQuad(builder, adjDataSouth[0], ELodDirection.SOUTH, x, minY, maxZ, xSize, ySize,
makeAdjVerticalQuad(builder, adjDataSouth[0], EDhDirection.SOUTH, x, minY, maxZ, xSize, ySize,
color, adjOverlapSouth, skyLightTop, blockLight,
topData, bottomData);
}
else
{
makeAdjVerticalQuad(builder, adjDataSouth[0], ELodDirection.SOUTH, x, minY, maxZ, (short) (xSize / 2), ySize,
makeAdjVerticalQuad(builder, adjDataSouth[0], EDhDirection.SOUTH, x, minY, maxZ, (short) (xSize / 2), ySize,
color, adjOverlapSouth, skyLightTop, blockLight,
topData, bottomData);
makeAdjVerticalQuad(builder, adjDataSouth[1], ELodDirection.SOUTH, (short) (x + xSize / 2), minY, maxZ, (short) (xSize / 2), ySize,
makeAdjVerticalQuad(builder, adjDataSouth[1], EDhDirection.SOUTH, (short) (x + xSize / 2), minY, maxZ, (short) (xSize / 2), ySize,
color, adjOverlapSouth, skyLightTop, blockLight,
topData, bottomData);
}
@@ -171,25 +171,25 @@ public class ColumnBox
//WEST face vertex creation
{
ColumnArrayView[] adjDataWest = adjData[ELodDirection.WEST.ordinal() - 2];
ColumnArrayView[] adjDataWest = adjData[EDhDirection.WEST.ordinal() - 2];
int adjOverlapWest = ColorUtil.INVISIBLE;
if (adjDataWest == null)
{
if (!isTransparent || overVoid)
builder.addQuadAdj(ELodDirection.WEST, x, minY, z, zSize, ySize, color, (byte) 15, blockLight);
builder.addQuadAdj(EDhDirection.WEST, x, minY, z, zSize, ySize, color, (byte) 15, blockLight);
}
else if (adjDataWest.length == 1)
{
makeAdjVerticalQuad(builder, adjDataWest[0], ELodDirection.WEST, x, minY, z, zSize, ySize,
makeAdjVerticalQuad(builder, adjDataWest[0], EDhDirection.WEST, x, minY, z, zSize, ySize,
color, adjOverlapWest, skyLightTop, blockLight,
topData, bottomData);
}
else
{
makeAdjVerticalQuad(builder, adjDataWest[0], ELodDirection.WEST, x, minY, z, (short) (zSize / 2), ySize,
makeAdjVerticalQuad(builder, adjDataWest[0], EDhDirection.WEST, x, minY, z, (short) (zSize / 2), ySize,
color, adjOverlapWest, skyLightTop, blockLight,
topData, bottomData);
makeAdjVerticalQuad(builder, adjDataWest[1], ELodDirection.WEST, x, minY, (short) (z + zSize / 2), (short) (zSize / 2), ySize,
makeAdjVerticalQuad(builder, adjDataWest[1], EDhDirection.WEST, x, minY, (short) (z + zSize / 2), (short) (zSize / 2), ySize,
color, adjOverlapWest, skyLightTop, blockLight,
topData, bottomData);
}
@@ -197,25 +197,25 @@ public class ColumnBox
//EAST face vertex creation
{
ColumnArrayView[] adjDataEast = adjData[ELodDirection.EAST.ordinal() - 2];
ColumnArrayView[] adjDataEast = adjData[EDhDirection.EAST.ordinal() - 2];
int adjOverlapEast = ColorUtil.INVISIBLE;
if (adjData[ELodDirection.EAST.ordinal() - 2] == null)
if (adjData[EDhDirection.EAST.ordinal() - 2] == null)
{
if (!isTransparent || overVoid)
builder.addQuadAdj(ELodDirection.EAST, maxX, minY, z, zSize, ySize, color, (byte) 15, blockLight);
builder.addQuadAdj(EDhDirection.EAST, maxX, minY, z, zSize, ySize, color, (byte) 15, blockLight);
}
else if (adjDataEast.length == 1)
{
makeAdjVerticalQuad(builder, adjDataEast[0], ELodDirection.EAST, maxX, minY, z, zSize, ySize,
makeAdjVerticalQuad(builder, adjDataEast[0], EDhDirection.EAST, maxX, minY, z, zSize, ySize,
color, adjOverlapEast, skyLightTop, blockLight,
topData, bottomData);
}
else
{
makeAdjVerticalQuad(builder, adjDataEast[0], ELodDirection.EAST, maxX, minY, z, (short) (zSize / 2), ySize,
makeAdjVerticalQuad(builder, adjDataEast[0], EDhDirection.EAST, maxX, minY, z, (short) (zSize / 2), ySize,
color, adjOverlapEast, skyLightTop, blockLight,
topData, bottomData);
makeAdjVerticalQuad(builder, adjDataEast[1], ELodDirection.EAST, maxX, minY, (short) (z + zSize / 2), (short) (zSize / 2), ySize,
makeAdjVerticalQuad(builder, adjDataEast[1], EDhDirection.EAST, maxX, minY, (short) (z + zSize / 2), (short) (zSize / 2), ySize,
color, adjOverlapEast, skyLightTop, blockLight,
topData, bottomData);
}
@@ -224,7 +224,7 @@ public class ColumnBox
// the overlap color can be used to see faces that shouldn't be rendered
private static void makeAdjVerticalQuad(
LodQuadBuilder builder, ColumnArrayView adjColumnView, ELodDirection direction,
LodQuadBuilder builder, ColumnArrayView adjColumnView, EDhDirection direction,
short x, short yMin, short z, short horizontalWidth, short ySize,
int color, int debugOverlapColor, byte skyLightTop, byte blockLight,
long topData, long bottomData)
@@ -2,6 +2,7 @@ package com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding;
import com.seibel.distanthorizons.api.enums.config.EGpuUploadMethod;
import com.seibel.distanthorizons.api.enums.rendering.EDebugRendering;
import com.seibel.distanthorizons.core.enums.EDhDirection;
import com.seibel.distanthorizons.core.enums.EGLProxyContext;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.config.listeners.ConfigChangeListener;
@@ -18,7 +19,6 @@ import com.seibel.distanthorizons.core.util.ThreadUtil;
import com.seibel.distanthorizons.core.util.objects.Reference;
import com.seibel.distanthorizons.core.util.objects.UncheckedInterruptedException;
import com.seibel.distanthorizons.core.dataObjects.render.columnViews.ColumnArrayView;
import com.seibel.distanthorizons.core.enums.ELodDirection;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -215,7 +215,7 @@ public class ColumnRenderBufferBuilder
// We avoid cases where the adjPosition is in player chunk while the position is
// not
// to always have a wall underwater
for (ELodDirection lodDirection : ELodDirection.ADJ_DIRECTIONS)
for (EDhDirection lodDirection : EDhDirection.ADJ_DIRECTIONS)
{
try
{
@@ -280,8 +280,8 @@ public class ColumnRenderBufferBuilder
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() == ELodDirection.Axis.X ? 0 : 1),
zAdj + (lodDirection.getAxis() == ELodDirection.Axis.Z ? 0 : 1));
xAdj + (lodDirection.getAxis() == EDhDirection.Axis.X ? 0 : 1),
zAdj + (lodDirection.getAxis() == EDhDirection.Axis.Z ? 0 : 1));
}
}
catch (RuntimeException e)
@@ -23,7 +23,7 @@ import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.*;
import com.seibel.distanthorizons.core.enums.ELodDirection;
import com.seibel.distanthorizons.core.enums.EDhDirection;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.pos.Pos2D;
import com.seibel.distanthorizons.core.render.AbstractRenderBuffer;
@@ -136,11 +136,11 @@ public class LodQuadBuilder
// add quads //
//===========//
public void addQuadAdj(ELodDirection dir, short x, short y, short z,
public void addQuadAdj(EDhDirection dir, short x, short y, short z,
short widthEastWest, short widthNorthSouthOrUpDown,
int color, byte skyLight, byte blockLight)
{
if (dir == ELodDirection.DOWN)
if (dir == EDhDirection.DOWN)
{
throw new IllegalArgumentException("addQuadAdj() is only for adj direction! Not UP or Down!");
}
@@ -174,9 +174,9 @@ public class LodQuadBuilder
return;
}
BufferQuad quad = new BufferQuad(x, y, z, widthEastWest, widthNorthSouthOrUpDown, color, skylight, blocklight, ELodDirection.UP);
BufferQuad quad = new BufferQuad(x, y, z, widthEastWest, widthNorthSouthOrUpDown, color, skylight, blocklight, EDhDirection.UP);
boolean isTransparent = (this.doTransparency && ColorUtil.getAlpha(color) < 255);
ArrayList<BufferQuad> quadList = isTransparent ? this.transparentQuads[ELodDirection.UP.ordinal()] : this.opaqueQuads[ELodDirection.UP.ordinal()];
ArrayList<BufferQuad> quadList = isTransparent ? this.transparentQuads[EDhDirection.UP.ordinal()] : this.opaqueQuads[EDhDirection.UP.ordinal()];
// update the minimum relative height for this quad's positions
@@ -214,9 +214,9 @@ public class LodQuadBuilder
{
if (skipQuadsWithZeroSkylight && skylight == 0 && y < skyLightCullingBelow)
return;
BufferQuad quad = new BufferQuad(x, y, z, width, wz, color, skylight, blocklight, ELodDirection.DOWN);
BufferQuad quad = new BufferQuad(x, y, z, width, wz, color, skylight, blocklight, EDhDirection.DOWN);
ArrayList<BufferQuad> qs = (doTransparency && ColorUtil.getAlpha(color) < 255)
? transparentQuads[ELodDirection.DOWN.ordinal()] : opaqueQuads[ELodDirection.DOWN.ordinal()];
? transparentQuads[EDhDirection.DOWN.ordinal()] : opaqueQuads[EDhDirection.DOWN.ordinal()];
if (!qs.isEmpty() &&
(qs.get(qs.size()-1).tryMerge(quad, BufferMergeDirectionEnum.EastWest)
|| qs.get(qs.size()-1).tryMerge(quad, BufferMergeDirectionEnum.NorthSouthOrUpDown))
@@ -238,7 +238,7 @@ public class LodQuadBuilder
int[][] quadBase = DIRECTION_VERTEX_IBO_QUAD[quad.direction.ordinal()];
short widthEastWest = quad.widthEastWest;
short widthNorthSouth = quad.widthNorthSouthOrUpDown;
ELodDirection.Axis axis = quad.direction.getAxis();
EDhDirection.Axis axis = quad.direction.getAxis();
for (int i = 0; i < quadBase.length; i++)
{
short dx, dy, dz;
@@ -349,7 +349,7 @@ public class LodQuadBuilder
// only run the second merge if the face is the top or bottom
if (directionIndex == ELodDirection.UP.ordinal() || directionIndex == ELodDirection.DOWN.ordinal())
if (directionIndex == EDhDirection.UP.ordinal() || directionIndex == EDhDirection.DOWN.ordinal())
{
mergeCount += mergeQuadsInternal(this.opaqueQuads, directionIndex, BufferMergeDirectionEnum.NorthSouthOrUpDown);
if (this.doTransparency)
@@ -400,7 +400,7 @@ public class LodQuadBuilder
public void fixTransparencyOverVoid()
{
// make transparent LODs opaque if they are over the void
ListIterator<BufferQuad> iter = this.transparentQuads[ELodDirection.UP.ordinal()].listIterator();
ListIterator<BufferQuad> iter = this.transparentQuads[EDhDirection.UP.ordinal()].listIterator();
if (iter.hasNext())
{
BufferQuad currentQuad = iter.next();
@@ -422,7 +422,7 @@ public class LodQuadBuilder
// move the now-opaque quad into the opaque list (if not done the quads may render on top of other transparent quads)
iter.remove();
this.opaqueQuads[ELodDirection.UP.ordinal()].add(currentQuad);
this.opaqueQuads[EDhDirection.UP.ordinal()].add(currentQuad);
}
currentQuad = iter.next();
@@ -397,18 +397,18 @@ public class FullDataToRenderDataTransformer
// System.arraycopy(result, 0, data, dataOffset, maxVerticalData);
// }
//
// public static final ELodDirection[] DIRECTIONS = new ELodDirection[] {
// ELodDirection.UP,
// ELodDirection.DOWN,
// ELodDirection.WEST,
// ELodDirection.EAST,
// ELodDirection.NORTH,
// ELodDirection.SOUTH };
// public static final EDhDirection[] DIRECTIONS = new EDhDirection[] {
// EDhDirection.UP,
// EDhDirection.DOWN,
// EDhDirection.WEST,
// EDhDirection.EAST,
// EDhDirection.NORTH,
// EDhDirection.SOUTH };
//
// private boolean hasCliffFace(IChunkWrapper chunk, int x, int y, int z) {
// for (ELodDirection dir : DIRECTIONS) {
// for (EDhDirection dir : DIRECTIONS) {
// IBlockDetailWrapper block = chunk.getBlockDetailAtFace(x, y, z, dir);
// if (block == null || !block.hasFaceCullingFor(ELodDirection.OPPOSITE_DIRECTIONS[dir.ordinal()]))
// if (block == null || !block.hasFaceCullingFor(EDhDirection.OPPOSITE_DIRECTIONS[dir.ordinal()]))
// return true;
// }
// return false;
@@ -10,15 +10,26 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory;
import it.unimi.dsi.fastutil.longs.LongArrayList;
public class LodDataBuilder {
public class LodDataBuilder
{
private static final IBlockStateWrapper AIR = SingletonInjector.INSTANCE.get(IWrapperFactory.class).getAirBlockStateWrapper();
public static ChunkSizedFullDataAccessor createChunkData(IChunkWrapper chunkWrapper) {
if (!canGenerateLodFromChunk(chunkWrapper)) return null;
public static ChunkSizedFullDataAccessor createChunkData(IChunkWrapper chunkWrapper)
{
if (!canGenerateLodFromChunk(chunkWrapper))
{
return null;
}
ChunkSizedFullDataAccessor chunkData = new ChunkSizedFullDataAccessor(chunkWrapper.getChunkPos());
for (int x=0; x<16; x++) {
for (int z=0; z<16; z++) {
for (int x=0; x<LodUtil.CHUNK_WIDTH; x++)
{
for (int z=0; z<LodUtil.CHUNK_WIDTH; z++)
{
LongArrayList longs = new LongArrayList(chunkWrapper.getHeight()/4);
int lastY = chunkWrapper.getMaxBuildHeight();
IBiomeWrapper biome = chunkWrapper.getBiome(x, lastY, z);
@@ -29,12 +40,14 @@ public class LodDataBuilder {
int y=chunkWrapper.getLightBlockingHeightMapValue(x, z);
for (; y>=chunkWrapper.getMinBuildHeight(); y--) {
for (; y>=chunkWrapper.getMinBuildHeight(); y--)
{
IBiomeWrapper newBiome = chunkWrapper.getBiome(x, y, z);
IBlockStateWrapper newBlockState = chunkWrapper.getBlockState(x, y, z);
byte newLight = (byte) ((chunkWrapper.getBlockLight(x,y+1,z) << 4) + chunkWrapper.getSkyLight(x,y+1,z));
if (!newBiome.equals(biome) || !newBlockState.equals(blockState)) {
if (!newBiome.equals(biome) || !newBlockState.equals(blockState))
{
longs.add(FullDataPointUtil.encode(mappedId, lastY-y, y+1 - chunkWrapper.getMinBuildHeight(), light));
biome = newBiome;
blockState = newBlockState;
@@ -29,7 +29,7 @@ import com.seibel.distanthorizons.coreapi.util.math.Vec3i;
/**
* An (almost) exact copy of Minecraft's
* Direction enum.
* Direction enum. <Br><Br>
*
* Up <Br>
* Down <Br>
@@ -41,46 +41,57 @@ import com.seibel.distanthorizons.coreapi.util.math.Vec3i;
* @author James Seibel
* @version 2021-11-13
*/
public enum ELodDirection
public enum EDhDirection
{
DOWN(0, 1, -1, "down", ELodDirection.AxisDirection.NEGATIVE, ELodDirection.Axis.Y, new Vec3i(0, -1, 0)),
UP(1, 0, -1, "up", ELodDirection.AxisDirection.POSITIVE, ELodDirection.Axis.Y, new Vec3i(0, 1, 0)),
NORTH(2, 3, 2, "north", ELodDirection.AxisDirection.NEGATIVE, ELodDirection.Axis.Z, new Vec3i(0, 0, -1)),
SOUTH(3, 2, 0, "south", ELodDirection.AxisDirection.POSITIVE, ELodDirection.Axis.Z, new Vec3i(0, 0, 1)),
WEST(4, 5, 1, "west", ELodDirection.AxisDirection.NEGATIVE, ELodDirection.Axis.X, new Vec3i(-1, 0, 0)),
EAST(5, 4, 3, "east", ELodDirection.AxisDirection.POSITIVE, ELodDirection.Axis.X, new Vec3i(1, 0, 0));
public static final ELodDirection[] DIRECTIONS = new ELodDirection[] {
ELodDirection.UP,
ELodDirection.DOWN,
ELodDirection.WEST,
ELodDirection.EAST,
ELodDirection.NORTH,
ELodDirection.SOUTH };
DOWN(0, 1, -1, "down", EDhDirection.AxisDirection.NEGATIVE, EDhDirection.Axis.Y, new Vec3i(0, -1, 0)),
UP(1, 0, -1, "up", EDhDirection.AxisDirection.POSITIVE, EDhDirection.Axis.Y, new Vec3i(0, 1, 0)),
NORTH(2, 3, 2, "north", EDhDirection.AxisDirection.NEGATIVE, EDhDirection.Axis.Z, new Vec3i(0, 0, -1)),
SOUTH(3, 2, 0, "south", EDhDirection.AxisDirection.POSITIVE, EDhDirection.Axis.Z, new Vec3i(0, 0, 1)),
WEST(4, 5, 1, "west", EDhDirection.AxisDirection.NEGATIVE, EDhDirection.Axis.X, new Vec3i(-1, 0, 0)),
EAST(5, 4, 3, "east", EDhDirection.AxisDirection.POSITIVE, EDhDirection.Axis.X, new Vec3i(1, 0, 0));
/**
* Up, Down, West, East, North, South <br>
* Similar to {@link EDhDirection#OPPOSITE_DIRECTIONS}, just with a different order
*/
public static final EDhDirection[] CARDINAL_DIRECTIONS = new EDhDirection[] {
EDhDirection.UP,
EDhDirection.DOWN,
EDhDirection.WEST,
EDhDirection.EAST,
EDhDirection.NORTH,
EDhDirection.SOUTH };
/**
* Up, Down, South, North, East, West <br>
* Similar to {@link EDhDirection#CARDINAL_DIRECTIONS}, just with a different order
*/
public static final EDhDirection[] OPPOSITE_DIRECTIONS = new EDhDirection[] {
EDhDirection.UP,
EDhDirection.DOWN,
EDhDirection.SOUTH,
EDhDirection.NORTH,
EDhDirection.EAST,
EDhDirection.WEST };
/** North, South, East, West */ // TODO rename to state this is just X/Z or flat directions
public static final EDhDirection[] ADJ_DIRECTIONS = new EDhDirection[] {
EDhDirection.EAST,
EDhDirection.WEST,
EDhDirection.SOUTH,
EDhDirection.NORTH };
public static final ELodDirection[] OPPOSITE_DIRECTIONS = new ELodDirection[] {
ELodDirection.UP,
ELodDirection.DOWN,
ELodDirection.SOUTH,
ELodDirection.NORTH,
ELodDirection.EAST,
ELodDirection.WEST };
/** North, South, East, West */
public static final ELodDirection[] ADJ_DIRECTIONS = new ELodDirection[] {
ELodDirection.EAST,
ELodDirection.WEST,
ELodDirection.SOUTH,
ELodDirection.NORTH };
// private final int data3d;
// private final int oppositeIndex;
// private final int data2d;
private final String name;
private final ELodDirection.Axis axis;
private final ELodDirection.AxisDirection axisDirection;
private final EDhDirection.Axis axis;
private final EDhDirection.AxisDirection axisDirection;
private final Vec3i normal;
private static final ELodDirection[] VALUES = values();
private static final EDhDirection[] VALUES = values();
private static final Map<String, ELodDirection> BY_NAME = Arrays.stream(VALUES).collect(Collectors.toMap(ELodDirection::getName, (p_199787_0_) ->
private static final Map<String, EDhDirection> BY_NAME = Arrays.stream(VALUES).collect(Collectors.toMap(EDhDirection::getName, (p_199787_0_) ->
{
return p_199787_0_;
}));
@@ -117,7 +128,7 @@ public enum ELodDirection
ELodDirection(int p_i46016_3_, int p_i46016_4_, int p_i46016_5_, String p_i46016_6_, ELodDirection.AxisDirection p_i46016_7_, ELodDirection.Axis p_i46016_8_, Vec3i p_i46016_9_)
EDhDirection(int p_i46016_3_, int p_i46016_4_, int p_i46016_5_, String p_i46016_6_, EDhDirection.AxisDirection p_i46016_7_, EDhDirection.Axis p_i46016_8_, Vec3i p_i46016_9_)
{
// this.data3d = p_i46016_3_;
// this.data2d = p_i46016_5_;
@@ -218,7 +229,7 @@ public enum ELodDirection
// return this.data2d;
// }
public ELodDirection.AxisDirection getAxisDirection()
public EDhDirection.AxisDirection getAxisDirection()
{
return this.axisDirection;
}
@@ -228,7 +239,7 @@ public enum ELodDirection
// return from3DDataValue(this.oppositeIndex);
// }
public ELodDirection getClockWise()
public EDhDirection getClockWise()
{
switch (this)
{
@@ -245,7 +256,7 @@ public enum ELodDirection
}
}
public ELodDirection getCounterClockWise()
public EDhDirection getCounterClockWise()
{
switch (this)
{
@@ -267,12 +278,12 @@ public enum ELodDirection
return this.name;
}
public ELodDirection.Axis getAxis()
public EDhDirection.Axis getAxis()
{
return this.axis;
}
public static ELodDirection byName(String name)
public static EDhDirection byName(String name)
{
return name == null ? null : BY_NAME.get(name.toLowerCase(Locale.ROOT));
}
@@ -298,17 +309,17 @@ public enum ELodDirection
// return from2DDataValue(MathHelper.floor(p_176733_0_ / 90.0D + 0.5D) & 3);
// }
public static ELodDirection fromAxisAndDirection(ELodDirection.Axis p_211699_0_, ELodDirection.AxisDirection p_211699_1_)
public static EDhDirection fromAxisAndDirection(EDhDirection.Axis p_211699_0_, EDhDirection.AxisDirection p_211699_1_)
{
switch (p_211699_0_)
{
case X:
return p_211699_1_ == ELodDirection.AxisDirection.POSITIVE ? EAST : WEST;
return p_211699_1_ == EDhDirection.AxisDirection.POSITIVE ? EAST : WEST;
case Y:
return p_211699_1_ == ELodDirection.AxisDirection.POSITIVE ? UP : DOWN;
return p_211699_1_ == EDhDirection.AxisDirection.POSITIVE ? UP : DOWN;
case Z:
default:
return p_211699_1_ == ELodDirection.AxisDirection.POSITIVE ? SOUTH : NORTH;
return p_211699_1_ == EDhDirection.AxisDirection.POSITIVE ? SOUTH : NORTH;
}
}
@@ -345,9 +356,9 @@ public enum ELodDirection
// return lodDirection;
// }
public static ELodDirection get(ELodDirection.AxisDirection p_181076_0_, ELodDirection.Axis p_181076_1_)
public static EDhDirection get(EDhDirection.AxisDirection p_181076_0_, EDhDirection.Axis p_181076_1_)
{
for (ELodDirection lodDirection : VALUES)
for (EDhDirection lodDirection : VALUES)
{
if (lodDirection.getAxisDirection() == p_181076_0_ && lodDirection.getAxis() == p_181076_1_)
{
@@ -371,7 +382,7 @@ public enum ELodDirection
// return this.normal.getX() * f1 + this.normal.getZ() * f2 > 0.0F;
// }
public enum Axis implements Predicate<ELodDirection>
public enum Axis implements Predicate<EDhDirection>
{
X("x")
{
@@ -416,9 +427,9 @@ public enum ELodDirection
}
};
private static final ELodDirection.Axis[] VALUES = values();
private static final EDhDirection.Axis[] VALUES = values();
private static final Map<String, ELodDirection.Axis> BY_NAME = Arrays.stream(VALUES).collect(Collectors.toMap(ELodDirection.Axis::getName, (p_199785_0_) ->
private static final Map<String, EDhDirection.Axis> BY_NAME = Arrays.stream(VALUES).collect(Collectors.toMap(EDhDirection.Axis::getName, (p_199785_0_) ->
{
return p_199785_0_;
}));
@@ -429,7 +440,7 @@ public enum ELodDirection
this.name = name;
}
public static ELodDirection.Axis byName(String name)
public static EDhDirection.Axis byName(String name)
{
return BY_NAME.get(name.toLowerCase(Locale.ROOT));
}
@@ -461,7 +472,7 @@ public enum ELodDirection
// }
@Override
public boolean test(ELodDirection p_test_1_)
public boolean test(EDhDirection p_test_1_)
{
return p_test_1_ != null && p_test_1_.getAxis() == this;
}
@@ -510,7 +521,7 @@ public enum ELodDirection
return this.name;
}
public ELodDirection.AxisDirection opposite()
public EDhDirection.AxisDirection opposite()
{
return this == POSITIVE ? NEGATIVE : POSITIVE;
}
@@ -205,8 +205,9 @@ public class FullDataMetaFile extends AbstractMetaDataContainerFile implements I
})
.whenComplete((fullDataSource, ex) ->
{
if (ex != null && !LodUtil.isInterruptOrReject(ex)) {
LOGGER.error("Error updating file "+this.file+": ", ex);
if (ex != null && !LodUtil.isInterruptOrReject(ex))
{
LOGGER.error("Error updating file ["+this.file+"]: ", ex);
}
if (fullDataSource != null) {
@@ -0,0 +1,226 @@
package com.seibel.distanthorizons.core.generation;
import com.seibel.distanthorizons.core.enums.EDhDirection;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.pos.DhBlockPos;
import com.seibel.distanthorizons.core.pos.DhChunkPos;
import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
import org.apache.logging.log4j.Logger;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
/**
* This logic was roughly based on
* <a href="https://github.com/PaperMC/Starlight/blob/acc8ed9634bbe27ec68e8842e420948bfa9707e7/TECHNICAL_DETAILS.md">Starlight's technical documentation</a>
* although there were some changes due to how our lighting engine works in comparison to Minecraft's.
*/
public class DhLightingEngine
{
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
public static final DhLightingEngine INSTANCE = new DhLightingEngine();
private DhLightingEngine() { }
/**
* Note: depending on the implementation of {@link IChunkWrapper#setDhBlockLight(int, int, int, int)} and {@link IChunkWrapper#setDhSkyLight(int, int, int, int)}
* the light values may be stored in the wrapper itself instead of the wrapped chunk object.
* If that is the case unwrapping the chunk will undo any work this method did.
*
* @param centerChunk the chunk we want to apply lighting to
* @param nearbyChunkList should also contain centerChunk
* @param maxSkyLight should be a value between 0 and 15
*/
public void lightChunks(IChunkWrapper centerChunk, List<IChunkWrapper> nearbyChunkList, int maxSkyLight)
{
DhChunkPos centerChunkPos = centerChunk.getChunkPos();
HashMap<DhChunkPos, IChunkWrapper> chunksByChunkPos = new HashMap<>(9);
LinkedList<LightPos> blockLightPosQueue = new LinkedList<>();
LinkedList<LightPos> skyLightPosQueue = new LinkedList<>();
// generate the list of chunk pos we need,
// currently a 3x3 grid
HashSet<DhChunkPos> requestedAdjacentPositions = new HashSet<>(9);
for (int xOffset = -1; xOffset <= 1; xOffset++)
{
for (int zOffset = -1; zOffset <= 1; zOffset++)
{
DhChunkPos adjacentPos = new DhChunkPos(centerChunkPos.x+xOffset, centerChunkPos.z+zOffset);
requestedAdjacentPositions.add(adjacentPos);
}
}
// find all adjacent chunks
// and get any necessary info from them
for (IChunkWrapper chunk : nearbyChunkList)
{
if (chunk != null && requestedAdjacentPositions.contains(chunk.getChunkPos()))
{
// remove the newly found position
requestedAdjacentPositions.remove(chunk.getChunkPos());
// add the adjacent chunk
chunksByChunkPos.put(chunk.getChunkPos(), chunk);
// get and set the adjacent chunk's initial block lights
List<DhBlockPos> blockLightPosList = chunk.getBlockLightPosList();
for (DhBlockPos blockLightPos : blockLightPosList)
{
// get the light
DhBlockPos relLightBlockPos = blockLightPos.convertToChunkRelativePos();
IBlockStateWrapper blockState = chunk.getBlockState(relLightBlockPos);
int lightValue = blockState.getLightEmission();
blockLightPosQueue.add(new LightPos(blockLightPos, lightValue));
// set the light
DhBlockPos relBlockPos = blockLightPos.convertToChunkRelativePos();
chunk.setDhBlockLight(relBlockPos.x, relBlockPos.y, relBlockPos.z, lightValue);
}
// get and set the adjacent chunk's initial skylights,
// if the dimension has skylights
if (maxSkyLight > 0)
{
// get the adjacent chunk's sky lights
for (int relX = 0; relX < LodUtil.CHUNK_WIDTH; relX++) // relative block pos
{
for (int relZ = 0; relZ < LodUtil.CHUNK_WIDTH; relZ++)
{
// get the light
int maxY = chunk.getLightBlockingHeightMapValue(relX, relZ);
DhBlockPos skyLightPos = new DhBlockPos(chunk.getMinBlockX() + relX, maxY, chunk.getMinBlockZ() + relZ);
skyLightPosQueue.add(new LightPos(skyLightPos, maxSkyLight));
// set the light
DhBlockPos relBlockPos = skyLightPos.convertToChunkRelativePos();
chunk.setDhSkyLight(relBlockPos.x, relBlockPos.y, relBlockPos.z, maxSkyLight);
}
}
}
}
if (requestedAdjacentPositions.isEmpty())
{
// we found every chunk we needed, we don't need to keep iterating
break;
}
}
// validate that at least 1 chunk was found
if (chunksByChunkPos.size() == 0)
{
LOGGER.warn("Attempted to generate lighting for position ["+centerChunkPos+"], but neither that chunk nor any adjacent chunks were found. No chunk lighting was performed.");
return;
}
// block light
this.propagateLightPosList(blockLightPosQueue, chunksByChunkPos,
(neighbourChunk, relBlockPos) -> neighbourChunk.getDhBlockLight(relBlockPos.x, relBlockPos.y, relBlockPos.z),
(neighbourChunk, relBlockPos, newLightValue) -> neighbourChunk.setDhBlockLight(relBlockPos.x, relBlockPos.y, relBlockPos.z, newLightValue));
// sky light
this.propagateLightPosList(skyLightPosQueue, chunksByChunkPos,
(neighbourChunk, relBlockPos) -> neighbourChunk.getDhSkyLight(relBlockPos.x, relBlockPos.y, relBlockPos.z),
(neighbourChunk, relBlockPos, newLightValue) -> neighbourChunk.setDhSkyLight(relBlockPos.x, relBlockPos.y, relBlockPos.z, newLightValue));
LOGGER.trace("Finished generating lighting for chunk: ["+centerChunkPos+"]");
}
/** Applies each {@link LightPos} from the queue to the given set of {@link IChunkWrapper}'s. */
private void propagateLightPosList(
LinkedList<LightPos> lightPosQueue, HashMap<DhChunkPos, IChunkWrapper> chunksByChunkPos,
IGetLightFunc getLightFunc, ISetLightFunc setLightFunc)
{
// update each light position
while (!lightPosQueue.isEmpty())
{
LightPos lightPos = lightPosQueue.poll();
DhBlockPos pos = lightPos.pos;
int lightValue = lightPos.lightValue;
// propagate the lighting in each cardinal direction, IE: -x, +x, -y, +y, -z, +z
for (EDhDirection direction : EDhDirection.CARDINAL_DIRECTIONS)
{
DhBlockPos neighbourBlockPos = pos.offset(direction);
DhChunkPos neighbourChunkPos = new DhChunkPos(neighbourBlockPos);
// converting the block pos into a relative position is necessary for accessing the light values in the chunk
DhBlockPos relNeighbourBlockPos = neighbourBlockPos.convertToChunkRelativePos();
// only continue if the light position is inside one of our chunks
IChunkWrapper neighbourChunk = chunksByChunkPos.get(neighbourChunkPos);
if (neighbourChunk == null)
{
// the light pos is outside our generator's range, ignore it
continue;
}
int currentBlockLight = getLightFunc.getLight(neighbourChunk, relNeighbourBlockPos);
if (currentBlockLight >= (lightValue - 1))
{
// short circuit for when the light value at this position
// is already greater-than what we could set it
continue;
}
IBlockStateWrapper neighbourBlockState = neighbourChunk.getBlockState(relNeighbourBlockPos);
// Math.max(1, ...) is used so that the propagated light level always drops by at least 1, preventing infinite cycles.
int targetLevel = lightValue - Math.max(1, neighbourBlockState.getOpacity());
if (targetLevel > currentBlockLight)
{
// this position is darker than the new light value, update/set it
setLightFunc.setLight(neighbourChunk, relNeighbourBlockPos, targetLevel);
// now that light has been propagated to this blockPos
// we need to queue it up so its neighbours can be propagated as well
lightPosQueue.add(new LightPos(neighbourBlockPos, targetLevel));
}
}
}
// propagation complete
}
//================//
// helper classes //
//================//
@FunctionalInterface
interface IGetLightFunc { int getLight(IChunkWrapper chunk, DhBlockPos pos); }
@FunctionalInterface
interface ISetLightFunc { void setLight(IChunkWrapper chunk, DhBlockPos pos, int lightValue); }
private static class LightPos
{
public final DhBlockPos pos;
public final int lightValue;
public LightPos(DhBlockPos pos, int lightValue)
{
this.pos = pos;
this.lightValue = lightValue;
}
}
}
@@ -4,7 +4,7 @@ import com.seibel.distanthorizons.core.file.fullDatafile.GeneratedFullDataFileHa
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
public interface IDhServerLevel extends IDhLevel, GeneratedFullDataFileHandler.IOnWorldGenCompleteListener
{
{
void serverTick();
void doWorldGen();
@@ -19,6 +19,9 @@
package com.seibel.distanthorizons.core.pos;
import com.seibel.distanthorizons.core.enums.EDhDirection;
import com.seibel.distanthorizons.core.util.LodUtil;
import java.util.Objects;
public class DhBlockPos {
@@ -110,10 +113,23 @@ public class DhBlockPos {
return asLong(x, y, z);
}
public DhBlockPos offset(int x, int y, int z)
{
return new DhBlockPos(this.x + x, this.y + y, this.z + z);
}
public DhBlockPos offset(EDhDirection direction) { return this.offset(direction.getNormal().x, direction.getNormal().y, direction.getNormal().z); }
public DhBlockPos offset(int x, int y, int z) { return new DhBlockPos(this.x + x, this.y + y, this.z + z); }
/** Limits the block position to a value between 0 and 15 (inclusive) */
public DhBlockPos convertToChunkRelativePos()
{
// move the position into the range -15 and +15
int relX = (this.x % LodUtil.CHUNK_WIDTH);
// if the position is negative move it into the range 0 and 15
relX = (relX < 0) ? (relX + LodUtil.CHUNK_WIDTH) : relX;
int relZ = (this.z % LodUtil.CHUNK_WIDTH);
relZ = (relZ < 0) ? (relZ + LodUtil.CHUNK_WIDTH) : relZ;
// the y value shouldn't need to be changed
return new DhBlockPos(relX, this.y, relZ);
}
/**
* Can be used to quickly determine the rough distance between two points<Br>
@@ -1,6 +1,6 @@
package com.seibel.distanthorizons.core.pos;
import com.seibel.distanthorizons.core.enums.ELodDirection;
import com.seibel.distanthorizons.core.enums.EDhDirection;
import com.seibel.distanthorizons.core.network.protocol.INetworkObject;
import com.seibel.distanthorizons.coreapi.util.BitShiftUtil;
import com.seibel.distanthorizons.core.util.LodUtil;
@@ -187,7 +187,7 @@ public class DhSectionPos implements Comparable<DhSectionPos>, INetworkObject
public DhSectionPos getParentPos() { return new DhSectionPos((byte) (this.sectionDetailLevel + 1), BitShiftUtil.half(this.sectionX), BitShiftUtil.half(this.sectionZ)); }
public DhSectionPos getAdjacentPos(ELodDirection dir)
public DhSectionPos getAdjacentPos(EDhDirection dir)
{
return new DhSectionPos(this.sectionDetailLevel,
this.sectionX + dir.getNormal().x,
@@ -2,6 +2,7 @@ package com.seibel.distanthorizons.core.render;
import com.seibel.distanthorizons.core.dataObjects.render.ColumnRenderSource;
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.ColumnRenderBufferBuilder;
import com.seibel.distanthorizons.core.enums.EDhDirection;
import com.seibel.distanthorizons.core.file.renderfile.ILodRenderSourceProvider;
import com.seibel.distanthorizons.core.level.IDhClientLevel;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
@@ -11,7 +12,6 @@ import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.util.objects.Reference;
import com.seibel.distanthorizons.core.util.objects.quadTree.QuadTree;
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.ColumnRenderBuffer;
import com.seibel.distanthorizons.core.enums.ELodDirection;
import com.seibel.distanthorizons.core.render.renderer.DebugRenderer;
import org.apache.logging.log4j.Logger;
@@ -20,7 +20,6 @@ import java.util.Objects;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
/**
@@ -224,8 +223,8 @@ public class LodRenderSection implements IDebugRenderable
private LodRenderSection[] getNeighbors()
{
LodRenderSection[] adjacents = new LodRenderSection[ELodDirection.ADJ_DIRECTIONS.length];
for (ELodDirection direction : ELodDirection.ADJ_DIRECTIONS) {
LodRenderSection[] adjacents = new LodRenderSection[EDhDirection.ADJ_DIRECTIONS.length];
for (EDhDirection direction : EDhDirection.ADJ_DIRECTIONS) {
try {
DhSectionPos adjPos = pos.getAdjacentPos(direction);
LodRenderSection adjRenderSection = parentQuadTree.getValue(adjPos);
@@ -285,8 +284,8 @@ public class LodRenderSection implements IDebugRenderable
tellNeighborsUpdated();
}
LodRenderSection[] adjacents = getNeighbors();
ColumnRenderSource[] adjacentSources = new ColumnRenderSource[ELodDirection.ADJ_DIRECTIONS.length];
for (int i = 0; i < ELodDirection.ADJ_DIRECTIONS.length; i++) {
ColumnRenderSource[] adjacentSources = new ColumnRenderSource[EDhDirection.ADJ_DIRECTIONS.length];
for (int i = 0; i < EDhDirection.ADJ_DIRECTIONS.length; i++) {
LodRenderSection adj = adjacents[i];
if (adj != null) {
adjacentSources[i] = adj.getRenderSource();
@@ -1,11 +1,11 @@
package com.seibel.distanthorizons.core.render;
import com.seibel.distanthorizons.core.enums.EDhDirection;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.pos.DhSectionPos;
import com.seibel.distanthorizons.core.pos.Pos2D;
import com.seibel.distanthorizons.core.util.objects.SortedArraySet;
import com.seibel.distanthorizons.core.util.objects.quadTree.QuadNode;
import com.seibel.distanthorizons.core.enums.ELodDirection;
import com.seibel.distanthorizons.core.render.renderer.LodRenderer;
import com.seibel.distanthorizons.coreapi.util.math.Vec3f;
import org.apache.logging.log4j.Logger;
@@ -45,16 +45,16 @@ public class RenderBufferHandler
*/
public void buildRenderListAndUpdateSections(Vec3f lookForwardVector)
{
ELodDirection[] axisDirections = new ELodDirection[3];
EDhDirection[] axisDirections = new EDhDirection[3];
// Do the axis that are the longest first (i.e. the largest absolute value of the lookForwardVector),
// with the sign being the opposite of the respective lookForwardVector component's sign
float absX = Math.abs(lookForwardVector.x);
float absY = Math.abs(lookForwardVector.y);
float absZ = Math.abs(lookForwardVector.z);
ELodDirection xDir = lookForwardVector.x < 0 ? ELodDirection.EAST : ELodDirection.WEST;
ELodDirection yDir = lookForwardVector.y < 0 ? ELodDirection.UP : ELodDirection.DOWN;
ELodDirection zDir = lookForwardVector.z < 0 ? ELodDirection.SOUTH : ELodDirection.NORTH;
EDhDirection xDir = lookForwardVector.x < 0 ? EDhDirection.EAST : EDhDirection.WEST;
EDhDirection yDir = lookForwardVector.y < 0 ? EDhDirection.UP : EDhDirection.DOWN;
EDhDirection zDir = lookForwardVector.z < 0 ? EDhDirection.SOUTH : EDhDirection.NORTH;
if (absX >= absY && absX >= absZ)
{
@@ -112,7 +112,7 @@ public class RenderBufferHandler
return bManhattanDistance - aManhattanDistance;
}
for (ELodDirection axisDirection : axisDirections)
for (EDhDirection axisDirection : axisDirections)
{
if (axisDirection.getAxis().isVertical())
{
@@ -120,7 +120,7 @@ public class RenderBufferHandler
}
int abPosDifference;
if (axisDirection.getAxis().equals(ELodDirection.Axis.X))
if (axisDirection.getAxis().equals(EDhDirection.Axis.X))
{
abPosDifference = aPos.x - bPos.x;
}
@@ -134,7 +134,7 @@ public class RenderBufferHandler
continue;
}
if (axisDirection.getAxisDirection().equals(ELodDirection.AxisDirection.NEGATIVE))
if (axisDirection.getAxisDirection().equals(EDhDirection.AxisDirection.NEGATIVE))
{
abPosDifference = -abPosDifference; // Reverse the sign
}
@@ -30,6 +30,9 @@ import com.seibel.distanthorizons.core.render.glObject.GLProxy;
import com.seibel.distanthorizons.core.render.glObject.GLState;
import com.seibel.distanthorizons.core.render.glObject.buffer.GLVertexBuffer;
import com.seibel.distanthorizons.core.render.glObject.buffer.QuadElementBuffer;
import com.seibel.distanthorizons.core.render.renderer.shaders.DarkShader;
import com.seibel.distanthorizons.core.render.renderer.shaders.FogShader;
import com.seibel.distanthorizons.core.render.renderer.shaders.SSAORenderer;
import com.seibel.distanthorizons.core.render.renderer.shaders.SSAOShader;
import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.util.RenderUtil;
@@ -76,7 +79,10 @@ public class LodRenderer
public void setupOffset(DhBlockPos pos) {
Vec3d cam = MC_RENDER.getCameraExactPosition();
shaderProgram.setModelPos(new Vec3f((float) (pos.x - cam.x), (float) (pos.y - cam.y), (float) (pos.z - cam.z)));
Vec3f modelPos = new Vec3f((float) (pos.x - cam.x), (float) (pos.y - cam.y), (float) (pos.z - cam.z));
shaderProgram.setModelPos(modelPos);
// FogShader.INSTANCE.setModelPos(modelPos);
}
public void drawVbo(GLVertexBuffer vbo) {
@@ -203,6 +209,8 @@ public class LodRenderer
if (newConfig != null) {
shaderProgram.free();
shaderProgram = new LodRenderProgram(newConfig);
// FogShader.INSTANCE.free();
// FogShader.INSTANCE = new FogShader(newConfig);
}
shaderProgram.bind();
}
@@ -244,7 +252,12 @@ public class LodRenderer
bufferHandler.renderOpaque(this);
if (Config.Client.Advanced.Graphics.Quality.ssao.get()) {
SSAOShader.INSTANCE.render(partialTicks);
// SSAOShader.INSTANCE.render(partialTicks);
SSAORenderer.INSTANCE.render(partialTicks);
}
{
// FogShader.INSTANCE.render(partialTicks);
// DarkShader.INSTANCE.render(partialTicks); // A test shader to make the world darker
}
//======================//
@@ -348,6 +361,7 @@ public class LodRenderer
isSetupComplete = false;
EVENT_LOGGER.info("Renderer Cleanup Started");
shaderProgram.free();
// FogShader.INSTANCE.free();
if (quadIBO != null) quadIBO.destroy(false);
EVENT_LOGGER.info("Renderer Cleanup Complete");
}
@@ -6,6 +6,7 @@ import com.seibel.distanthorizons.core.render.glObject.GLState;
import com.seibel.distanthorizons.core.render.glObject.buffer.GLVertexBuffer;
import com.seibel.distanthorizons.core.render.glObject.shader.ShaderProgram;
import com.seibel.distanthorizons.core.render.glObject.vertexAttribute.VertexAttribute;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL32;
@@ -14,6 +15,7 @@ import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public abstract class AbstractShaderRenderer {
protected static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
protected static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
private static final float[] box_vertices = {
@@ -106,7 +108,7 @@ public abstract class AbstractShaderRenderer {
this.setApplyShaderUniforms(partialTicks);
}
GL32.glEnable(GL11.GL_BLEND);
GL32.glBlendFunc(GL32.GL_ZERO, GL32.GL_SRC_ALPHA);
GL32.glBlendFunc(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA);
GL32.glBindFramebuffer(GL32.GL_FRAMEBUFFER, MC_RENDER.getTargetFrameBuffer());
GL32.glActiveTexture(GL32.GL_TEXTURE0);
GL32.glBindTexture(GL32.GL_TEXTURE_2D, shaderTexture);
@@ -149,4 +151,10 @@ public abstract class AbstractShaderRenderer {
boxBuffer.bind();
boxBuffer.uploadBuffer(buffer, box_vertices.length, EGpuUploadMethod.DATA, box_vertices.length * Float.BYTES);
}
public void free() {
this.shader.free();
if (this.applyShader != null)
this.applyShader.free();
}
}
@@ -0,0 +1,11 @@
package com.seibel.distanthorizons.core.render.renderer.shaders;
import com.seibel.distanthorizons.core.render.glObject.shader.ShaderProgram;
public class DarkShader extends AbstractShaderRenderer {
public static DarkShader INSTANCE = new DarkShader();
protected DarkShader() {
super(new ShaderProgram("shaders/normal.vert", "shaders/test/dark.frag", "fragColor", new String[] { "vPosition", "color" }));
}
}
@@ -0,0 +1,100 @@
package com.seibel.distanthorizons.core.render.renderer.shaders;
import com.seibel.distanthorizons.api.enums.rendering.EFogColorMode;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.render.fog.LodFogConfig;
import com.seibel.distanthorizons.core.render.glObject.shader.Shader;
import com.seibel.distanthorizons.core.render.glObject.shader.ShaderProgram;
import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.util.RenderUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
import com.seibel.distanthorizons.coreapi.util.math.Vec3f;
import org.lwjgl.opengl.GL32;
import java.awt.*;
public class FogShader extends AbstractShaderRenderer {
public static FogShader INSTANCE = new FogShader(LodFogConfig.generateFogConfig());
private static final IVersionConstants VERSION_CONSTANTS = SingletonInjector.INSTANCE.get(IVersionConstants.class);
// public final int modelOffsetUniform;
public final int worldYOffsetUniform;
// Fog Uniforms
public final int fogColorUniform;
public final int fogScaleUniform;
public final int fogVerticalScaleUniform;
public final int nearFogStartUniform;
public final int nearFogLengthUniform;;
public final int fullFogModeUniform;
public FogShader(LodFogConfig fogConfig) {
// TODO & Note: This code is a bit jank, so try to make it better later (preferably not using something to process the shader)
// This code is just a temp fix so that it looks fine for the time being
// and even with the jank soloution, i cannot get it to work
super(new ShaderProgram(
() -> Shader.loadFile("shaders/fog/fog.vert", false, new StringBuilder()).toString(),
() -> fogConfig.loadAndProcessFragShader("shaders/fog/fog.frag", false).toString(),
"fragColor", new String[] { "vPosition", "vPos", "color" }
));
// modelOffsetUniform = this.shader.getUniformLocation("modelOffset");
worldYOffsetUniform = this.shader.getUniformLocation("worldYOffset");
// Fog uniforms
fogColorUniform = this.shader.getUniformLocation("fogColor");
fullFogModeUniform = this.shader.getUniformLocation("fullFogMode");
fogScaleUniform = this.shader.tryGetUniformLocation("fogScale");
fogVerticalScaleUniform = this.shader.tryGetUniformLocation("fogVerticalScale");
// near
nearFogStartUniform = this.shader.tryGetUniformLocation("nearFogStart");
nearFogLengthUniform = this.shader.tryGetUniformLocation("nearFogLength");
}
@Override
void setShaderUniforms(float partialTicks) {
int lodDrawDistance = RenderUtil.getFarClipPlaneDistanceInBlocks();
int vanillaDrawDistance = MC_RENDER.getRenderDistance() * LodUtil.CHUNK_WIDTH;
// super.bind();
vanillaDrawDistance += 32; // Give it a 2 chunk boundary for near fog.
this.shader.setUniform(worldYOffsetUniform, (float) MC.getWrappedClientWorld().getMinHeight());
// Fog
this.shader.setUniform(fullFogModeUniform, MC_RENDER.isFogStateSpecial() ? 1 : 0);
this.shader.setUniform(fogColorUniform, MC_RENDER.isFogStateSpecial() ? getSpecialFogColor(partialTicks) : getFogColor(partialTicks));
float nearFogLen = vanillaDrawDistance * 0.2f / lodDrawDistance;
float nearFogStart = vanillaDrawDistance * (VERSION_CONSTANTS.isVanillaRenderedChunkSquare() ? (float)Math.sqrt(2.) : 1.f) / lodDrawDistance;
if (nearFogStartUniform != -1) this.shader.setUniform(nearFogStartUniform, nearFogStart);
if (nearFogLengthUniform != -1) this.shader.setUniform(nearFogLengthUniform, nearFogLen);
if (fogScaleUniform != -1) this.shader.setUniform(fogScaleUniform, 1.f/lodDrawDistance);
if (fogVerticalScaleUniform != -1) this.shader.setUniform(fogVerticalScaleUniform, 1.f/MC.getWrappedClientWorld().getHeight());
}
private Color getFogColor(float partialTicks)
{
Color fogColor;
if (Config.Client.Advanced.Graphics.Fog.colorMode.get() == EFogColorMode.USE_SKY_COLOR)
fogColor = MC_RENDER.getSkyColor();
else
fogColor = MC_RENDER.getFogColor(partialTicks);
return fogColor;
}
private Color getSpecialFogColor(float partialTicks)
{
return MC_RENDER.getSpecialFogColor(partialTicks);
}
public void setModelPos(Vec3f modelPos) {
// this.shader.setUniform(modelOffsetUniform, modelPos);
}
}
@@ -0,0 +1,199 @@
package com.seibel.distanthorizons.core.render.renderer.shaders;
import com.seibel.distanthorizons.api.enums.config.EGpuUploadMethod;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.render.glObject.GLState;
import com.seibel.distanthorizons.core.render.glObject.buffer.GLVertexBuffer;
import com.seibel.distanthorizons.core.render.glObject.shader.ShaderProgram;
import com.seibel.distanthorizons.core.render.glObject.vertexAttribute.VertexAttribute;
import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.util.RenderUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL32;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
// TODO: Move over to SSAOShader
// For some reason this version looks slightly different to that, even tough there isnt much visible change in the code
public class SSAORenderer {
public static SSAORenderer INSTANCE = new SSAORenderer();
public SSAORenderer() {
}
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
private static final float[] box_vertices = {
-1, -1,
1, -1,
1, 1,
-1, -1,
1, 1,
-1, 1,
};
ShaderProgram ssaoShader;
ShaderProgram applyShader;
GLVertexBuffer boxBuffer;
VertexAttribute va;
boolean init = false;
private static final int MAX_KERNEL_SIZE = 32;
private float[] kernel = new float[MAX_KERNEL_SIZE * 3];
public void init() {
if (init) return;
init = true;
va = VertexAttribute.create();
va.bind();
// Pos
va.setVertexAttribute(0, 0, VertexAttribute.VertexPointer.addVec2Pointer(false));
va.completeAndCheck(Float.BYTES * 2);
ssaoShader = new ShaderProgram("shaders/normal.vert", "shaders/ssao/ao.frag",
"fragColor", new String[]{"vPosition"});
applyShader = new ShaderProgram("shaders/normal.vert", "shaders/ssao/apply-frag.frag",
"fragColor", new String[]{"vPosition"});
// Generate kernel
kernel = genKernel();
// Framebuffer
createBuffer();
}
private int width = -1;
private int height = -1;
private int ssaoFramebuffer = -1;
private int ssaoTexture = -1;
private void createFramebuffer(int width, int height) {
if (ssaoFramebuffer != -1) {
GL32.glDeleteFramebuffers(ssaoFramebuffer);
ssaoFramebuffer = -1;
}
if (ssaoTexture != -1) {
GL32.glDeleteTextures(ssaoTexture);
ssaoTexture = -1;
}
ssaoFramebuffer = GL32.glGenFramebuffers();
GL32.glBindFramebuffer(GL32.GL_FRAMEBUFFER, ssaoFramebuffer);
ssaoTexture = GL32.glGenTextures();
GL32.glBindTexture(GL32.GL_TEXTURE_2D, ssaoTexture);
GL32.glTexImage2D(GL32.GL_TEXTURE_2D, 0, GL32.GL_RED, width, height, 0, GL32.GL_RED, GL32.GL_FLOAT, (ByteBuffer) null);
GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MIN_FILTER, GL32.GL_NEAREST);
GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MAG_FILTER, GL32.GL_NEAREST);
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_TEXTURE_2D, ssaoTexture, 0);
}
private void createBuffer() {
ByteBuffer buffer = ByteBuffer.allocateDirect(box_vertices.length * Float.BYTES);
buffer.order(ByteOrder.nativeOrder());
buffer.asFloatBuffer().put(box_vertices);
buffer.rewind();
boxBuffer = new GLVertexBuffer(false);
boxBuffer.bind();
boxBuffer.uploadBuffer(buffer, box_vertices.length, EGpuUploadMethod.DATA, box_vertices.length * Float.BYTES);
}
private static float[] genKernel() {
float[] kernel = new float[MAX_KERNEL_SIZE * 3];
for (int i = 0; i < MAX_KERNEL_SIZE; i++) {
float sampleX = (float) (Math.random() * 2.0 - 1.0);
float sampleY = (float) (Math.random() * 2.0 - 1.0);
float sampleZ = (float) Math.random();
// Normalize
float magnitude = (float) Math.sqrt(Math.pow(sampleX, 2) + Math.pow(sampleY, 2) + Math.pow(sampleZ, 2));
sampleX /= magnitude;
sampleY /= magnitude;
sampleZ /= magnitude;
float scale = i / (float) MAX_KERNEL_SIZE;
float interpolatedScale = (float) (0.1 + (scale * scale) * (0.9));
sampleX *= interpolatedScale;
sampleY *= interpolatedScale;
sampleZ *= interpolatedScale;
kernel[i * 3] = sampleX;
kernel[i * 3 + 1] = sampleY;
kernel[i * 3 + 2] = sampleZ;
}
return kernel;
}
public void render(float partialTicks) {
GLState state = new GLState();
init();
//GL32.glDepthMask(false);
int width = MC_RENDER.getTargetFrameBufferViewportWidth();
int height = MC_RENDER.getTargetFrameBufferViewportHeight();
if (this.width != width || this.height != height) {
this.width = width;
this.height = height;
createFramebuffer(width, height);
}
GL32.glBindFramebuffer(GL32.GL_FRAMEBUFFER, ssaoFramebuffer);
GL32.glViewport(0, 0, width, height);
GL32.glDisable(GL32.GL_DEPTH_TEST);
GL32.glDisable(GL32.GL_BLEND);
GL32.glDisable(GL32.GL_SCISSOR_TEST);
Mat4f perspective = Mat4f.perspective(
(float) MC_RENDER.getFov(partialTicks),
MC_RENDER.getTargetFrameBufferViewportWidth() / (float) MC_RENDER.getTargetFrameBufferViewportHeight(),
RenderUtil.getNearClipPlaneDistanceInBlocks(partialTicks),
(float) ((RenderUtil.getFarClipPlaneDistanceInBlocks() + LodUtil.REGION_WIDTH) * Math.sqrt(2)));
ssaoShader.bind();
ssaoShader.setUniform(ssaoShader.getUniformLocation("gProj"), perspective);
ssaoShader.setUniform(ssaoShader.getUniformLocation("gSampleRad"), 3.0f);
ssaoShader.setUniform(ssaoShader.getUniformLocation("gFactor"), 0.8f);
ssaoShader.setUniform(ssaoShader.getUniformLocation("gPower"), 1.0f);
va.bind();
va.bindBufferToAllBindingPoint(boxBuffer.getId());
GL32.glActiveTexture(GL32.GL_TEXTURE0);
GL32.glBindTexture(GL32.GL_TEXTURE_2D, MC_RENDER.getDepthTextureId());
GL32.glUniform3fv(ssaoShader.getUniformLocation("gKernel"), kernel);
GL32.glUniform1i(ssaoShader.getUniformLocation("gDepthMap"), 0);
GL32.glDrawArrays(GL32.GL_TRIANGLES, 0, 6);
applyShader.bind();
GL32.glEnable(GL11.GL_BLEND);
GL32.glBlendFunc(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA);
GL32.glBindFramebuffer(GL32.GL_FRAMEBUFFER, MC_RENDER.getTargetFrameBuffer());
GL32.glActiveTexture(GL32.GL_TEXTURE0);
GL32.glBindTexture(GL32.GL_TEXTURE_2D, ssaoTexture);
GL32.glDrawArrays(GL32.GL_TRIANGLES, 0, 6);
//GL32.glBindFramebuffer(GL32.GL_READ_FRAMEBUFFER, ssaoFramebuffer);
//GL32.glBindFramebuffer(GL32.GL_DRAW_FRAMEBUFFER, MC_RENDER.getTargetFrameBuffer());
//GL32.glBlitFramebuffer(
// 0, 0, width, height,
// 0, 0, width, height,
// GL11.GL_COLOR_BUFFER_BIT,
// GL11.GL_NEAREST
//);
state.restore();
}
public void free() {
ssaoShader.free();
applyShader.free();
}
}
@@ -15,9 +15,9 @@ public class SSAOShader extends AbstractShaderRenderer {
public SSAOShader() {
super(
new ShaderProgram("shaders/ssao/ao.vert", "shaders/ssao/ao.frag",
new ShaderProgram("shaders/normal.vert", "shaders/ssao/ao.frag",
"fragColor", new String[]{"vPos"}),
new ShaderProgram("shaders/ssao/ao.vert", "shaders/ssao/apply-frag.frag",
new ShaderProgram("shaders/normal.vert", "shaders/ssao/apply-frag.frag",
"fragColor", new String[]{"vPos"})
);
@@ -2,14 +2,17 @@ package com.seibel.distanthorizons.core.wrapperInterfaces.block;
import com.seibel.distanthorizons.api.interfaces.block.IDhApiBlockStateWrapper;
/**
* A Minecraft version independent way of handling Blocks.
*
* @author James Seibel
* @version 2022-11-12
*/
/** A Minecraft version independent way of handling Blocks. */
public interface IBlockStateWrapper extends IDhApiBlockStateWrapper
{
String serialize();
/**
* Returning a value of 0 means the block is completely transparent. <br.
* Returning a value of 15 means the block is completely opaque.
*/
int getOpacity();
int getLightEmission();
}
@@ -19,14 +19,20 @@
package com.seibel.distanthorizons.core.wrapperInterfaces.chunk;
import com.seibel.distanthorizons.core.pos.DhBlockPos;
import com.seibel.distanthorizons.core.pos.DhBlockPos2D;
import com.seibel.distanthorizons.core.pos.DhChunkPos;
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IBindable;
import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
import java.util.List;
public interface IChunkWrapper extends IBindable
{
DhChunkPos getChunkPos();
default int getHeight() { return this.getMaxBuildHeight() - this.getMinBuildHeight(); }
int getMinBuildHeight();
int getMaxBuildHeight();
@@ -39,27 +45,44 @@ public interface IChunkWrapper extends IBindable
*/
int getLightBlockingHeightMapValue(int xRel, int zRel);
int getMaxX();
int getMaxZ();
int getMinX();
int getMinZ();
int getMaxBlockX();
int getMaxBlockZ();
int getMinBlockX();
int getMinBlockZ();
long getLongChunkPos();
void setIsDhLightCorrect(boolean isDhLightCorrect);
boolean isLightCorrect();
default int getBlockLight(int x, int y, int z) {return -1;}
default int getSkyLight(int x, int y, int z) {return -1;}
int getDhSkyLight(int relX, int relY, int relZ);
void setDhSkyLight(int relX, int relY, int relZ, int lightValue);
int getDhBlockLight(int relX, int relY, int relZ);
void setDhBlockLight(int relX, int relY, int relZ, int lightValue);
int getBlockLight(int relX, int relY, int relZ);
int getSkyLight(int relX, int relY, int relZ);
List<DhBlockPos> getBlockLightPosList();
default boolean blockPosInsideChunk(DhBlockPos blockPos) { return this.blockPosInsideChunk(blockPos.x, blockPos.y, blockPos.z); }
default boolean blockPosInsideChunk(int x, int y, int z)
{
return (x >= this.getMinX() && x <= this.getMaxX()
return (x >= this.getMinBlockX() && x <= this.getMaxBlockX()
&& y >= this.getMinBuildHeight() && y < this.getMaxBuildHeight()
&& z >= this.getMinZ() && z <= this.getMaxZ());
&& z >= this.getMinBlockZ() && z <= this.getMaxBlockZ());
}
default boolean blockPosInsideChunk(DhBlockPos2D blockPos)
{
return (blockPos.x >= this.getMinBlockX() && blockPos.x <= this.getMaxBlockX()
&& blockPos.z >= this.getMinBlockZ() && blockPos.z <= this.getMaxBlockZ());
}
boolean doesNearbyChunksExist();
boolean doNearbyChunksExist();
String toString();
/** This is a bad hash algorithm, but can be used for rough debugging. */
@@ -78,11 +101,12 @@ public interface IChunkWrapper extends IBindable
return hash;
}
IBlockStateWrapper getBlockState(int x, int y, int z);
IBiomeWrapper getBiome(int x, int y, int z);
DhChunkPos getChunkPos();
default IBlockStateWrapper getBlockState(DhBlockPos pos) { return this.getBlockState(pos.x, pos.y, pos.z); }
IBlockStateWrapper getBlockState(int relX, int relY, int relZ);
IBiomeWrapper getBiome(int relX, int relY, int relZ);
boolean isStillValid();
}
@@ -23,10 +23,10 @@ import java.io.File;
import java.util.ArrayList;
import java.util.UUID;
import com.seibel.distanthorizons.core.enums.EDhDirection;
import com.seibel.distanthorizons.core.pos.DhBlockPos;
import com.seibel.distanthorizons.core.pos.DhChunkPos;
import com.seibel.distanthorizons.coreapi.ModInfo;
import com.seibel.distanthorizons.core.enums.ELodDirection;
import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IBindable;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
import org.apache.logging.log4j.Level;
@@ -57,7 +57,7 @@ public interface IMinecraftClientWrapper extends IBindable
// method wrappers //
//=================//
float getShade(ELodDirection lodDirection);
float getShade(EDhDirection lodDirection);
boolean hasSinglePlayerServer();
boolean clientConnectedToDedicatedServer();
@@ -275,10 +275,14 @@
"Distance Generator Mode",
"distanthorizons.config.client.advanced.worldGenerator.distantGeneratorMode.@tooltip":
"How complicated the generation should be when generating LODs outside the vanilla render distance.\n\n§6§6Fastest:§r Biome only\n§6Best Quality:§r Features (suggested)",
"distanthorizons.config.client.advanced.worldGenerator.lightingEngine":
"distanthorizons.config.client.advanced.worldGenerator.worldGenLightingEngine":
"Lighting Engine",
"distanthorizons.config.client.advanced.worldGenerator.lightingEngine.@tooltip":
"distanthorizons.config.client.advanced.worldGenerator.worldGenLightingEngine.@tooltip":
"§6Minecraft:§r use Minecraft's lighting engine, gives accurate lighting.\n§6Distant Horizons:§r estimates lighting, shadows won't be as smooth, but is more stable.\n\nIf the LODs appear black, set this to §6Distant Horizons§r.",
"distanthorizons.config.client.advanced.worldGenerator.worldGenerationTimeoutLengthInSeconds":
"Timeout Length In Seconds",
"distanthorizons.config.client.advanced.worldGenerator.worldGenerationTimeoutLengthInSeconds.@tooltip":
"How long should a world generator thread run for before timing out? \nNote: If you are experiencing timeout errors it is better to lower your CPU usage first \nvia the thread config before changing this value.",
"distanthorizons.config.client.advanced.worldGenerator.generationPriority":
"Generation Priority",
"distanthorizons.config.client.advanced.worldGenerator.generationPriority.@tooltip":
+43 -12
View File
@@ -1,10 +1,7 @@
#version 150 core
in vec4 vertexColor;
in vec3 vertexWorldPos;
in float vertexYPos;
in vec4 vPos;
//in vec2 TexCoord;
out vec4 fragColor;
@@ -30,6 +27,20 @@ float mixFogThickness(float near, float far, float height);
// =========================================================
// Puts steps in a float
// EG. setting stepSize to 4 then this would be the result of this function
// In: 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, ..., 1.1, 1.2, 1.3
// Out: 0.0, 0.0, 0.0, 0.25, 0.25, 0.5, 0.5, ..., 1.0, 1.0, 1.25
float quantize(float val, int stepSize) {
return floor(val*stepSize)/stepSize;
}
// The modulus function dosnt exist in GLSL so I made my own
// To speed up the mod function, this only accepts full numbers for y
float mod(float x, int y) {
return x - y * floor(x/y);
}
/**
@@ -39,19 +50,39 @@ float mixFogThickness(float near, float far, float height);
* version: 2023-6-21
*/
void main() {
float horizontalDist = length(vertexWorldPos.xz) * fogScale;
float heightDist = calculateHeightFogDepth(
if (fullFogMode != 0) {
fragColor = vec4(fogColor.r, fogColor.g, fogColor.b, 1.);
} else {
float horizontalDist = length(vertexWorldPos.xz) * fogScale;
float heightDist = calculateHeightFogDepth(
vertexWorldPos.y, vertexYPos) * fogVerticalScale;
float farDist = calculateFarFogDepth(horizontalDist,
float farDist = calculateFarFogDepth(horizontalDist,
length(vertexWorldPos.xyz) * fogScale, nearFogStart);
float nearFogThickness = getNearFogThickness(horizontalDist);
float farFogThickness = getFarFogThickness(farDist);
float heightFogThickness = getHeightFogThickness(heightDist);
float mixedFogThickness = clamp(mixFogThickness(
float nearFogThickness = getNearFogThickness(horizontalDist);
float farFogThickness = getFarFogThickness(farDist);
float heightFogThickness = getHeightFogThickness(heightDist);
float mixedFogThickness = clamp(mixFogThickness(
nearFogThickness, farFogThickness, heightFogThickness), 0.0, 1.0);
fragColor = mix(vertexColor, vec4(fogColor.rgb, 1.0), mixedFogThickness);
fragColor = vec4(fogColor.r, fogColor.g, fogColor.b, mixedFogThickness);
}
// Testing
// if (fragColor.r != 6969.) { // This line is so that the compiler doesnt delete the previos code
//// fragColor = vec4(
//// mod(vertexWorldPos.x, 1),
//// mod(vertexWorldPos.y, 1),
//// mod(vertexWorldPos.z, 1),
//// 1.
//// );
// fragColor = vec4(
// mod(vertexYPos, 1),
// mod(vertexYPos, 1),
// mod(vertexYPos, 1),
// 1.
// );
// }
}
@@ -0,0 +1,19 @@
#version 150 core
//uniform vec3 modelOffset;
uniform float worldYOffset;
in vec2 vPos;
in uvec4 vPosition;
out vec3 vertexWorldPos;
out float vertexYPos;
void main()
{
// vertexWorldPos = vPosition.xyz + modelOffset;
vertexYPos = vPosition.y + worldYOffset;
gl_Position = vec4(vPos, 1.0, 1.0);
}
@@ -81,11 +81,11 @@ void main() {
);
// For testing
if (vertexColor.r != 69420.) {
fragColor = vec4(
mod(fixedVPos.x, 1),
mod(fixedVPos.y, 1),
mod(fixedVPos.z, 1),
1f);
}
// if (vertexColor.r != 69420.) {
// fragColor = vec4(
// mod(fixedVPos.x, 1),
// mod(fixedVPos.y, 1),
// mod(fixedVPos.z, 1),
// 1f);
// }
}
@@ -3,10 +3,6 @@
in vec2 vPos;
out vec2 TexCoord;
out vec4 vertexColor;
out vec3 vertexWorldPos;
out float vertexYPos;
void main()
{
@@ -9,5 +9,5 @@ uniform sampler2D gSSAOMap;
void main()
{
fragColor = vec4(0.0, 0.0, 0.0, texture(gSSAOMap, TexCoord).r);
fragColor = vec4(0.0, 0.0, 0.0, 1-texture(gSSAOMap, TexCoord).r);
}
@@ -0,0 +1,9 @@
#version 150 core
out vec4 fragColor;
// A test shader that makes everything darker
void main()
{
fragColor = vec4(0., 0., 1., 0.5);
}