Improve overlapped quads handling + fix minLevel being used to clamp getMaxVerticalData(), causing invalid sized containers being added to incorrect detail level slot in a region.

This commit is contained in:
TomTheFurry
2022-04-18 15:57:14 +08:00
parent a3022d2c64
commit 29fab65ee9
11 changed files with 90 additions and 47 deletions
@@ -19,6 +19,7 @@
package com.seibel.lod.core.builders.lodBuilding;
import java.util.ConcurrentModificationException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -287,6 +288,10 @@ public class LodBuilder
//ApiShared.LOGGER.info("Generate chunk: {}, {} ({}, {}) at genMode {}",
// chunk.getChunkPosX(), chunk.getChunkPosZ(), chunk.getMinX(), chunk.getMinZ(), config.distanceGenerationMode);
if (targetLevel != region.getMinDetailLevel()) {
//Concurrency issues happened.
throw new ConcurrentModificationException("Min detail level changed while writing data");
}
region.addChunkOfData(targetLevel,
LevelPosUtil.convert(LodUtil.CHUNK_DETAIL_LEVEL, chunkX, targetLevel),
LevelPosUtil.convert(LodUtil.CHUNK_DETAIL_LEVEL, chunkZ, targetLevel),
@@ -31,7 +31,7 @@ import static com.seibel.lod.core.render.LodRenderer.EVENT_LOGGER;
* @author ?
* @version 4-9-2022
*/
public class BufferQuad
public final class BufferQuad
{
final short x;
final short y;
@@ -39,11 +39,12 @@ public class BufferQuad
short widthEastWest;
/** This is both North/South and Up/Down since the merging logic is the same either way */
short widthNorthSouthOrUpDown;
int color;
final int color;
final byte skyLight;
final byte blockLight;
final LodDirection direction;
boolean hasError = false;
BufferQuad(short x, short y, short z, short widthEastWest, short widthNorthSouthOrUpDown,
int color, byte skylight, byte blocklight,
@@ -64,16 +65,13 @@ public class BufferQuad
this.blockLight = blocklight;
this.direction = direction;
}
/** a rough but fast calculation */
double calculateDistance(double relativeX, double relativeY, double relativeZ)
{
return Math.pow(relativeX - x, 2) + Math.pow(relativeY - y, 2) + Math.pow(relativeZ - z, 2);
}
/** compares this quad's position to the given quad */
public int compare(BufferQuad quad, BufferMergeDirectionEnum compareDirection)
{
@@ -131,6 +129,7 @@ public class BufferQuad
*/
public boolean tryMerge(BufferQuad quad, BufferMergeDirectionEnum mergeDirection)
{
if (quad.hasError || this.hasError) return false;
// only merge quads that are in the same direction
if (direction != quad.direction)
return false;
@@ -244,7 +243,8 @@ public class BufferQuad
{
// these quads are overlapping, they can't be merged
EVENT_LOGGER.warn("Overlapping quads detected!");
quad.color = ColorUtil.rgbToInt(255, 0, 0);
quad.hasError = true;
this.hasError = true;
return false;
}
@@ -53,36 +53,54 @@ public class CubicLodTemplate
}
int color;
if (debugging != DebugMode.OFF && debugging != DebugMode.SHOW_WIREFRAME)
{
if (debugging == DebugMode.SHOW_DETAIL || debugging == DebugMode.SHOW_DETAIL_WIREFRAME)
color = LodUtil.DEBUG_DETAIL_LEVEL_COLORS[detailLevel];
else /// if (debugging == DebugMode.SHOW_GENMODE || debugging ==
/// DebugMode.SHOW_GENMODE_WIREFRAME)
color = LodUtil.DEBUG_DETAIL_LEVEL_COLORS[DataPointUtil.getGenerationMode(data)];
}
else
{
float saturationMultiplier = (float)CONFIG.client().graphics().advancedGraphics().getSaturationMultiplier();
float brightnessMultiplier = (float)CONFIG.client().graphics().advancedGraphics().getBrightnessMultiplier();
if (saturationMultiplier == 1.0 && brightnessMultiplier == 1.0) {
color = DataPointUtil.getColor(data);
} else {
float[] ahsv = ColorUtil.argbToAhsv(DataPointUtil.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));
boolean fullBright = false;
switch (debugging) {
case OFF:
case SHOW_WIREFRAME:
{
float saturationMultiplier = (float)CONFIG.client().graphics().advancedGraphics().getSaturationMultiplier();
float brightnessMultiplier = (float)CONFIG.client().graphics().advancedGraphics().getBrightnessMultiplier();
if (saturationMultiplier == 1.0 && brightnessMultiplier == 1.0) {
color = DataPointUtil.getColor(data);
} else {
float[] ahsv = ColorUtil.argbToAhsv(DataPointUtil.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:
case SHOW_DETAIL_WIREFRAME:
{
color = LodUtil.DEBUG_DETAIL_LEVEL_COLORS[detailLevel];
fullBright = true;
break;
}
case SHOW_GENMODE:
case SHOW_GENMODE_WIREFRAME:
{
color = LodUtil.DEBUG_DETAIL_LEVEL_COLORS[DataPointUtil.getGenerationMode(data)];
fullBright = true;
break;
}
case SHOW_OVERLAPPING_QUADS:
case SHOW_NON_OVERLAPPING_QUADS_WIREFRAME:
{
color = ColorUtil.WHITE;
fullBright = true;
break;
}
default:
throw new IllegalArgumentException("Unknown debug mode: " + debugging);
}
LodBox.addBoxQuadsToBuilder(quadBuilder, // buffer
width, dy, width, // setWidth
x, y, z, // setOffset
color, // setColor
DataPointUtil.getLightSky(data), DataPointUtil.getLightBlock(data), // setLights
DataPointUtil.getLightSky(data), // setSkyLights
fullBright ? 15 : DataPointUtil.getLightBlock(data), // setBlockLights
topData, botData, adjData, adjFillBlack); // setAdjData
}
}
@@ -306,8 +306,11 @@ public class LodQuadBuilder
default:
throw new IllegalArgumentException("Invalid Axis enum: " + axis);
}
putVertex(bb, (short) (quad.x + dx), (short) (quad.y + dy), (short) (quad.z + dz), quad.color,
quad.skyLight, quad.blockLight, mx, my, mz);
putVertex(bb, (short) (quad.x + dx), (short) (quad.y + dy), (short) (quad.z + dz),
quad.hasError ? ColorUtil.RED : quad.color,
quad.hasError ? 15 : quad.skyLight,
quad.hasError ? 15 : quad.blockLight,
mx, my, mz);
}
}
@@ -43,7 +43,13 @@ public enum DebugMode
SHOW_GENMODE,
/** LOD colors are based on their gen mode, and draws in wireframe. */
SHOW_GENMODE_WIREFRAME;
SHOW_GENMODE_WIREFRAME,
/** Only draw overlapping LOD quads. */
SHOW_OVERLAPPING_QUADS,
/** Only draw overlapping LOD quads, and draws in wireframe. */
SHOW_OVERLAPPING_QUADS_WIREFRAME;
/** used when cycling through the different modes */
private DebugMode next;
@@ -55,7 +61,9 @@ public enum DebugMode
SHOW_DETAIL.next = SHOW_DETAIL_WIREFRAME;
SHOW_DETAIL_WIREFRAME.next = SHOW_GENMODE;
SHOW_GENMODE.next = SHOW_GENMODE_WIREFRAME;
SHOW_GENMODE_WIREFRAME.next = OFF;
SHOW_GENMODE_WIREFRAME.next = SHOW_OVERLAPPING_QUADS;
SHOW_OVERLAPPING_QUADS.next = SHOW_OVERLAPPING_QUADS_WIREFRAME;
SHOW_OVERLAPPING_QUADS_WIREFRAME.next = OFF;
}
/** returns the next debug mode */
@@ -294,6 +294,7 @@ public class LodDimension
detail = DetailDistanceUtil.getDetailLevelFromDistance(minDistance);
if (region.getMinDetailLevel() < detail) {
if (region.needSaving) return; // FIXME: A crude attempt at lowering chance of race condition!
if (region.isWriting.get()!=0) return;
region.cutTree(detail);
region.needSignalToRegenBuffer = true;
}
@@ -54,7 +54,7 @@ public class LodRegion {
private static final byte POSSIBLE_LOD = LodUtil.DETAIL_OPTIONS;
/** Holds the lowest (least detailed) detail level in this region */
private byte minDetailLevel;
private volatile byte minDetailLevel;
public byte lastMaxDetailLevel = LodUtil.REGION_DETAIL_LEVEL;
/**
@@ -161,9 +161,12 @@ public class LodRegion {
// detailLevel changes.
if (this.dataContainer[detailLevel] == null)
return false;// this.dataContainer[detailLevel] = new VerticalLevelContainer(detailLevel);
if (this.dataContainer[detailLevel].getVerticalSize() != verticalSize)
throw new RuntimeException("Provided data's verticalSize is different from current storage's verticalSize!");
if (this.dataContainer[detailLevel].getVerticalSize() != verticalSize) {
throw new RuntimeException(
String.format("Provided data's verticalSize [%d]" +
" is different from current storage's verticalSize [%d] at detail [%d]",
verticalSize, this.dataContainer[detailLevel].getVerticalSize(), detailLevel));
}
boolean updated = this.dataContainer[detailLevel].addChunkOfData(data, posX, posZ, widthX, widthZ, override);
//ApiShared.LOGGER.info("addChunkOfData(region:{}, level:{}, x:{}, z:{}, wx:{}, wz:{}, override:{}, updated:{})",
// getRegionPos(), detailLevel, posX, posZ, widthX, widthZ, override, updated);
@@ -501,7 +504,7 @@ public class LodRegion {
/**
* Updates all children.
* <p>
@@ -646,10 +649,10 @@ public class LodRegion {
+ "only allows adding LevelContainers with a " + "detail level of [" + (minDetailLevel - 1) + "]");
}
dataContainer[levelContainer.getDetailLevel()] = levelContainer;
if (levelContainer.getDetailLevel() == minDetailLevel - 1)
minDetailLevel = levelContainer.getDetailLevel();
dataContainer[levelContainer.getDetailLevel()] = levelContainer;
needRecheckGenPoint = true;
}
@@ -662,10 +665,9 @@ public class LodRegion {
*/
public void cutTree(byte detailLevel) {
if (detailLevel > minDetailLevel) {
minDetailLevel = detailLevel;
for (byte detailLevelIndex = 0; detailLevelIndex < detailLevel; detailLevelIndex++)
dataContainer[detailLevelIndex] = null;
minDetailLevel = detailLevel;
}
}
@@ -250,7 +250,8 @@ public class LodRenderer
LagSpikeCatcher drawSetPolygon = new LagSpikeCatcher();
if (CONFIG.client().advanced().debugging().getDebugMode() == DebugMode.SHOW_DETAIL_WIREFRAME
|| CONFIG.client().advanced().debugging().getDebugMode() == DebugMode.SHOW_GENMODE_WIREFRAME
|| CONFIG.client().advanced().debugging().getDebugMode() == DebugMode.SHOW_WIREFRAME) {
|| CONFIG.client().advanced().debugging().getDebugMode() == DebugMode.SHOW_WIREFRAME
|| CONFIG.client().advanced().debugging().getDebugMode() == DebugMode.SHOW_OVERLAPPING_QUADS_WIREFRAME) {
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_LINE);
//GL32.glDisable(GL32.GL_CULL_FACE);
}
@@ -38,6 +38,8 @@ public class ColorUtil
public static final int BLACK = rgbToInt(0,0,0);
public static final int WHITE = rgbToInt(255,255,255);
public static final int TRANSPARENT = rgbToInt(0, 0, 0, 0);
public static final int RED = rgbToInt(255,0,0);
private static final IMinecraftClientWrapper MC = SingletonHandler.get(IMinecraftClientWrapper.class);
@@ -104,7 +104,7 @@ public class DetailDistanceUtil
public static int getMaxVerticalData(int detail)
{
return CONFIG.client().graphics().quality().getVerticalQuality().maxVerticalData[LodUtil.clamp(minDetail, detail, LodUtil.REGION_DETAIL_LEVEL)];
return CONFIG.client().graphics().quality().getVerticalQuality().maxVerticalData[detail];
}
}
@@ -842,7 +842,10 @@ public interface ILodConfigWrapperSingleton extends IBindable
+ " " + DebugMode.SHOW_DETAIL + ": Fake chunks color will be based on their detail level. \n"
+ " " + DebugMode.SHOW_DETAIL_WIREFRAME + ": Fake chunks color will be based on their detail level, drawn as a wireframe. \n"
+ " " + DebugMode.SHOW_GENMODE + ": Fake chunks color will be based on their distant generation mode. \n"
+ " " + DebugMode.SHOW_GENMODE_WIREFRAME + ": Fake chunks color will be based on their distant generation mode, drawn as a wireframe. \n";
+ " " + DebugMode.SHOW_GENMODE_WIREFRAME + ": Fake chunks color will be based on their distant generation mode, drawn as a wireframe. \n"
+ " " + DebugMode.SHOW_OVERLAPPING_QUADS + ": Fake chunks will be drawn with total white, but overlapping quads will be drawn with red. \n"
+ " " + DebugMode.SHOW_OVERLAPPING_QUADS_WIREFRAME + ": Fake chunks will be drawn with total white, \n"
+ " but overlapping quads will be drawn with red, drawn as a wireframe. \n";
DebugMode getDebugMode();
void setDebugMode(DebugMode newDebugMode);