From 9c2add4e3b5e56ce4f5b30dfab972fc3d6fa5824 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Tue, 10 Aug 2021 20:34:06 -0500 Subject: [PATCH] Clean up distance based detail and change debugMode --- .../lod/builders/LodNodeBufferBuilder.java | 112 ++++++++---------- .../CubicLodNodeTemplate.java | 60 +++++----- .../com/seibel/lod/handlers/LodConfig.java | 12 +- .../java/com/seibel/lod/util/LodUtil.java | 12 +- 4 files changed, 96 insertions(+), 100 deletions(-) diff --git a/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java b/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java index 80fa33013..8f7928525 100644 --- a/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java +++ b/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java @@ -50,32 +50,32 @@ import net.minecraftforge.common.WorldWorkerManager; public class LodNodeBufferBuilder { private Minecraft mc; - + /** This holds the thread used to generate new LODs off the main thread. */ private ExecutorService genThread = Executors.newSingleThreadExecutor(); - + private LodNodeBuilder LodQuadTreeNodeBuilder; - + /** The buffers that are used to create LODs using near fog */ public volatile BufferBuilder buildableNearBuffer; /** The buffers that are used to create LODs using far fog */ public volatile BufferBuilder buildableFarBuffer; - + /** if this is true the LOD buffers are currently being * regenerated. */ public volatile boolean generatingBuffers = false; - + /** if this is true new LOD buffers have been generated * and are waiting to be swapped with the drawable buffers*/ private volatile boolean switchBuffers = false; - + /** This keeps track of how many chunk generation requests are on going. * This is to prevent chunks from being generated for a long time in an area * the player is no longer in. */ public volatile AtomicInteger numberOfChunksWaitingToGenerate = new AtomicInteger(0); - + /** how many chunks to generate outside of the player's * view distance at one time. (or more specifically how * many requests to make at one time). @@ -83,8 +83,8 @@ public class LodNodeBufferBuilder * to make sure the CPU is always busy and we can generate LODs as quickly as * possible. */ public int maxChunkGenRequests = LodConfig.CLIENT.numberOfWorldGenerationThreads.get() * 8; - - + + public LodNodeBufferBuilder(LodNodeBuilder newLodBuilder) { mc = Minecraft.getInstance(); @@ -95,7 +95,7 @@ public class LodNodeBufferBuilder private BiomeContainer biomeContainer = null; private LodQuadTreeDimension previousDimension = null; - + /** * Create a thread to asynchronously generate LOD buffers * centered around the given camera X and Z. @@ -106,7 +106,7 @@ public class LodNodeBufferBuilder * swapped with the drawable buffers in the LodRenderer to be drawn. */ public void generateLodBuffersAsync(LodNodeRenderer renderer, LodQuadTreeDimension lodDim, - double playerX, double playerZ, int numbChunksWide) + double playerX, double playerZ, int numbChunksWide) { // only allow one generation process to happen at a time if (generatingBuffers) @@ -137,7 +137,7 @@ public class LodNodeBufferBuilder int startZ = (-LodQuadTreeNode.CHUNK_WIDTH * (numbChunksWide / 2)) + playerZChunkOffset; - Thread thread = new Thread(()-> + Thread thread = new Thread(() -> { // index of the chunk currently being added to the // generation list @@ -154,7 +154,7 @@ public class LodNodeBufferBuilder // generate our new buildable buffers buildableNearBuffer.begin(GL11.GL_QUADS, LodNodeRenderer.LOD_VERTEX_FORMAT); buildableFarBuffer.begin(GL11.GL_QUADS, LodNodeRenderer.LOD_VERTEX_FORMAT); - + // x axis for (int i = 0; i < numbChunksWide; i++) { @@ -162,29 +162,28 @@ public class LodNodeBufferBuilder for (int j = 0; j < numbChunksWide; j++) { int chunkX = i + Math.floorDiv(startX, LodQuadTreeNode.CHUNK_WIDTH); int chunkZ = j + Math.floorDiv(startZ, LodQuadTreeNode.CHUNK_WIDTH); - + // skip any chunks that Minecraft is going to render if (isCoordInCenterArea(i, j, (numbChunksWide / 2)) && renderer.vanillaRenderedChunks.contains(new ChunkPos(chunkX, chunkZ))) { continue; } - - + + // set where this square will be drawn in the world double xOffset = (LodQuadTreeNode.CHUNK_WIDTH * i) + // offset by the number of LOD blocks startX; - // 8 works for LODs the size of chunks double yOffset = 0; double zOffset = (LodQuadTreeNode.CHUNK_WIDTH * j) + startZ; - + LodQuadTreeNode lod = lodDim.getLodFromCoordinates(new ChunkPos(chunkX, chunkZ), LodQuadTreeNode.CHUNK_LEVEL); - + if (lod == null || lod.complexity == DistanceGenerationMode.NONE) { // generate a new chunk if no chunk currently exists // and we aren't waiting on any other chunks to generate if (lod == null && numberOfChunksWaitingToGenerate.get() < maxChunkGenRequests) { ChunkPos pos = new ChunkPos(chunkX, chunkZ); - + // alternate determining logic that // can be used for debugging // if (chunksToGen == null) @@ -198,12 +197,12 @@ public class LodNodeBufferBuilder // chunksToGen[chunkGenIndex] = pos; // chunkGenIndex++; // } - - + + // determine if this position is closer to the player // than the previous int newDistance = playerChunkPos.getChessboardDistance(pos); - + // issue #40 // TODO optimize this code, // using the purely optimized code above we can achieve close to @@ -214,7 +213,7 @@ public class LodNodeBufferBuilder // this chunk is closer, clear any previous // positions and update the new minimum distance minChunkDist = newDistance; - + // move all the old chunks into the reserve ChunkPos[] newReserve = new ChunkPos[maxChunkGenRequests]; int oldToGenIndex = 0; @@ -223,7 +222,7 @@ public class LodNodeBufferBuilder // we don't check if the boundaries are good since // the tmp array will always be the same length // as chunksToGen and chunksToGenReserve - + if (chunksToGen[oldToGenIndex] != null) { // add all the closest chunks... newReserve[tmpIndex] = chunksToGen[oldToGenIndex]; @@ -240,8 +239,8 @@ public class LodNodeBufferBuilder } } chunksToGenReserve = newReserve; - - + + chunkGenIndex = 0; chunksToGen = new ChunkPos[maxChunkGenRequests]; chunksToGen[chunkGenIndex] = pos; @@ -256,58 +255,51 @@ public class LodNodeBufferBuilder chunkGenIndex++; } } - + } // lod null and can generate more chunks - + // don't render this null/empty chunk continue; - + } // lod null or empty - - + + + // should we draw near or far fog? BufferBuilder currentBuffer = null; if (isCoordinateInNearFogArea(i, j, numbChunksWide / 2)) currentBuffer = buildableNearBuffer; else currentBuffer = buildableFarBuffer; - - // get the desired LodTemplate and - // add this LOD to the buffer + + + // what detail level should this LOD be drawn at? int distance = (int) Math.sqrt(Math.pow((mc.player.getX() - lod.startBlockPos.getX()),2) + Math.pow((mc.player.getZ() - lod.startBlockPos.getZ()),2)); LodDetail detail; - if(distance < 200){ + if(distance < (numbChunksWide / 2) * 16 * 0.2) + { detail = LodDetail.HALF; - }else if(distance < 400){ + } + else if(distance < (numbChunksWide / 2) * 16 * 0.5) + { detail = LodDetail.QUAD; - }else if(distance < 600){ + } + else if(distance < (numbChunksWide / 2) * 16 * 0.75) + { detail = LodDetail.DOUBLE; - }else{ + } + else + { detail = LodDetail.SINGLE; } + + // get the desired LodTemplate and + // add this LOD to the buffer LodConfig.CLIENT.lodTemplate.get(). - template.addLodToBuffer(currentBuffer, lodDim, lod, + template.addLodToBuffer(currentBuffer, lodDim, lod, xOffset , yOffset, zOffset, renderer.debugging, detail); - /* - LodDetail detail = LodConfig.CLIENT.lodDetail.get(); - for(int x = 0; x < detail.dataPointLengthCount; x++){ - for(int z = 0; z < detail.dataPointLengthCount; z++) { - int posX = LodUtil.convertLevelPos(lod.startBlockPos.getX() + (x*detail.dataPointWidth), 0, detail.detailLevel); - int posZ = LodUtil.convertLevelPos(lod.startBlockPos.getZ() + (z*detail.dataPointWidth), 0, detail.detailLevel); - LodQuadTreeNode newLod = lodDim.getLodFromCoordinates(posX, posZ, detail.detailLevel); - System.out.print("printing "); - System.out.println(newLod); - if(newLod != null) { - LodConfig.CLIENT.lodTemplate.get(). - template.addLodToBuffer(currentBuffer, lodDim, newLod, - xOffset + (x*detail.dataPointWidth), yOffset, zOffset + (z*detail.dataPointWidth), renderer.debugging); - } - } - } - */ } } - //ClientProxy.LOGGER.info(numberOfChunksWaitingToGenerate.get()); // issue #19 // TODO add a way for a server side mod to generate chunks requested here @@ -323,7 +315,7 @@ public class LodNodeBufferBuilder chunksToGen[i] = chunksToGenReserve[j]; } } - + // start chunk generation for(ChunkPos chunkPos : chunksToGen) { @@ -340,7 +332,7 @@ public class LodNodeBufferBuilder WorldWorkerManager.addWorker(genWorker); } } - + // finish the buffer building buildableNearBuffer.end(); buildableFarBuffer.end(); diff --git a/src/main/java/com/seibel/lod/builders/lodNodeTemplates/CubicLodNodeTemplate.java b/src/main/java/com/seibel/lod/builders/lodNodeTemplates/CubicLodNodeTemplate.java index 67d18f0da..9d9804ec9 100644 --- a/src/main/java/com/seibel/lod/builders/lodNodeTemplates/CubicLodNodeTemplate.java +++ b/src/main/java/com/seibel/lod/builders/lodNodeTemplates/CubicLodNodeTemplate.java @@ -21,11 +21,10 @@ import java.awt.Color; import com.seibel.lod.enums.LodDetail; import com.seibel.lod.enums.ShadingMode; import com.seibel.lod.handlers.LodConfig; -import com.seibel.lod.objects.LodQuadTree; import com.seibel.lod.objects.LodQuadTreeDimension; import com.seibel.lod.objects.LodQuadTreeNode; - import com.seibel.lod.util.LodUtil; + import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.util.math.AxisAlignedBB; @@ -34,7 +33,7 @@ import net.minecraft.util.math.AxisAlignedBB; * Builds LODs as rectangular prisms. * * @author James Seibel - * @version 8-8-2021 + * @version 8-10-2021 */ public class CubicLodNodeTemplate extends AbstractLodNodeTemplate { @@ -47,35 +46,24 @@ public class CubicLodNodeTemplate extends AbstractLodNodeTemplate public void addLodToBuffer(BufferBuilder buffer, LodQuadTreeDimension lodDim, LodQuadTreeNode lod, double xOffset, double yOffset, double zOffset, - boolean debugging, LodDetail detail) { + boolean debugging, LodDetail detail) + { AxisAlignedBB bbox; - - // Add this LOD to the BufferBuilder - int halfWidth = LodQuadTreeNode.CHUNK_WIDTH / 2; - //LodDetail detail = LodConfig.CLIENT.lodDetail.get(); -/* - bbox = generateBoundingBox( - lod.getLodDataPoint().height, - lod.getLodDataPoint().depth, - lod.width, - xOffset - halfWidth, - yOffset, - zOffset - halfWidth); - - if (bbox != null) { - addBoundingBoxToBuffer(buffer, bbox, lod.getLodDataPoint().color); - } - - */ - LodQuadTree chunkTree = lodDim.getLevelFromPos(lod.posX, lod.posZ, lod.detailLevel); - for(int i = 0; i < detail.dataPointLengthCount * detail.dataPointLengthCount; i++) { + + // add each LOD for the detail level + for(int i = 0; i < detail.dataPointLengthCount * detail.dataPointLengthCount; i++) + { + // how much to offset this LOD by int startX = detail.startX[i]; int startZ = detail.startZ[i]; - int posX = LodUtil.convertLevelPos((int) xOffset+startX,0, detail.detailLevel); - int posZ = LodUtil.convertLevelPos((int) zOffset+startZ,0, detail.detailLevel);; - //LodQuadTreeNode newLod = chunkTree.getNodeAtPos(posX ,posZ ,detail.detailLevel); - LodQuadTreeNode newLod = lodDim.getLodFromCoordinates(posX ,posZ ,detail.detailLevel); - if(newLod != null) { + + // get the QuadTree location of this LOD + int posX = LodUtil.convertLevelPos((int) xOffset + startX, 0, detail.detailLevel); + int posZ = LodUtil.convertLevelPos((int) zOffset + startZ, 0, detail.detailLevel); + + LodQuadTreeNode newLod = lodDim.getLodFromCoordinates(posX, posZ, detail.detailLevel); + if(newLod != null) + { bbox = generateBoundingBox( newLod.getLodDataPoint().height, newLod.getLodDataPoint().depth, @@ -83,9 +71,17 @@ public class CubicLodNodeTemplate extends AbstractLodNodeTemplate xOffset + startX, yOffset, zOffset + startZ); - - if (bbox != null) { - addBoundingBoxToBuffer(buffer, bbox, newLod.getLodDataPoint().color); + + + Color color = newLod.getLodDataPoint().color; + if (LodConfig.CLIENT.debugMode.get()) + { + color = LodUtil.DEBUG_DETAIL_LEVEL_COLORS[detail.detailLevel]; + } + + if (bbox != null) + { + addBoundingBoxToBuffer(buffer, bbox, color); } } } diff --git a/src/main/java/com/seibel/lod/handlers/LodConfig.java b/src/main/java/com/seibel/lod/handlers/LodConfig.java index 87e3f984d..c30e2f3f1 100644 --- a/src/main/java/com/seibel/lod/handlers/LodConfig.java +++ b/src/main/java/com/seibel/lod/handlers/LodConfig.java @@ -39,9 +39,10 @@ import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.config.ModConfig; /** + * This handles any configuration the user has access to. * * @author James Seibel - * @version 7-25-2021 + * @version 8-10-2021 */ @Mod.EventBusSubscriber public class LodConfig @@ -106,11 +107,10 @@ public class LodConfig debugMode = builder .comment("\n\n" - + " If false the LODs will draw with their normal world colors. \n" - + " If true they will draw as a black and white checkerboard. \n" - + " This can be used for debugging or imagining you are playing a \n" - + " giant game of chess ;) \n") - .define("drawCheckerBoard", false); + + " If false the LODs will draw with their normal colors. \n" + + " If true LODs colors will be based on their detail \n" + + " level. \n") + .define("debugMode", false); lodTemplate = builder .comment("\n\n" diff --git a/src/main/java/com/seibel/lod/util/LodUtil.java b/src/main/java/com/seibel/lod/util/LodUtil.java index a6b3309f9..726f977ac 100644 --- a/src/main/java/com/seibel/lod/util/LodUtil.java +++ b/src/main/java/com/seibel/lod/util/LodUtil.java @@ -21,8 +21,8 @@ import java.awt.Color; import java.io.File; import com.seibel.lod.objects.LodQuadTreeNode; - import com.seibel.lod.objects.RegionPos; + import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ServerData; import net.minecraft.server.integrated.IntegratedServer; @@ -37,7 +37,7 @@ import net.minecraft.world.server.ServerWorld; * This class holds methods and constants that may be used in multiple places. * * @author James Seibel - * @version 8-8-2021 + * @version 8-10-2021 */ public class LodUtil { @@ -50,6 +50,14 @@ public class LodUtil public static final Color COLOR_DEBUG_WHITE = new Color(255, 255, 255, DEBUG_ALPHA); public static final Color COLOR_INVISIBLE = new Color(0,0,0,0); + /** + * In order of nearest to farthest:
+ * Orange, Yellow, Green, Blue, Magenta, Red

+ * + * Black is included in index 0, but it shouldn't be used normally. + */ + public static final Color DEBUG_DETAIL_LEVEL_COLORS[] = new Color[] { Color.BLACK, Color.ORANGE, Color.YELLOW, Color.GREEN, Color.BLUE, Color.MAGENTA, Color.RED}; + /** * Gets the first valid ServerWorld.