From c20ec4ef59a3968bce8f7db2d70b78a543f8476e Mon Sep 17 00:00:00 2001 From: Leonardo Date: Sat, 21 Aug 2021 22:01:52 +0200 Subject: [PATCH] added commented use of biomeUtils and terrainUtils --- .../seibel/lod/builders/LodBufferBuilder.java | 871 +++++++++--------- .../com/seibel/lod/builders/LodBuilder.java | 106 ++- .../worldGeneration/LodNodeGenWorker.java | 3 + .../java/com/seibel/lod/objects/LevelPos.java | 1 + 4 files changed, 546 insertions(+), 435 deletions(-) diff --git a/src/main/java/com/seibel/lod/builders/LodBufferBuilder.java b/src/main/java/com/seibel/lod/builders/LodBufferBuilder.java index a8b0bc989..f38a4ed21 100644 --- a/src/main/java/com/seibel/lod/builders/LodBufferBuilder.java +++ b/src/main/java/com/seibel/lod/builders/LodBufferBuilder.java @@ -51,114 +51,131 @@ import net.minecraftforge.common.WorldWorkerManager; /** * This object is used to create NearFarBuffer objects. - * + * * @author James Seibel * @version 8-21-2021 */ public class LodBufferBuilder { - private Minecraft mc; - - /** This holds the thread used to generate new LODs off the main thread. */ - private ExecutorService mainGenThread = Executors.newSingleThreadExecutor(new LodThreadFactory(this.getClass().getSimpleName() + " - main")); - - private LodBuilder LodQuadTreeNodeBuilder; - - /** 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; + private Minecraft mc; - /** if this is true the LOD buffers are currently being - * regenerated. */ - public Set positionWaitingToBeGenerated = new HashSet<>(); + /** + * This holds the thread used to generate new LODs off the main thread. + */ + private ExecutorService mainGenThread = Executors.newSingleThreadExecutor(new LodThreadFactory(this.getClass().getSimpleName() + " - main")); - /** if this is true new LOD buffers have been generated - * and are waiting to be swapped with the drawable buffers*/ - private boolean switchVbos = 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 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). - * I multiply by 8 to make sure there is always a buffer of chunk requests, - * 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 LodBufferBuilder(LodBuilder newLodBuilder) - { - mc = Minecraft.getInstance(); - LodQuadTreeNodeBuilder = newLodBuilder; - } - - - private LodDimension previousDimension = null; - - - /** - * Create a thread to asynchronously generate LOD buffers - * centered around the given camera X and Z. - *
- * This method will write to the drawable near and far buffers. - *
- * After the buildable buffers have been generated they must be - * swapped with the drawable buffers in the LodRenderer to be drawn. - */ - public void generateLodBuffersAsync(LodRenderer renderer, LodDimension lodDim, - BlockPos playerBlockPos, int numbChunksWide) - { - // only allow one generation process to happen at a time - if (generatingBuffers) - return; - - if (buildableBuffers == null) - throw new IllegalStateException("\"generateLodBuffersAsync\" was called before the \"setupBuffers\" method was called."); - - if (previousDimension != lodDim) - { - previousDimension = lodDim; - } - - - generatingBuffers = true; - - - // round the player's block position down to the nearest chunk BlockPos - ChunkPos playerChunkPos = new ChunkPos(playerBlockPos); - BlockPos playerBlockPosRounded = playerChunkPos.getWorldPosition(); - - // this is where we will start drawing squares - // (exactly half the total width) - BlockPos startBlockPos = new BlockPos(-(numbChunksWide * 16 / 2) + playerBlockPosRounded.getX(), 0, -(numbChunksWide * 16 / 2) + playerBlockPosRounded.getZ()); - ChunkPos startChunkPos = new ChunkPos(startBlockPos); - - - Thread thread = new Thread(() -> - { - try - { - long startTime = System.currentTimeMillis(); - - ArrayList chunksToGen = new ArrayList<>(maxChunkGenRequests); - // if we don't have a full number of chunks to generate in chunksToGen - // we can top it off from the reserve - ArrayList chunksToGenReserve = new ArrayList<>(maxChunkGenRequests); + private LodBuilder LodQuadTreeNodeBuilder; + + /** + * 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 the LOD buffers are currently being + * regenerated. + */ + public Set positionWaitingToBeGenerated = new HashSet<>(); + + /** + * if this is true new LOD buffers have been generated + * and are waiting to be swapped with the drawable buffers + */ + private boolean switchVbos = 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 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). + * I multiply by 8 to make sure there is always a buffer of chunk requests, + * 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 LodBufferBuilder(LodBuilder newLodBuilder) + { + mc = Minecraft.getInstance(); + LodQuadTreeNodeBuilder = newLodBuilder; + } + + + private LodDimension previousDimension = null; + + + /** + * Create a thread to asynchronously generate LOD buffers + * centered around the given camera X and Z. + *
+ * This method will write to the drawable near and far buffers. + *
+ * After the buildable buffers have been generated they must be + * swapped with the drawable buffers in the LodRenderer to be drawn. + */ + public void generateLodBuffersAsync(LodRenderer renderer, LodDimension lodDim, + BlockPos playerBlockPos, int numbChunksWide) + { + // only allow one generation process to happen at a time + if (generatingBuffers) + return; + + if (buildableBuffers == null) + throw new IllegalStateException("\"generateLodBuffersAsync\" was called before the \"setupBuffers\" method was called."); + + if (previousDimension != lodDim) + { + previousDimension = lodDim; + } + + + generatingBuffers = true; + + + // round the player's block position down to the nearest chunk BlockPos + ChunkPos playerChunkPos = new ChunkPos(playerBlockPos); + BlockPos playerBlockPosRounded = playerChunkPos.getWorldPosition(); + + // this is where we will start drawing squares + // (exactly half the total width) + BlockPos startBlockPos = new BlockPos(-(numbChunksWide * 16 / 2) + playerBlockPosRounded.getX(), 0, -(numbChunksWide * 16 / 2) + playerBlockPosRounded.getZ()); + ChunkPos startChunkPos = new ChunkPos(startBlockPos); + + + Thread thread = new Thread(() -> + { + try + { + long startTime = System.currentTimeMillis(); + + ArrayList chunksToGen = new ArrayList<>(maxChunkGenRequests); + // if we don't have a full number of chunks to generate in chunksToGen + // we can top it off from the reserve + ArrayList chunksToGenReserve = new ArrayList<>(maxChunkGenRequests); /* DistanceGenerationMode[] distancesGenerators = {DistanceGenerationMode.FEATURES, @@ -174,75 +191,77 @@ public class LodBufferBuilder */ - DistanceGenerationMode[] distancesGenerators = { - DistanceGenerationMode.SURFACE, - DistanceGenerationMode.SURFACE, - DistanceGenerationMode.SURFACE, - DistanceGenerationMode.SURFACE, - DistanceGenerationMode.SURFACE, - DistanceGenerationMode.SURFACE, - DistanceGenerationMode.SURFACE, - DistanceGenerationMode.SURFACE, - DistanceGenerationMode.SURFACE, - DistanceGenerationMode.SURFACE}; - int[] distancesLinear = {0, 200, 400, 600, 800, 1000, 1500, 2000, 3000, 4000, 8000}; - int[] distancesExponential = {0, 100, 200, 400, 800, 1600, 3200, 3200, 3200, 3200, 8000}; - - startBuffers(); - - // used when determining which chunks are closer when queuing distance - // generation - int minChunkDist = Integer.MAX_VALUE; + DistanceGenerationMode[] distancesGenerators = { + DistanceGenerationMode.SURFACE, + DistanceGenerationMode.SURFACE, + DistanceGenerationMode.SURFACE, + DistanceGenerationMode.SURFACE, + DistanceGenerationMode.SURFACE, + DistanceGenerationMode.SURFACE, + DistanceGenerationMode.SURFACE, + DistanceGenerationMode.SURFACE, + DistanceGenerationMode.SURFACE, + DistanceGenerationMode.SURFACE}; + int[] distancesLinear = {0, 200, 400, 600, 800, 1000, 1500, 2000, 3000, 4000, 8000}; + int[] distancesExponential = {0, 100, 200, 400, 800, 1600, 3200, 3200, 3200, 3200, 8000}; - int width; - List posListToRender = new ArrayList<>(); - LodDataPoint lodData; - for (int xRegion = 0; xRegion < lodDim.regions.length; xRegion++) - { - for (int zRegion = 0; zRegion < lodDim.regions.length; zRegion++) - { - RegionPos regionPos = new RegionPos(xRegion + lodDim.getCenterX() - lodDim.getWidth()/2, zRegion + lodDim.getCenterZ() - lodDim.getWidth()/2); - - // local position in the vbo and bufferBuilder arrays - BufferBuilder currentBuffer = buildableBuffers[xRegion][zRegion]; - - // make sure the buffers weren't - // changed while we were running this method - if (currentBuffer == null || (currentBuffer != null && !currentBuffer.building())) - return; + startBuffers(); - /**TODO make this automatic and config dependent*/ - for (byte detail = LodUtil.BLOCK_DETAIL_LEVEL; detail <= LodUtil.REGION_DETAIL_LEVEL; detail++) - { - posListToRender.addAll(lodDim.getDataToRender(regionPos, playerBlockPosRounded.getX(), playerBlockPosRounded.getZ(), distancesLinear[detail], distancesLinear[detail + 1], detail)); - } + // used when determining which chunks are closer when queuing distance + // generation + int minChunkDist = Integer.MAX_VALUE; - for (LevelPos pos : posListToRender) - { - LevelPos chunkPos = pos.convert((byte) 3); - int chunkX = chunkPos.posX + startChunkPos.x; - int chunkZ = chunkPos.posZ + startChunkPos.z; - - // skip any chunks that Minecraft is going to render - if (!(isCoordInCenterArea(pos.convert((byte) 3).posX, pos.convert((byte) 3).posZ, (numbChunksWide / 2)) - && renderer.vanillaRenderedChunks.contains(new ChunkPos(chunkX, chunkZ))) && lodDim.doesDataExist(pos)) - { - width = (int) Math.pow(2, pos.detailLevel); - lodData = lodDim.getData(pos); - LodConfig.CLIENT.lodTemplate.get().template.addLodToBuffer(currentBuffer, lodDim, lodData, - pos.posX * width, 0, pos.posZ * width, renderer.debugging, pos.detailLevel); - } - - } - - posListToRender.clear(); - } - } + int width; + List posListToRender = new ArrayList<>(); + LodDataPoint lodData; + for (int xRegion = 0; xRegion < lodDim.regions.length; xRegion++) + { + for (int zRegion = 0; zRegion < lodDim.regions.length; zRegion++) + { + RegionPos regionPos = new RegionPos(xRegion + lodDim.getCenterX() - lodDim.getWidth() / 2, zRegion + lodDim.getCenterZ() - lodDim.getWidth() / 2); - /**TODO make this automatic and config dependent*/ - List posListToGenerate = new ArrayList<>(); + // local position in the vbo and bufferBuilder arrays + BufferBuilder currentBuffer = buildableBuffers[xRegion][zRegion]; - /**TODO this order can be inverted*/ + // make sure the buffers weren't + // changed while we were running this method + if (currentBuffer == null || (currentBuffer != null && !currentBuffer.building())) + return; + + /**TODO make this automatic and config dependent*/ + for (byte detail = LodUtil.BLOCK_DETAIL_LEVEL; detail <= LodUtil.REGION_DETAIL_LEVEL; detail++) + { + posListToRender.addAll(lodDim.getDataToRender(regionPos, playerBlockPosRounded.getX(), playerBlockPosRounded.getZ(), distancesLinear[detail], distancesLinear[detail + 1], detail)); + } + for (LevelPos pos : posListToRender) + { + LevelPos chunkPos = pos.convert((byte) 2); + int chunkX = chunkPos.posX + startChunkPos.x; + int chunkZ = chunkPos.posZ + startChunkPos.z; + // skip any chunks that Minecraft is going to render + if (isCoordInCenterArea(chunkPos.posX, chunkPos.posZ, (numbChunksWide / 2)) || renderer.vanillaRenderedChunks.contains(new ChunkPos(chunkX, chunkZ))) + { + continue; + } + + if (lodDim.doesDataExist(pos)) + { + width = (int) Math.pow(2, pos.detailLevel); + lodData = lodDim.getData(pos); + LodConfig.CLIENT.lodTemplate.get().template.addLodToBuffer(currentBuffer, lodDim, lodData, + pos.posX * width, 0, pos.posZ * width, renderer.debugging, pos.detailLevel); + } + + } + + posListToRender.clear(); + } + } + + /**TODO make this automatic and config dependent*/ + List posListToGenerate = new ArrayList<>(); + + /**TODO this order can be inverted*/ /* for (byte detail = LodUtil.BLOCK_DETAIL_LEVEL; detail <= LodUtil.REGION_DETAIL_LEVEL; detail++) { @@ -262,275 +281,259 @@ public class LodBufferBuilder } } */ - for (byte detailGen = LodUtil.BLOCK_DETAIL_LEVEL; detailGen <= LodUtil.REGION_DETAIL_LEVEL; detailGen++) - { - if (!posListToGenerate.isEmpty()) break; - posListToGenerate.addAll(lodDim.getDataToGenerate( - playerBlockPosRounded.getX(), - playerBlockPosRounded.getZ(), - (int) (distancesLinear[detailGen]*1.5), - (int) (distancesLinear[detailGen+1]*1.5), - (byte) distancesGenerators[detailGen].complexity, - (byte) 0, - 16)); - } + for (byte detailGen = LodUtil.BLOCK_DETAIL_LEVEL; detailGen <= LodUtil.REGION_DETAIL_LEVEL; detailGen++) + { + if (!posListToGenerate.isEmpty()) break; + posListToGenerate.addAll(lodDim.getDataToGenerate( + playerBlockPosRounded.getX(), + playerBlockPosRounded.getZ(), + (int) (distancesLinear[detailGen] * 1.5), + (int) (distancesLinear[detailGen + 1] * 1.5), + (byte) distancesGenerators[detailGen].complexity, + (byte) 0, + maxChunkGenRequests)); + } + + + for (LevelPos levelPos : posListToGenerate) + { + LevelPos chunkLevelPos = levelPos.convert((byte) 3); + int chunkX = Math.floorDiv(chunkLevelPos.posX, 2); + int chunkZ = Math.floorDiv(chunkLevelPos.posZ, 2); + + if (numberOfChunksWaitingToGenerate.get() < maxChunkGenRequests) + { + ChunkPos pos = new ChunkPos(chunkX, chunkZ); + + if (positionWaitingToBeGenerated.contains(pos)) + { + ClientProxy.LOGGER.debug(pos + " asked to be generated again."); + continue; + } + + + // determine if this position is closer to the player + // than the previous + int newDistance = playerChunkPos.getChessboardDistance(pos); + + if (newDistance < minChunkDist) + { + // this chunk is closer, clear any previous + // positions and update the new minimum distance + minChunkDist = newDistance; + + // move all the old chunks into the reserve + ArrayList oldReserve = new ArrayList<>(chunksToGenReserve); + chunksToGenReserve.clear(); + chunksToGenReserve.addAll(chunksToGen); + // top off reserve with whatever was in oldReerve + for (int i = 0; i < oldReserve.size(); i++) + { + if (chunksToGenReserve.size() < maxChunkGenRequests) + chunksToGenReserve.add(oldReserve.get(i)); + else + break; + } + + chunksToGen.clear(); + chunksToGen.add(pos); + } else if (newDistance == minChunkDist) + { + // this chunk position as close as the minimum distance + if (chunksToGen.size() < maxChunkGenRequests) + { + // we are still under the number of chunks to generate + // add this position to the list + chunksToGen.add(pos); + } + } else + { + // this chunk is farther away than the minimum distance, + // add it to the reserve to make sure we always have a full reserve + chunksToGenReserve.add(pos); + } + + } // lod null and can generate more chunks + } // positions to generate + + + // issue #19 + // TODO add a way for a server side mod to generate chunks requested here + if (mc.hasSingleplayerServer()) + { + ServerWorld serverWorld = LodUtil.getServerWorldFromDimension(lodDim.dimension); + + // make sure we have as many chunks to generate as we are allowed + if (chunksToGen.size() < maxChunkGenRequests) + { + Iterator reserveIterator = chunksToGenReserve.iterator(); + while (chunksToGen.size() < maxChunkGenRequests && reserveIterator.hasNext()) + { + chunksToGen.add(reserveIterator.next()); + } + } + + // start chunk generation + for (ChunkPos chunkPos : chunksToGen) + { + // don't add null chunkPos (which shouldn't happen anyway) + // or add more to the generation queue + if (chunkPos == null || numberOfChunksWaitingToGenerate.get() >= maxChunkGenRequests) + continue; + + positionWaitingToBeGenerated.add(chunkPos); + numberOfChunksWaitingToGenerate.addAndGet(1); + LodNodeGenWorker genWorker = new LodNodeGenWorker(chunkPos, DistanceGenerationMode.SURFACE, LodDetail.FULL, renderer, LodQuadTreeNodeBuilder, this, lodDim, serverWorld); + WorldWorkerManager.addWorker(genWorker); + } + } + + // finish the buffer building + closeBuffers(); + + // upload the new buffers + uploadBuffers(); + + + long endTime = System.currentTimeMillis(); + long buildTime = endTime - startTime; + //ClientProxy.LOGGER.info("Buffer Build time: " + buildTime + " ms"); + + // mark that the buildable buffers as ready to swap + switchVbos = true; + } catch (Exception e) + { + ClientProxy.LOGGER.warn("\"LodNodeBufferBuilder.generateLodBuffersAsync\" ran into trouble: "); + e.printStackTrace(); + } 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(); + } + + }); + + mainGenThread.execute(thread); + + return; + } + + + //====================// + // generation helpers // + //====================// + + /** + * Returns if the given coordinate is in the loaded area of the world. + * + * @param centerCoordinate the center of the loaded world + */ + private boolean isCoordInCenterArea(int i, int j, int centerCoordinate) + { + return (i >= centerCoordinate - mc.options.renderDistance + && i <= centerCoordinate + mc.options.renderDistance) + && + (j >= centerCoordinate - mc.options.renderDistance + && j <= centerCoordinate + mc.options.renderDistance); + } + + + //===============================// + // BufferBuilder related methods // + //===============================// + + + /** + * Called from the LodRenderer to create the + * BufferBuilders. + */ + public void setupBuffers(int numbRegionsWide, int 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); + } + } + } + + /** + * Calls begin on each of the buildable BufferBuilders. + */ + public void startBuffers() + { + for (int x = 0; x < buildableBuffers.length; x++) + for (int z = 0; z < buildableBuffers.length; z++) + buildableBuffers[x][z].begin(GL11.GL_QUADS, LodRenderer.LOD_VERTEX_FORMAT); + } + + /** + * Calls end on each of the buildable BufferBuilders. + */ + public void closeBuffers() + { + for (int x = 0; x < buildableBuffers.length; x++) + for (int z = 0; z < buildableBuffers.length; z++) + if (buildableBuffers[x][z] != null && buildableBuffers[x][z].building()) + buildableBuffers[x][z].end(); + } + + /** + * Called from the LodRenderer to create the + * BufferBuilders at the right size. + * + * @param bufferMaxCapacity + */ + public void uploadBuffers() + { + for (int x = 0; x < buildableVbos.length; x++) + { + for (int z = 0; z < buildableVbos.length; z++) + { + buildableVbos[x][z].upload(buildableBuffers[x][z]); + } + } + } + + + /** + * Get the newly created VBOs + */ + public VertexBuffer[][] getVertexBuffers() + { + VertexBuffer[][] tmp = drawableVbos; + drawableVbos = buildableVbos; + buildableVbos = tmp; + + // the vbos have been swapped + switchVbos = false; + + return drawableVbos; + } + + /** + * If this is true the buildable near and far + * buffers have been generated and are ready to be + * sent to the LodRenderer. + */ + public boolean newBuffersAvaliable() + { + return switchVbos; + } - - for (LevelPos levelPos : posListToGenerate) - { - LevelPos chunkLevelPos = levelPos.convert((byte) 3); - int chunkX = chunkLevelPos.posX / 2; - int chunkZ = chunkLevelPos.posZ / 2; - - if (numberOfChunksWaitingToGenerate.get() < maxChunkGenRequests) - { - ChunkPos pos = new ChunkPos(chunkX, chunkZ); - - if (positionWaitingToBeGenerated.contains(pos)) - { - ClientProxy.LOGGER.debug(pos + " asked to be generated again."); - continue; - } - - - // determine if this position is closer to the player - // than the previous - int newDistance = playerChunkPos.getChessboardDistance(pos); - - if (newDistance < minChunkDist) - { - // this chunk is closer, clear any previous - // positions and update the new minimum distance - minChunkDist = newDistance; - - // move all the old chunks into the reserve - ArrayList oldReserve = new ArrayList<>(chunksToGenReserve); - chunksToGenReserve.clear(); - chunksToGenReserve.addAll(chunksToGen); - // top off reserve with whatever was in oldReerve - for (int i = 0; i < oldReserve.size(); i++) - { - if (chunksToGenReserve.size() < maxChunkGenRequests) - chunksToGenReserve.add(oldReserve.get(i)); - else - break; - } - - chunksToGen.clear(); - chunksToGen.add(pos); - } - else if (newDistance == minChunkDist) - { - // this chunk position as close as the minimum distance - if (chunksToGen.size() < maxChunkGenRequests) - { - // we are still under the number of chunks to generate - // add this position to the list - chunksToGen.add(pos); - } - } - else - { - // this chunk is farther away than the minimum distance, - // add it to the reserve to make sure we always have a full reserve - chunksToGenReserve.add(pos); - } - - } // lod null and can generate more chunks - } // positions to generate - - - // issue #19 - // TODO add a way for a server side mod to generate chunks requested here - if (mc.hasSingleplayerServer()) - { - ServerWorld serverWorld = LodUtil.getServerWorldFromDimension(lodDim.dimension); - - // make sure we have as many chunks to generate as we are allowed - if (chunksToGen.size() < maxChunkGenRequests) - { - Iterator reserveIterator = chunksToGenReserve.iterator(); - while (chunksToGen.size() < maxChunkGenRequests && reserveIterator.hasNext()) - { - chunksToGen.add(reserveIterator.next()); - } - } - - // start chunk generation - for (ChunkPos chunkPos : chunksToGen) - { - // don't add null chunkPos (which shouldn't happen anyway) - // or add more to the generation queue - if (chunkPos == null || numberOfChunksWaitingToGenerate.get() >= maxChunkGenRequests) - continue; - - positionWaitingToBeGenerated.add(chunkPos); - numberOfChunksWaitingToGenerate.addAndGet(1); - LodNodeGenWorker genWorker = new LodNodeGenWorker(chunkPos, DistanceGenerationMode.SURFACE, LodDetail.FULL, renderer, LodQuadTreeNodeBuilder, this, lodDim, serverWorld); - WorldWorkerManager.addWorker(genWorker); - } - } - // finish the buffer building - closeBuffers(); - - // upload the new buffers - uploadBuffers(); - - - long endTime = System.currentTimeMillis(); - long buildTime = endTime - startTime; - //ClientProxy.LOGGER.info("Buffer Build time: " + buildTime + " ms"); - - // mark that the buildable buffers as ready to swap - switchVbos = true; - } - catch (Exception e) - { - ClientProxy.LOGGER.warn("\"LodNodeBufferBuilder.generateLodBuffersAsync\" ran into trouble: "); - e.printStackTrace(); - } - 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(); - } - - }); - - mainGenThread.execute(thread); - - return; - } - - - - - - - - - - - //====================// - // generation helpers // - //====================// - - /** - * Returns if the given coordinate is in the loaded area of the world. - * @param centerCoordinate the center of the loaded world - */ - private boolean isCoordInCenterArea(int i, int j, int centerCoordinate) - { - return (i >= centerCoordinate - mc.options.renderDistance - && i <= centerCoordinate + mc.options.renderDistance) - && - (j >= centerCoordinate - mc.options.renderDistance - && j <= centerCoordinate + mc.options.renderDistance); - } - - - - - - //===============================// - // BufferBuilder related methods // - //===============================// - - - /** - * Called from the LodRenderer to create the - * BufferBuilders. - */ - public void setupBuffers(int numbRegionsWide, int 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); - } - } - } - - /** - * Calls begin on each of the buildable BufferBuilders. - */ - public void startBuffers() - { - for (int x = 0; x < buildableBuffers.length; x++) - for (int z = 0; z < buildableBuffers.length; z++) - buildableBuffers[x][z].begin(GL11.GL_QUADS, LodRenderer.LOD_VERTEX_FORMAT); - } - - /** - * Calls end on each of the buildable BufferBuilders. - */ - public void closeBuffers() - { - for (int x = 0; x < buildableBuffers.length; x++) - for (int z = 0; z < buildableBuffers.length; z++) - if (buildableBuffers[x][z] != null && buildableBuffers[x][z].building()) - buildableBuffers[x][z].end(); - } - - /** - * Called from the LodRenderer to create the - * BufferBuilders at the right size. - * - * @param bufferMaxCapacity - */ - public void uploadBuffers() - { - for (int x = 0; x < buildableVbos.length; x++) - { - for (int z = 0; z < buildableVbos.length; z++) - { - buildableVbos[x][z].upload(buildableBuffers[x][z]); - } - } - } - - - /** - * Get the newly created VBOs - */ - public VertexBuffer[][] getVertexBuffers() - { - VertexBuffer[][] tmp = drawableVbos; - drawableVbos = buildableVbos; - buildableVbos = tmp; - - // the vbos have been swapped - switchVbos = false; - - return drawableVbos; - } - - /** - * If this is true the buildable near and far - * buffers have been generated and are ready to be - * sent to the LodRenderer. - */ - public boolean newBuffersAvaliable() - { - return switchVbos; - } - - - - } \ No newline at end of file diff --git a/src/main/java/com/seibel/lod/builders/LodBuilder.java b/src/main/java/com/seibel/lod/builders/LodBuilder.java index 9ab5732ab..72a61c558 100644 --- a/src/main/java/com/seibel/lod/builders/LodBuilder.java +++ b/src/main/java/com/seibel/lod/builders/LodBuilder.java @@ -29,9 +29,13 @@ import com.seibel.lod.objects.LevelPos; import com.seibel.lod.objects.LodDataPoint; import com.seibel.lod.objects.LodDimension; import com.seibel.lod.objects.LodWorld; +//import com.seibel.lod.util.BiomeColorsUtils; import com.seibel.lod.util.LodThreadFactory; import com.seibel.lod.util.LodUtil; +//import kaptainwutax.biomeutils.source.OverworldBiomeSource; +//import kaptainwutax.mcutils.version.MCVersion; +//import kaptainwutax.terrainutils.TerrainGenerator; import net.minecraft.block.AbstractPlantBlock; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; @@ -40,6 +44,7 @@ import net.minecraft.block.GrassBlock; import net.minecraft.block.IGrowable; import net.minecraft.block.LeavesBlock; import net.minecraft.block.material.MaterialColor; +//import net.minecraft.util.math.ChunkPos; import net.minecraft.world.DimensionType; import net.minecraft.world.IWorld; import net.minecraft.world.biome.Biome; @@ -187,6 +192,53 @@ public class LodBuilder } } + /** + * Creates a LodChunk for a chunk in the given world. + * + * @throws IllegalArgumentException thrown if either the chunk or world is null. + */ + /**TODO if we want to test biome utils and terrain utils + public void generateLodNodeFromChunk(LodDimension lodDim, ChunkPos chunkPos , LodDetail detail, long seed) + throws IllegalArgumentException + { + + if (chunkPos == null) + throw new IllegalArgumentException("generateLodFromChunk given a null chunk pos"); + + int startX; + int startZ; + int endX; + int endZ; + Color color; + short height; + short depth; + LevelPos levelPos; + LodDataPoint data; + + OverworldBiomeSource biomeSource = new OverworldBiomeSource(MCVersion.v1_16_5, seed); + TerrainGenerator terrainGenerator= TerrainGenerator.of(biomeSource); + + for (int i = 0; i < detail.dataPointLengthCount * detail.dataPointLengthCount; i++) + { + startX = detail.startX[i]; + startZ = detail.startZ[i]; + endX = detail.endX[i]; + endZ = detail.endZ[i]; + + color = generateLodColorForArea(biomeSource, chunkPos, startX, startZ, endX, endZ); + height = determineHeightPoint(terrainGenerator, chunkPos, startX, startZ, endX, endZ); + levelPos = new LevelPos((byte) 0, + chunkPos.x * 16 + startX, + chunkPos.z * 16 + startZ); + data = new LodDataPoint(height, 0, color); + lodDim.addData(levelPos.convert((byte) detail.detailLevel), + data, + DistanceGenerationMode.SURFACE, + true, + false); + } + }*/ + // =====================// // constructor helpers // // =====================// @@ -312,6 +364,26 @@ public class LodBuilder return highest; } + /** + * Find the highest point from the Top + */ + /**TODO if we want to test biome utils and terrain utils + private short determineHeightPoint(TerrainGenerator terrainGenerator, ChunkPos chunkPos, int startX, int startZ, int endX, int endZ) + { + short newHeight = 0; + int num = 0; + for (int x = startX; x < endX; x++) + { + for (int z = startZ; z < endZ; z++) + { + num++; + newHeight += (short) terrainGenerator.getFirstHeightInColumn(chunkPos.x*16 + x,chunkPos.z*16 + z, TerrainGenerator.WORLD_SURFACE_WG);; + } + } + + return (short) (newHeight/num); + }*/ + /** * Generate the color for the given chunk using biome water color, foliage * color, and grass color. @@ -411,6 +483,39 @@ public class LodBuilder return new Color(red, green, blue); } +/**TODO if we want to test biome utils and terrain utils + private Color generateLodColorForArea(OverworldBiomeSource biomeSource, ChunkPos chunkPos, int startX, int startZ, int endX, + int endZ) + { + + int numbOfBlocks = 0; + int red = 0; + int green = 0; + int blue = 0; + + for (int x = startX; x < endX; x++) + { + for (int z = startZ; z < endZ; z++) + { + Color color = BiomeColorsUtils.getColorFromBiomeManual(biomeSource.getBiome(chunkPos.x*16 + x,0,chunkPos.z*16 + z)); + red += color.getBlue(); + green += color.getGreen(); + blue += color.getBlue(); + } + } + + if (numbOfBlocks == 0) + numbOfBlocks = 1; + + red /= numbOfBlocks; + green /= numbOfBlocks; + blue /= numbOfBlocks; + + return new Color(red, green, blue); + } + + */ + /** * Returns a color int for a given block. */ @@ -542,5 +647,4 @@ public class LodBuilder return false; } - } diff --git a/src/main/java/com/seibel/lod/builders/worldGeneration/LodNodeGenWorker.java b/src/main/java/com/seibel/lod/builders/worldGeneration/LodNodeGenWorker.java index 1443d6315..02fdc8e50 100644 --- a/src/main/java/com/seibel/lod/builders/worldGeneration/LodNodeGenWorker.java +++ b/src/main/java/com/seibel/lod/builders/worldGeneration/LodNodeGenWorker.java @@ -400,6 +400,9 @@ public class LodNodeGenWorker implements IWorker snowFeature.place(lodServerWorld, chunkGen, serverWorld.random, chunk.getPos().getWorldPosition(), null); lodBuilder.generateLodNodeFromChunk(lodDim, chunk, new LodBuilderConfig(DistanceGenerationMode.SURFACE), detailLevel); + + /**TODO if we want to use Biome utils and terrain utils for overworld + * lodBuilder.generateLodNodeFromChunk(lodDim, pos ,detailLevel, serverWorld.getSeed());*/ } diff --git a/src/main/java/com/seibel/lod/objects/LevelPos.java b/src/main/java/com/seibel/lod/objects/LevelPos.java index ad83db703..7e28d7db8 100644 --- a/src/main/java/com/seibel/lod/objects/LevelPos.java +++ b/src/main/java/com/seibel/lod/objects/LevelPos.java @@ -57,6 +57,7 @@ public class LevelPos implements Cloneable return new LevelPos(detailLevel, posX, posZ); } +/**TODO fix the region disappearing for a second*/ public int maxDistance(int playerPosX, int playerPosZ, int regionPosX, int regionPosZ) {