diff --git a/gradle.properties b/gradle.properties index 20488469..09805e88 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,7 +8,7 @@ yarn_mappings=1.20.4+build.1 loader_version=0.15.0 # Mod Properties -mod_version = 0.0.7-alpha +mod_version = 0.0.8-alpha maven_group = me.cortex archives_base_name = voxy diff --git a/src/main/java/me/cortex/voxy/client/core/DistanceTracker.java b/src/main/java/me/cortex/voxy/client/core/DistanceTracker.java index 7b4007b5..828e6cf1 100644 --- a/src/main/java/me/cortex/voxy/client/core/DistanceTracker.java +++ b/src/main/java/me/cortex/voxy/client/core/DistanceTracker.java @@ -8,6 +8,8 @@ import me.cortex.voxy.client.core.rendering.RenderTracker; import me.cortex.voxy.client.core.util.RingUtil; import net.minecraft.client.MinecraftClient; +import java.util.stream.IntStream; + //Can use ring logic // i.e. when a player moves the rings of each lod change (how it was doing in the original attempt) // also have it do directional quad culling and rebuild the chunk if needed (this shouldent happen very often) (the reason is to significantly reduce draw calls) @@ -26,8 +28,8 @@ public class DistanceTracker { this.cacheLoadRings = new TransitionRing2D[lodRingScales.length]; this.cacheUnloadRings = new TransitionRing2D[lodRingScales.length]; this.tracker = tracker; - this.minYSection = MinecraftClient.getInstance().world.getBottomSectionCoord()/2; - this.maxYSection = MinecraftClient.getInstance().world.getTopSectionCoord()/2; + this.minYSection = MinecraftClient.getInstance().world.getBottomSectionCoord()/2;//-128; + this.maxYSection = MinecraftClient.getInstance().world.getTopSectionCoord()/2;//128; //The rings 0+ start at 64 vanilla rd, no matter what the game is set at, that is if the game is set to 32 rd @@ -40,18 +42,20 @@ public class DistanceTracker { //TODO:FIXME i think the radius is wrong and (lodRingScales[i]) needs to be (lodRingScales[i]<<1) since the transition ring (the thing above) // acts on LoD level + 1 - this.cacheLoadRings[i] = new TransitionRing2D(5+i, (lodRingScales[i]<<1) + cacheLoadDistance, (x, z) -> { - //When entering a cache ring, trigger a mesh op and inject into cache - for (int y = this.minYSection>>capRing; y <= this.maxYSection>>capRing; y++) { - this.tracker.addCache(capRing, x, y, z); - } - }, (x, z) -> {}); - this.cacheUnloadRings[i] = new TransitionRing2D(5+i, (lodRingScales[i]<<1) + cacheUnloadDistance, (x, z) -> {}, (x, z) -> { - //When exiting the cache unload ring, tell the cache to dump whatever mesh it has cached and not add any mesh from that position - for (int y = this.minYSection>>capRing; y <= this.maxYSection>>capRing; y++) { - this.tracker.removeCache(capRing, x, y, z); - } - }); + + //TODO: check this is actually working lmao and make it generate parent level lods on the exit instead of entry so it looks correct when flying backwards + //this.cacheLoadRings[i] = new TransitionRing2D(5+i, (lodRingScales[i]<<1) + cacheLoadDistance, (x, z) -> { + // //When entering a cache ring, trigger a mesh op and inject into cache + // for (int y = this.minYSection>>capRing; y <= this.maxYSection>>capRing; y++) { + // this.tracker.addCache(capRing, x, y, z); + // } + //}, (x, z) -> {}); + //this.cacheUnloadRings[i] = new TransitionRing2D(5+i, (lodRingScales[i]<<1) + cacheUnloadDistance, (x, z) -> {}, (x, z) -> { + // //When exiting the cache unload ring, tell the cache to dump whatever mesh it has cached and not add any mesh from that position + // for (int y = this.minYSection>>capRing; y <= this.maxYSection>>capRing; y++) { + // this.tracker.removeCache(capRing, x, y, z); + // } + //}); } } @@ -75,36 +79,64 @@ public class DistanceTracker { // the lod sections public void setCenter(int x, int y, int z) { for (var ring : this.cacheLoadRings) { - ring.update(x, z); + if (ring!=null) + ring.update(x, z); } for (var ring : this.loDRings) { ring.update(x, z); } for (var ring : this.cacheUnloadRings) { - ring.update(x, z); + if (ring!=null) + ring.update(x, z); } } public void init(int x, int z) { - //Radius of chunks to enqueue - int SIZE = 128; - //Insert highest LOD level - for (int ox = -SIZE; ox <= SIZE; ox++) { - for (int oz = -SIZE; oz <= SIZE; oz++) { - this.inc(4, (x>>(5+this.loDRings.length)) + ox, (z>>(5+this.loDRings.length)) + oz); - } - } - - for (var ring : this.cacheLoadRings) { - ring.fill(x, z); + if (ring != null) + ring.setCenter(x, z); } - for (int i = this.loDRings.length-1; 0 <= i; i--) { - if (this.loDRings[i] != null) { - this.loDRings[i].fill(x, z); - } + for (var ring : this.cacheUnloadRings) { + if (ring != null) + ring.setCenter(x, z); } + + for (var ring : this.loDRings) { + if (ring != null) + ring.setCenter(x, z); + } + + var thread = new Thread(()-> { + //Radius of chunks to enqueue + int SIZE = 128; + //Insert highest LOD level + for (int ox = -SIZE; ox <= SIZE; ox++) { + for (int oz = -SIZE; oz <= SIZE; oz++) { + this.inc(4, (x >> (5 + this.loDRings.length)) + ox, (z >> (5 + this.loDRings.length)) + oz); + } + } + + + for (var ring : this.cacheLoadRings) { + if (ring != null) + ring.fill(x, z); + } + + for (var ring : this.cacheUnloadRings) { + if (ring != null) + ring.fill(x, z); + } + + for (int i = this.loDRings.length - 1; 0 <= i; i--) { + if (this.loDRings[i] != null) { + this.loDRings[i].fill(x, z); + } + } + }); + thread.setName("LoD Ring Initializer"); + thread.start(); + //TODO: FIXME: need to destory on shutdown } @@ -248,6 +280,7 @@ public class DistanceTracker { int r2 = this.radius*this.radius; for (int a = -this.radius; a <= this.radius; a++) { + //IntStream.range(-this.radius, this.radius+1).parallel().forEach(a->{ int b = (int) Math.floor(Math.sqrt(r2-(a*a))); for (int c = -b; c <= b; c++) { this.enter.callback(a + cx, c + cz); @@ -261,8 +294,12 @@ public class DistanceTracker { outsideCallback.callback(a + cx, c + cz); } } - } + }//); + } + public void setCenter(int x, int z) { + int cx = x>>this.shiftSize; + int cz = z>>this.shiftSize; this.currentX = cx; this.currentZ = cz; this.lastUpdateX = x + (((int)(Math.random()*4))<<(this.shiftSize-4)); diff --git a/src/main/java/me/cortex/voxy/client/core/model/ModelManager.java b/src/main/java/me/cortex/voxy/client/core/model/ModelManager.java index 0d5799cf..6bf15886 100644 --- a/src/main/java/me/cortex/voxy/client/core/model/ModelManager.java +++ b/src/main/java/me/cortex/voxy/client/core/model/ModelManager.java @@ -347,7 +347,7 @@ public class ModelManager { public void addBiome(int id, Biome biome) { this.biomes.add(biome); if (this.biomes.size()-1 != id) { - throw new IllegalStateException("Biome ordering not consistent with biome id"); + throw new IllegalStateException("Biome ordering not consistent with biome id for biome " + biome + " expected id: " + (this.biomes.size()-1) + " got id: " + id); } int i = 0; diff --git a/src/main/java/me/cortex/voxy/client/core/model/ModelTextureBakery.java b/src/main/java/me/cortex/voxy/client/core/model/ModelTextureBakery.java index 3d740438..da5e4602 100644 --- a/src/main/java/me/cortex/voxy/client/core/model/ModelTextureBakery.java +++ b/src/main/java/me/cortex/voxy/client/core/model/ModelTextureBakery.java @@ -164,7 +164,8 @@ public class ModelTextureBakery { this.rasterShader.bind(); glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, MinecraftClient.getInstance().getTextureManager().getTexture(new Identifier("minecraft", "textures/atlas/blocks.png")).getGlId()); + int texId = MinecraftClient.getInstance().getTextureManager().getTexture(new Identifier("minecraft", "textures/atlas/blocks.png")).getGlId(); + glBindTexture(GL_TEXTURE_2D, texId); GlUniform.uniform1(0, 0); var faces = new ColourDepthTextureData[FACE_VIEWS.size()]; @@ -192,6 +193,23 @@ public class ModelTextureBakery { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); vc.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR_TEXTURE); + + //if (state.hasBlockEntity() && state.getBlock() == Blocks.CHEST) { + // //TODO: finish BlockEntity raster + // var entity = ((BlockEntityProvider)state.getBlock()).createBlockEntity(BlockPos.ORIGIN, state); + // var renderer = MinecraftClient.getInstance().getBlockEntityRenderDispatcher().get(entity); + // if (renderer != null) { + // entity.setWorld(MinecraftClient.getInstance().world); + // renderer.render(entity, 0.0f, new MatrixStack(), (layer) -> { + // //glBindTexture(GL_TEXTURE_2D); + // return vc; + // }, 0, 0); + // } + // entity.markRemoved(); + //} + + + if (!renderFluid) { renderQuads(vc, state, model, new MatrixStack(), randomValue); } else { @@ -260,15 +278,6 @@ public class ModelTextureBakery { BufferRenderer.draw(vc.end()); - if (state.hasBlockEntity()) { - //TODO: finish BlockEntity raster - //var entity = ((BlockEntityProvider)state).createBlockEntity(BlockPos.ORIGIN, state); - //var renderer = MinecraftClient.getInstance().getBlockEntityRenderDispatcher().get(entity); - //renderer.render(); - //entity.markRemoved(); - } - - glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT); int[] colourData = new int[this.width*this.height]; int[] depthData = new int[this.width*this.height]; diff --git a/src/main/java/me/cortex/voxy/client/core/model/TextureUtils.java b/src/main/java/me/cortex/voxy/client/core/model/TextureUtils.java index 62294d74..573aca02 100644 --- a/src/main/java/me/cortex/voxy/client/core/model/TextureUtils.java +++ b/src/main/java/me/cortex/voxy/client/core/model/TextureUtils.java @@ -95,7 +95,8 @@ public class TextureUtils { // due to this and the unsigned bullshit, i believe the depth value needs to get multiplied by 2 depthF *= 2; if (depthF > 1.00001f) { - throw new IllegalArgumentException("Depth greater than 1"); + System.err.println("Warning: Depth greater than 1"); + depthF = 1.0f; } return depthF; } diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/AbstractFarWorldRenderer.java b/src/main/java/me/cortex/voxy/client/core/rendering/AbstractFarWorldRenderer.java index c13da575..3ebbd38f 100644 --- a/src/main/java/me/cortex/voxy/client/core/rendering/AbstractFarWorldRenderer.java +++ b/src/main/java/me/cortex/voxy/client/core/rendering/AbstractFarWorldRenderer.java @@ -105,7 +105,7 @@ public abstract class AbstractFarWorldRenderer { UploadStream.INSTANCE.commit(); } - int maxUpdatesPerFrame = 30; + int maxUpdatesPerFrame = 10; //Do any BlockChanges while ((!this.blockStateUpdates.isEmpty()) && (maxUpdatesPerFrame-- > 0)) { diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/RenderTracker.java b/src/main/java/me/cortex/voxy/client/core/rendering/RenderTracker.java index 7fd29de8..0f51fad4 100644 --- a/src/main/java/me/cortex/voxy/client/core/rendering/RenderTracker.java +++ b/src/main/java/me/cortex/voxy/client/core/rendering/RenderTracker.java @@ -141,8 +141,8 @@ public class RenderTracker { //Enqueues a renderTask for a section to cache the result public void addCache(int lvl, int x, int y, int z) { - //this.renderGen.markCache(lvl, x, y, z); - //this.renderGen.enqueueTask(lvl, x, y, z, ((lvl1, x1, y1, z1) -> true));//TODO: replace the true identity lambda with a callback check to the render cache + this.renderGen.markCache(lvl, x, y, z); + this.renderGen.enqueueTask(lvl, x, y, z, ((lvl1, x1, y1, z1) -> true));//TODO: replace the true identity lambda with a callback check to the render cache } //Removes the position from the cache diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/building/BuiltSectionMeshCache.java b/src/main/java/me/cortex/voxy/client/core/rendering/building/BuiltSectionMeshCache.java index 868f69c9..cd043580 100644 --- a/src/main/java/me/cortex/voxy/client/core/rendering/building/BuiltSectionMeshCache.java +++ b/src/main/java/me/cortex/voxy/client/core/rendering/building/BuiltSectionMeshCache.java @@ -2,6 +2,8 @@ package me.cortex.voxy.client.core.rendering.building; import java.util.concurrent.ConcurrentHashMap; +//TODO: Have a second level disk cache + //TODO: instead of storing duplicate render geometry between here and gpu memory // when a section is unloaded from the gpu, put it into a download stream and recover the BuiltSection // and put that into the cache, then remove the uploaded mesh from the cache @@ -24,7 +26,9 @@ public class BuiltSectionMeshCache { //Returns true if the mesh was used, (this is so the parent method can free mesh object) public boolean putMesh(BuiltSection mesh) { var mesh2 = this.renderCache.computeIfPresent(mesh.position, (id, value) -> { - value.free(); + if (value != HOLDER) { + value.free(); + } return mesh; }); return mesh2 == mesh; diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/building/RenderGenerationService.java b/src/main/java/me/cortex/voxy/client/core/rendering/building/RenderGenerationService.java index f30e7150..ef3f6032 100644 --- a/src/main/java/me/cortex/voxy/client/core/rendering/building/RenderGenerationService.java +++ b/src/main/java/me/cortex/voxy/client/core/rendering/building/RenderGenerationService.java @@ -61,6 +61,11 @@ public class RenderGenerationService { try { mesh = factory.generateMesh(section); } catch (IdNotYetComputedException e) { + try { + Thread.sleep(100); + } catch (InterruptedException ex) { + throw new RuntimeException(ex); + } //We need to reinsert the build task into the queue //System.err.println("Render task failed to complete due to un-computed client id"); synchronized (this.taskQueue) {