From ae857dfeaeb89eaa7eac8f7202d42b82efadbdd3 Mon Sep 17 00:00:00 2001 From: Leonardo Date: Mon, 20 Sep 2021 10:46:14 +0200 Subject: [PATCH] fixed a small bug in the datapoint Simplified the code in the LodBufferBuilder --- .../seibel/lod/builders/LodBufferBuilder.java | 295 +++++++----------- .../com/seibel/lod/util/DataPointUtil.java | 2 +- 2 files changed, 120 insertions(+), 177 deletions(-) diff --git a/src/main/java/com/seibel/lod/builders/LodBufferBuilder.java b/src/main/java/com/seibel/lod/builders/LodBufferBuilder.java index 4dae5a94d..9b7a44bf7 100644 --- a/src/main/java/com/seibel/lod/builders/LodBufferBuilder.java +++ b/src/main/java/com/seibel/lod/builders/LodBufferBuilder.java @@ -71,69 +71,69 @@ public class LodBufferBuilder * This holds the threads used to generate buffers. */ public static ExecutorService bufferBuilderThreads = Executors.newFixedThreadPool(LodConfig.CLIENT.threading.numberOfBufferBuilderThreads.get(), new LodThreadFactory(LodBufferBuilder.class.getSimpleName() + " - builder")); - + /** * The buffers that are used to create LODs using far fog */ public volatile BufferBuilder[][] buildableBuffers; - + /** * Used when building new VBOs */ public volatile VertexBuffer[][] buildableVbos; - + /** * VBOs that are sent over to the LodNodeRenderer */ public volatile VertexBuffer[][] drawableVbos; - + /** * if this is true the LOD buffers are currently being * regenerated. */ public boolean generatingBuffers = false; - + /** * if this is true new LOD buffers have been generated * and are waiting to be swapped with the drawable buffers */ private boolean switchVbos = false; - + /** * Size of the buffer builders in bytes last time we created them */ public int previousBufferSize = 0; - + /** * Width of the dimension in regions last time we created the buffers */ public int previousRegionWidth = 0; - + /** * this is used to prevent multiple threads creating, destroying, or using the buffers at the same time */ private ReentrantLock bufferLock = new ReentrantLock(); - + // private static final int NUMBER_OF_DIRECTION = 4; //in order -x, +x, -z, +z // private static final int[][] ADJ_VECTOR = new int[][]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; - + private volatile Box[][] boxCache; private volatile PosToRenderContainer[][] setsToRender; private volatile RegionPos center; - + /** * This is the ChunkPos the player was at the last time the buffers were built. * IE the center of the buffers last time they were built */ private volatile ChunkPos drawableCenterChunkPos = new ChunkPos(0, 0); private volatile ChunkPos buildableCenterChunkPos = new ChunkPos(0, 0); - + public LodBufferBuilder() { - + } - + /** * Create a thread to asynchronously generate LOD buffers * centered around the given camera X and Z. @@ -144,61 +144,61 @@ public class LodBufferBuilder * swapped with the drawable buffers in the LodRenderer to be drawn. */ public void generateLodBuffersAsync(LodRenderer renderer, LodDimension lodDim, - BlockPos playerBlockPos, boolean fullRegen) + BlockPos playerBlockPos, boolean fullRegen) { - + // only allow one generation process to happen at a time if (generatingBuffers) return; - + if (buildableBuffers == null) // setupBuffers hasn't been called yet return; - + generatingBuffers = true; - + // round the player's block position down to the nearest chunk BlockPos ChunkPos playerChunkPos = new ChunkPos(playerBlockPos); BlockPos playerBlockPosRounded = playerChunkPos.getWorldPosition(); - + Thread thread = new Thread(() -> { bufferLock.lock(); - + try { long treeStart = System.currentTimeMillis(); long treeEnd = System.currentTimeMillis(); - + long startTime = System.currentTimeMillis(); - + ArrayList> nodeToRenderThreads = new ArrayList<>(lodDim.getWidth() * lodDim.getWidth()); - + startBuffers(fullRegen, lodDim); - + // =====================// // RENDERING PART // // =====================// - + RegionPos playerRegionPos = new RegionPos(playerChunkPos); if (center == null) center = playerRegionPos; - + if (setsToRender == null) setsToRender = new PosToRenderContainer[lodDim.getWidth()][lodDim.getWidth()]; - + if (setsToRender.length != lodDim.getWidth()) setsToRender = new PosToRenderContainer[lodDim.getWidth()][lodDim.getWidth()]; - + if (boxCache == null) boxCache = new Box[lodDim.getWidth()][lodDim.getWidth()]; - + if (boxCache.length != lodDim.getWidth()) boxCache = new Box[lodDim.getWidth()][lodDim.getWidth()]; - + // this will be the center of the VBOs once they have been built buildableCenterChunkPos = playerChunkPos; - + for (int xRegion = 0; xRegion < lodDim.getWidth(); xRegion++) { for (int zRegion = 0; zRegion < lodDim.getWidth(); zRegion++) @@ -208,60 +208,60 @@ public class LodBufferBuilder RegionPos regionPos = new RegionPos( xRegion + lodDim.getCenterX() - Math.floorDiv(lodDim.getWidth(), 2), zRegion + lodDim.getCenterZ() - Math.floorDiv(lodDim.getWidth(), 2)); - + // local position in the vbo and bufferBuilder arrays BufferBuilder currentBuffer = buildableBuffers[xRegion][zRegion]; LodRegion region = lodDim.getRegion(regionPos.x, regionPos.z); - + if (region == null) continue; - + // make sure the buffers weren't // changed while we were running this method if (currentBuffer == null || (currentBuffer != null && !currentBuffer.building())) return; - + byte minDetail = region.getMinDetailLevel(); - - + + final int xR = xRegion; final int zR = zRegion; Callable dataToRenderThread = () -> { Map adjData = new HashMap<>(); - + // determine how many LODs we can stack vertically int maxVerticalData = 1; if (LodConfig.CLIENT.worldGenerator.lodQualityMode.get() == LodQualityMode.MULTI_LOD) { maxVerticalData = DetailDistanceUtil.getMaxVerticalData(LodUtil.BLOCK_DETAIL_LEVEL); } - + // create adjData's arrays for (Direction direction : Box.ADJ_DIRECTIONS) { adjData.put(direction, new long[maxVerticalData]); } - + //previous setToRender cache if (setsToRender[xR][zR] == null) { setsToRender[xR][zR] = new PosToRenderContainer(minDetail, regionPos.x, regionPos.z); } - + if (boxCache[xR][zR] == null) { boxCache[xR][zR] = new Box(); } PosToRenderContainer posToRender = setsToRender[xR][zR]; posToRender.clear(minDetail, regionPos.x, regionPos.z); - + lodDim.getDataToRender( posToRender, regionPos, playerBlockPosRounded.getX(), playerBlockPosRounded.getZ()); - + byte detailLevel; int posX; int posZ; @@ -269,30 +269,30 @@ public class LodBufferBuilder int zAdj; int chunkXdist; int chunkZdist; - + // keep a local version so we don't have to worry about indexOutOfBounds Exceptions // if it changes in the LodRenderer while we are working here boolean[][] vanillaRenderedChunks = renderer.vanillaRenderedChunks; short gameChunkRenderDistance = (short) (vanillaRenderedChunks.length / 2 - 1); - + for (int index = 0; index < posToRender.getNumberOfPos(); index++) { detailLevel = posToRender.getNthDetailLevel(index); posX = posToRender.getNthPosX(index); posZ = posToRender.getNthPosZ(index); - + // skip any chunks that Minecraft is going to render chunkXdist = LevelPosUtil.getChunkPos(detailLevel, posX) - playerChunkPos.x; chunkZdist = LevelPosUtil.getChunkPos(detailLevel, posZ) - playerChunkPos.z; - + if (gameChunkRenderDistance >= Math.abs(chunkXdist) - && gameChunkRenderDistance >= Math.abs(chunkZdist) - && detailLevel <= LodUtil.CHUNK_DETAIL_LEVEL - && vanillaRenderedChunks[chunkXdist + gameChunkRenderDistance + 1][chunkZdist + gameChunkRenderDistance + 1]) + && gameChunkRenderDistance >= Math.abs(chunkZdist) + && detailLevel <= LodUtil.CHUNK_DETAIL_LEVEL + && vanillaRenderedChunks[chunkXdist + gameChunkRenderDistance + 1][chunkZdist + gameChunkRenderDistance + 1]) { continue; } - + // skip any chunks that Minecraft is going to render try { @@ -302,94 +302,41 @@ public class LodBufferBuilder zAdj = posZ + direction.getNormal().getZ(); chunkXdist = LevelPosUtil.getChunkPos(detailLevel, xAdj) - playerChunkPos.x; chunkZdist = LevelPosUtil.getChunkPos(detailLevel, zAdj) - playerChunkPos.z; - if (gameChunkRenderDistance >= Math.abs(chunkXdist) && gameChunkRenderDistance >= Math.abs(chunkZdist)) + + if (posToRender.contains(detailLevel, xAdj, zAdj) + && (gameChunkRenderDistance < Math.abs(chunkXdist) + || gameChunkRenderDistance < Math.abs(chunkZdist) + || !vanillaRenderedChunks[chunkXdist + gameChunkRenderDistance + 1][chunkZdist + gameChunkRenderDistance + 1])) { - if (!vanillaRenderedChunks[chunkXdist + gameChunkRenderDistance + 1][chunkZdist + gameChunkRenderDistance + 1] - && posToRender.contains(detailLevel, xAdj, zAdj)) - { - if (LodConfig.CLIENT.worldGenerator.lodQualityMode.get() == LodQualityMode.HEIGHTMAP) - { - adjData.get(direction)[0] = lodDim.getSingleData(detailLevel, xAdj, zAdj); - } - else - { - for (int verticalIndex = 0; verticalIndex < lodDim.getMaxVerticalData(detailLevel, xAdj, zAdj); verticalIndex++) - adjData.get(direction)[verticalIndex] = lodDim.getData(detailLevel, xAdj, zAdj, verticalIndex); - } - } - else - { - if (LodConfig.CLIENT.worldGenerator.lodQualityMode.get() == LodQualityMode.HEIGHTMAP) - { - adjData.get(direction)[0] = DataPointUtil.createVoidDataPoint(0); - } - else - { - adjData.put(direction, null); - } - } - } - else + if (!adjData.containsKey(direction) || adjData.get(direction)==null) + adjData.put(direction, new long[maxVerticalData]); + for (int verticalIndex = 0; verticalIndex < lodDim.getMaxVerticalData(detailLevel, xAdj, zAdj); verticalIndex++) + adjData.get(direction)[verticalIndex] = lodDim.getData(detailLevel, xAdj, zAdj, verticalIndex); + } else { - if (posToRender.contains(detailLevel, xAdj, zAdj)) - { - if (LodConfig.CLIENT.worldGenerator.lodQualityMode.get() == LodQualityMode.HEIGHTMAP) - { - adjData.get(direction)[0] = lodDim.getSingleData(detailLevel, xAdj, zAdj); - } - else - { - for (int verticalIndex = 0; verticalIndex < lodDim.getMaxVerticalData(detailLevel, xAdj, zAdj); verticalIndex++) - adjData.get(direction)[verticalIndex] = lodDim.getData(detailLevel, xAdj, zAdj, verticalIndex); - } - } - else - { - - if (LodConfig.CLIENT.worldGenerator.lodQualityMode.get() == LodQualityMode.HEIGHTMAP) - { - adjData.get(direction)[0] = DataPointUtil.createVoidDataPoint(0); - } - else - { - adjData.put(direction, null); - } - } + adjData.put(direction, null); } } - if (region.getLodQualityMode() == LodQualityMode.HEIGHTMAP) + + long data; + for (int verticalIndex = 0; verticalIndex < lodDim.getMaxVerticalData(detailLevel, posX, posZ); verticalIndex++) { - //dataPoint = lodDim.getData(detailLevel, posX, posZ)[0]; - long dataPoint = lodDim.getSingleData(detailLevel, posX, posZ); - if (!DataPointUtil.isItVoid(dataPoint) && DataPointUtil.doesItExist(dataPoint)) - { - LodConfig.CLIENT.graphics.lodTemplate.get().template.addLodToBuffer(currentBuffer, playerBlockPosRounded, dataPoint, adjData, - detailLevel, posX, posZ, boxCache[xR][zR], renderer.previousDebugMode, renderer.lightMap); - } - + data = lodDim.getData(detailLevel, posX, posZ, verticalIndex); + if (DataPointUtil.isItVoid(data) || !DataPointUtil.doesItExist(data)) + break; + LodConfig.CLIENT.graphics.lodTemplate.get().template.addLodToBuffer(currentBuffer, playerBlockPosRounded, data, adjData, + detailLevel, posX, posZ, boxCache[xR][zR], renderer.previousDebugMode, renderer.lightMap); } - else if (region.getLodQualityMode() == LodQualityMode.MULTI_LOD) - { - long data; - for (int verticalIndex = 0; verticalIndex < lodDim.getMaxVerticalData(detailLevel, posX, posZ); verticalIndex++) - { - data = lodDim.getData(detailLevel, posX, posZ, verticalIndex); - if (DataPointUtil.isItVoid(data) || !DataPointUtil.doesItExist(data)) - break; - LodConfig.CLIENT.graphics.lodTemplate.get().template.addLodToBuffer(currentBuffer, playerBlockPosRounded, data, adjData, - detailLevel, posX, posZ, boxCache[xR][zR], renderer.previousDebugMode, renderer.lightMap); - } - } - - } - catch (ArrayIndexOutOfBoundsException e) + + + } catch (ArrayIndexOutOfBoundsException e) { e.printStackTrace(); return false; } - + } // for pos to in list to render - // the thread executed successfully + // the thread executed successfully return true; }; nodeToRenderThreads.add(dataToRenderThread); @@ -410,7 +357,7 @@ public class LodBufferBuilder } } long renderEnd = System.currentTimeMillis(); - + long endTime = System.currentTimeMillis(); @SuppressWarnings("unused") long buildTime = endTime - startTime; @@ -418,45 +365,43 @@ public class LodBufferBuilder long treeTime = treeEnd - treeStart; @SuppressWarnings("unused") long renderingTime = renderEnd - renderStart; - + // ClientProxy.LOGGER.info("Buffer Build time: " + buildTime + " ms" + '\n' + // "Tree cutting time: " + treeTime + " ms" + '\n' + // "Rendering time: " + renderingTime + " ms"); - + // mark that the buildable buffers as ready to swap switchVbos = true; - } - catch (Exception e) + } catch (Exception e) { ClientProxy.LOGGER.warn("\"LodNodeBufferBuilder.generateLodBuffersAsync\" ran into trouble: "); e.printStackTrace(); - } - finally + } finally { // regardless of if we successfully created the buffers // we are done generating. generatingBuffers = false; - + // clean up any potentially open resources if (buildableBuffers != null) closeBuffers(fullRegen, lodDim); - + // upload the new buffers uploadBuffers(fullRegen, lodDim); bufferLock.unlock(); } - + }); - + mainGenThread.execute(thread); - + return; } - + //===============================// // BufferBuilder related methods // //===============================// - + /** * Called from the LodRenderer to create the * BufferBuilders.

@@ -466,29 +411,29 @@ public class LodBufferBuilder public void setupBuffers(int numbRegionsWide, int bufferMaxCapacity) { bufferLock.lock(); - + previousRegionWidth = numbRegionsWide; previousBufferSize = bufferMaxCapacity; - + buildableBuffers = new BufferBuilder[numbRegionsWide][numbRegionsWide]; - + buildableVbos = new VertexBuffer[numbRegionsWide][numbRegionsWide]; drawableVbos = new VertexBuffer[numbRegionsWide][numbRegionsWide]; - + for (int x = 0; x < numbRegionsWide; x++) { for (int z = 0; z < numbRegionsWide; z++) { buildableBuffers[x][z] = new BufferBuilder(bufferMaxCapacity); - + buildableVbos[x][z] = new VertexBuffer(LodRenderer.LOD_VERTEX_FORMAT); drawableVbos[x][z] = new VertexBuffer(LodRenderer.LOD_VERTEX_FORMAT); } } - + bufferLock.unlock(); } - + /** * sets the buffers and Vbos to null, forcing them to be recreated.

*

@@ -497,14 +442,14 @@ public class LodBufferBuilder public void destroyBuffers() { bufferLock.lock(); - + buildableBuffers = null; buildableVbos = null; drawableVbos = null; - + bufferLock.unlock(); } - + /** * Calls begin on each of the buildable BufferBuilders. */ @@ -521,7 +466,7 @@ public class LodBufferBuilder } } } - + /** * Calls end on each of the buildable BufferBuilders. */ @@ -532,20 +477,20 @@ public class LodBufferBuilder if (buildableBuffers[x][z] != null && buildableBuffers[x][z].building() && (fullRegen || lodDim.getRegenByArrayIndex(x, z))) buildableBuffers[x][z].end(); } - + /** * Upload all buildableBuffers to the GPU. */ private void uploadBuffers(boolean fullRegen, LodDimension lodDim) { GlProxy glProxy = GlProxy.getInstance(); - + try { // make sure we are uploading to a different OpenGL context, // to prevent interference (IE stuttering) with the Minecraft context. glProxy.setGlContext(GlProxyContext.LOD_BUILDER); - + for (int x = 0; x < buildableVbos.length; x++) { for (int z = 0; z < buildableVbos.length; z++) @@ -558,29 +503,27 @@ public class LodBufferBuilder } } } - + // make sure all the buffers have been uploaded. // this probably is necessary, but it makes me feel good :) GL11.glFlush(); - } - catch (IllegalStateException e) + } catch (IllegalStateException e) { ClientProxy.LOGGER.error(LodBufferBuilder.class.getSimpleName() + " - UploadBuffers failed: " + e.getMessage()); e.printStackTrace(); - } - finally + } finally { // make sure no buffer is bound if (glProxy.getGlContext() == GlProxyContext.LOD_BUILDER) { GL15C.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0); } - + // make sure the context is disabled glProxy.setGlContext(GlProxyContext.NONE); } } - + /** * Uploads the uploadBuffer into the VBO in GPU memory. */ @@ -591,22 +534,22 @@ public class LodBufferBuilder { // this is how many points will be rendered vbo.vertexCount = (uploadBuffer.remaining() / vbo.format.getVertexSize()); - + GL15C.glBindBuffer(GL15.GL_ARRAY_BUFFER, vbo.id); - + // subData only works if the memory is allocated beforehand. GL15C.glBufferData(GL15.GL_ARRAY_BUFFER, uploadBuffer.remaining(), GL15C.GL_DYNAMIC_DRAW); - + // interestingly bufferSubData renders faster than glMapBuffer // even though OpenGLInsights-AsynchronousBufferTransfers says glMapBuffer // is faster for transferring data. They must put the data in different memory // or something. GL15C.glBufferSubData(GL15.GL_ARRAY_BUFFER, 0, uploadBuffer); - + GL15C.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0); } } - + /** * Get the newly created VBOs */ @@ -619,17 +562,17 @@ public class LodBufferBuilder VertexBuffer[][] tmpVbo = drawableVbos; drawableVbos = buildableVbos; buildableVbos = tmpVbo; - + drawableCenterChunkPos = buildableCenterChunkPos; - + // the vbos have been swapped switchVbos = false; bufferLock.unlock(); } - + return new VertexBuffersAndOffset(drawableVbos, drawableCenterChunkPos); } - + /** * A simple container to pass multiple objects back in the getVertexBuffers method. */ @@ -637,14 +580,14 @@ public class LodBufferBuilder { public VertexBuffer[][] vbos; public ChunkPos drawableCenterChunkPos; - + public VertexBuffersAndOffset(VertexBuffer[][] newVbos, ChunkPos newDrawableCenterChunkPos) { vbos = newVbos; drawableCenterChunkPos = newDrawableCenterChunkPos; } } - + /** * If this is true the buildable near and far * buffers have been generated and are ready to be @@ -654,5 +597,5 @@ public class LodBufferBuilder { return switchVbos; } - + } diff --git a/src/main/java/com/seibel/lod/util/DataPointUtil.java b/src/main/java/com/seibel/lod/util/DataPointUtil.java index f5fbf7842..a983e81c3 100644 --- a/src/main/java/com/seibel/lod/util/DataPointUtil.java +++ b/src/main/java/com/seibel/lod/util/DataPointUtil.java @@ -282,7 +282,7 @@ public class DataPointUtil public static long[] mergeMultiData(long[] dataToMerge, int inputVerticalData,int maxVerticalData) { int size = dataToMerge.length / inputVerticalData; - short[] projection = ThreadMapUtil.getProjectionShort((WORLD_HEIGHT + 1) / 16); + short[] projection = ThreadMapUtil.getProjectionShort((WORLD_HEIGHT) / 16 + 1); short[][] heightAndDepth = ThreadMapUtil.getHeightAndDepth(inputVerticalData); long[] singleDataToMerge = ThreadMapUtil.getSingleAddDataToMerge(size); int genMode = DistanceGenerationMode.SERVER.complexity;