diff --git a/src/main/java/me/cortex/zenith/client/core/model/ModelManager.java b/src/main/java/me/cortex/zenith/client/core/model/ModelManager.java index 9fd5a253..956c330b 100644 --- a/src/main/java/me/cortex/zenith/client/core/model/ModelManager.java +++ b/src/main/java/me/cortex/zenith/client/core/model/ModelManager.java @@ -37,6 +37,9 @@ public class ModelManager { //Model data might also contain a constant colour if the colour resolver produces a constant colour, this saves space in the // section buffer reverse indexing + //model data also contains if a face should be randomly rotated,flipped etc to get rid of moire effect + // this would be done in the fragment shader + //The Meta-cache contains critical information needed for meshing, colour provider bit, per-face = is empty, has alpha, is solid, full width, full height // alpha means that some pixels have alpha values and belong in the translucent rendering layer, // is empty means that the face is air/shouldent be rendered as there is nothing there diff --git a/src/main/java/me/cortex/zenith/client/core/rendering/AbstractFarWorldRenderer.java b/src/main/java/me/cortex/zenith/client/core/rendering/AbstractFarWorldRenderer.java index b2b41dae..e3146be5 100644 --- a/src/main/java/me/cortex/zenith/client/core/rendering/AbstractFarWorldRenderer.java +++ b/src/main/java/me/cortex/zenith/client/core/rendering/AbstractFarWorldRenderer.java @@ -5,6 +5,7 @@ package me.cortex.zenith.client.core.rendering; import me.cortex.zenith.client.core.gl.GlBuffer; import me.cortex.zenith.client.core.model.ModelManager; +import me.cortex.zenith.client.core.rendering.building.BuiltSection; import me.cortex.zenith.client.core.rendering.building.BuiltSectionGeometry; import me.cortex.zenith.client.core.rendering.util.UploadStream; import net.minecraft.client.MinecraftClient; @@ -84,7 +85,7 @@ public abstract class AbstractFarWorldRenderer { public abstract void renderFarAwayOpaque(MatrixStack stack, double cx, double cy, double cz); - public void enqueueResult(BuiltSectionGeometry result) { + public void enqueueResult(BuiltSection result) { this.geometry.enqueueResult(result); } diff --git a/src/main/java/me/cortex/zenith/client/core/rendering/GeometryManager.java b/src/main/java/me/cortex/zenith/client/core/rendering/GeometryManager.java index 07cc84f1..79bfa9a5 100644 --- a/src/main/java/me/cortex/zenith/client/core/rendering/GeometryManager.java +++ b/src/main/java/me/cortex/zenith/client/core/rendering/GeometryManager.java @@ -4,6 +4,7 @@ import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap; import it.unimi.dsi.fastutil.longs.LongArrayList; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import me.cortex.zenith.client.core.gl.GlBuffer; +import me.cortex.zenith.client.core.rendering.building.BuiltSection; import me.cortex.zenith.client.core.rendering.building.BuiltSectionGeometry; import me.cortex.zenith.client.core.rendering.util.BufferArena; import me.cortex.zenith.client.core.rendering.util.UploadStream; @@ -31,7 +32,7 @@ public class GeometryManager { } } - private final ConcurrentLinkedDeque buildResults = new ConcurrentLinkedDeque<>(); + private final ConcurrentLinkedDeque buildResults = new ConcurrentLinkedDeque<>(); private int sectionCount = 0; private final Long2IntOpenHashMap pos2id = new Long2IntOpenHashMap(); @@ -48,15 +49,15 @@ public class GeometryManager { this.pos2id.defaultReturnValue(-1); } - public void enqueueResult(BuiltSectionGeometry sectionGeometry) { + public void enqueueResult(BuiltSection sectionGeometry) { this.buildResults.add(sectionGeometry); } - private SectionMeta createMeta(BuiltSectionGeometry geometry) { - long geometryPtr = this.geometryBuffer.upload(geometry.geometryBuffer); + private SectionMeta createMeta(BuiltSection geometry) { + long geometryPtr = this.geometryBuffer.upload(geometry.buffer); //TODO: support translucent geometry - return new SectionMeta(geometry.position, geometryPtr, (int) (geometry.geometryBuffer.size/8), 0, -1,0, 0); + return new SectionMeta(geometry.position, geometryPtr, (int) (geometry.buffer.size/8), 0, -1,0, 0); } private void freeMeta(SectionMeta meta) { @@ -71,7 +72,7 @@ public class GeometryManager { void uploadResults() { while (!this.buildResults.isEmpty()) { var result = this.buildResults.pop(); - boolean isDelete = result.geometryBuffer == null && result.translucentGeometryBuffer == null; + boolean isDelete = result.buffer == null && result.translucentGeometryBuffer == null; if (isDelete) { int id = -1; if ((id = this.pos2id.remove(result.position)) != -1) { diff --git a/src/main/java/me/cortex/zenith/client/core/rendering/RenderTracker.java b/src/main/java/me/cortex/zenith/client/core/rendering/RenderTracker.java index bfe125ff..71606601 100644 --- a/src/main/java/me/cortex/zenith/client/core/rendering/RenderTracker.java +++ b/src/main/java/me/cortex/zenith/client/core/rendering/RenderTracker.java @@ -1,5 +1,6 @@ package me.cortex.zenith.client.core.rendering; +import me.cortex.zenith.client.core.rendering.building.BuiltSection; import me.cortex.zenith.client.core.rendering.building.BuiltSectionGeometry; import me.cortex.zenith.client.core.rendering.building.RenderGenerationService; import me.cortex.zenith.common.world.WorldEngine; @@ -41,7 +42,7 @@ public class RenderTracker { //Removes a lvl 0 section from the world renderer public void remLvl0(int x, int y, int z) { this.activeSections.remove(WorldEngine.getWorldSectionId(0, x, y, z)); - this.renderer.enqueueResult(new BuiltSectionGeometry(WorldEngine.getWorldSectionId(0, x, y, z), null, null)); + this.renderer.enqueueResult(new BuiltSection(WorldEngine.getWorldSectionId(0, x, y, z), null, null)); this.renderGen.removeTask(0, x, y, z); } @@ -63,14 +64,14 @@ public class RenderTracker { this.renderGen.enqueueTask(lvl, x, y, z, this::shouldStillBuild, this::getBuildFlagsOrAbort); - this.renderer.enqueueResult(new BuiltSectionGeometry(WorldEngine.getWorldSectionId(lvl-1, (x<<1), (y<<1), (z<<1)), null, null)); - this.renderer.enqueueResult(new BuiltSectionGeometry(WorldEngine.getWorldSectionId(lvl-1, (x<<1), (y<<1), (z<<1)+1), null, null)); - this.renderer.enqueueResult(new BuiltSectionGeometry(WorldEngine.getWorldSectionId(lvl-1, (x<<1), (y<<1)+1, (z<<1)), null, null)); - this.renderer.enqueueResult(new BuiltSectionGeometry(WorldEngine.getWorldSectionId(lvl-1, (x<<1), (y<<1)+1, (z<<1)+1), null, null)); - this.renderer.enqueueResult(new BuiltSectionGeometry(WorldEngine.getWorldSectionId(lvl-1, (x<<1)+1, (y<<1), (z<<1)), null, null)); - this.renderer.enqueueResult(new BuiltSectionGeometry(WorldEngine.getWorldSectionId(lvl-1, (x<<1)+1, (y<<1), (z<<1)+1), null, null)); - this.renderer.enqueueResult(new BuiltSectionGeometry(WorldEngine.getWorldSectionId(lvl-1, (x<<1)+1, (y<<1)+1, (z<<1)), null, null)); - this.renderer.enqueueResult(new BuiltSectionGeometry(WorldEngine.getWorldSectionId(lvl-1, (x<<1)+1, (y<<1)+1, (z<<1)+1), null, null)); + this.renderer.enqueueResult(new BuiltSection(WorldEngine.getWorldSectionId(lvl-1, (x<<1), (y<<1), (z<<1)), null, null)); + this.renderer.enqueueResult(new BuiltSection(WorldEngine.getWorldSectionId(lvl-1, (x<<1), (y<<1), (z<<1)+1), null, null)); + this.renderer.enqueueResult(new BuiltSection(WorldEngine.getWorldSectionId(lvl-1, (x<<1), (y<<1)+1, (z<<1)), null, null)); + this.renderer.enqueueResult(new BuiltSection(WorldEngine.getWorldSectionId(lvl-1, (x<<1), (y<<1)+1, (z<<1)+1), null, null)); + this.renderer.enqueueResult(new BuiltSection(WorldEngine.getWorldSectionId(lvl-1, (x<<1)+1, (y<<1), (z<<1)), null, null)); + this.renderer.enqueueResult(new BuiltSection(WorldEngine.getWorldSectionId(lvl-1, (x<<1)+1, (y<<1), (z<<1)+1), null, null)); + this.renderer.enqueueResult(new BuiltSection(WorldEngine.getWorldSectionId(lvl-1, (x<<1)+1, (y<<1)+1, (z<<1)), null, null)); + this.renderer.enqueueResult(new BuiltSection(WorldEngine.getWorldSectionId(lvl-1, (x<<1)+1, (y<<1)+1, (z<<1)+1), null, null)); this.renderGen.removeTask(lvl-1, (x<<1), (y<<1), (z<<1)); @@ -95,7 +96,7 @@ public class RenderTracker { this.activeSections.put(WorldEngine.getWorldSectionId(lvl-1, (x<<1)+1, (y<<1)+1, (z<<1)+1), O); this.activeSections.remove(WorldEngine.getWorldSectionId(lvl, x, y, z)); - this.renderer.enqueueResult(new BuiltSectionGeometry(lvl, x, y, z, null, null)); + this.renderer.enqueueResult(new BuiltSection(WorldEngine.getWorldSectionId(lvl, x, y, z), null, null)); this.renderGen.removeTask(lvl, x, y, z); this.renderGen.enqueueTask(lvl - 1, (x<<1), (y<<1), (z<<1), this::shouldStillBuild, this::getBuildFlagsOrAbort); @@ -134,7 +135,7 @@ public class RenderTracker { //called by the RenderGenerationService about built geometry, the RenderTracker checks if it can use the result (e.g. the LoD hasnt changed/still correct etc) // and dispatches it to the renderer // it also batch collects the geometry sections until all the geometry for an operation is collected, then it executes the operation, its removes flickering - public void processBuildResult(BuiltSectionGeometry section) { + public void processBuildResult(BuiltSection section) { //Check that we still want the section if (this.activeSections.containsKey(section.position)) { this.renderer.enqueueResult(section); diff --git a/src/main/java/me/cortex/zenith/client/core/rendering/building/BuiltSection.java b/src/main/java/me/cortex/zenith/client/core/rendering/building/BuiltSection.java new file mode 100644 index 00000000..92c95990 --- /dev/null +++ b/src/main/java/me/cortex/zenith/client/core/rendering/building/BuiltSection.java @@ -0,0 +1,29 @@ +package me.cortex.zenith.client.core.rendering.building; + +import java.util.Objects; + +//TODO: also have an AABB size stored +public final class BuiltSection { + public final long position; + public final BuiltSectionGeometry opaque; + public final BuiltSectionGeometry translucent; + + public BuiltSection(long position, BuiltSectionGeometry opaque, BuiltSectionGeometry translucent) { + this.position = position; + this.opaque = opaque; + this.translucent = translucent; + } + + public BuiltSection clone() { + return new BuiltSection(this.position, this.opaque != null ? this.opaque.clone() : null, this.translucent != null ? this.translucent.clone() : null); + } + + public void free() { + if (this.opaque != null) { + this.opaque.free(); + } + if (this.translucent != null) { + this.translucent.free(); + } + } +} diff --git a/src/main/java/me/cortex/zenith/client/core/rendering/building/BuiltSectionGeometry.java b/src/main/java/me/cortex/zenith/client/core/rendering/building/BuiltSectionGeometry.java index 83112958..e9165c4d 100644 --- a/src/main/java/me/cortex/zenith/client/core/rendering/building/BuiltSectionGeometry.java +++ b/src/main/java/me/cortex/zenith/client/core/rendering/building/BuiltSectionGeometry.java @@ -1,32 +1,21 @@ package me.cortex.zenith.client.core.rendering.building; import me.cortex.zenith.common.util.MemoryBuffer; -import me.cortex.zenith.common.world.WorldEngine; -public class BuiltSectionGeometry { - public final long position; - public final MemoryBuffer geometryBuffer; - public final MemoryBuffer translucentGeometryBuffer; +import java.util.Arrays; - public BuiltSectionGeometry(int lvl, int x, int y, int z, MemoryBuffer geometryBuffer, MemoryBuffer translucentGeometryBuffer) { - this(WorldEngine.getWorldSectionId(lvl, x, y, z), geometryBuffer, translucentGeometryBuffer); - } - public BuiltSectionGeometry(long position, MemoryBuffer geometryBuffer, MemoryBuffer translucentGeometryBuffer) { - this.position = position; - this.geometryBuffer = geometryBuffer; - this.translucentGeometryBuffer = translucentGeometryBuffer; +/** + * @param startOffsets Will be converted to ending offsets when doing data computation + */ +public record BuiltSectionGeometry(MemoryBuffer buffer, short[] startOffsets) { + + public BuiltSectionGeometry clone() { + return new BuiltSectionGeometry(this.buffer != null ? this.buffer.copy() : null, Arrays.copyOf(this.startOffsets, this.startOffsets.length)); } public void free() { - if (this.geometryBuffer != null) { - this.geometryBuffer.free(); + if (this.buffer != null) { + this.buffer.free(); } - if (this.translucentGeometryBuffer != null) { - this.translucentGeometryBuffer.free(); - } - } - - public BuiltSectionGeometry clone() { - return new BuiltSectionGeometry(this.position, this.geometryBuffer!=null?this.geometryBuffer.copy():null, this.translucentGeometryBuffer!=null?this.translucentGeometryBuffer.copy():null); } } diff --git a/src/main/java/me/cortex/zenith/client/core/rendering/building/RenderDataFactory.java b/src/main/java/me/cortex/zenith/client/core/rendering/building/RenderDataFactory.java index 720ae5d0..ab042db4 100644 --- a/src/main/java/me/cortex/zenith/client/core/rendering/building/RenderDataFactory.java +++ b/src/main/java/me/cortex/zenith/client/core/rendering/building/RenderDataFactory.java @@ -1,23 +1,15 @@ package me.cortex.zenith.client.core.rendering.building; -import it.unimi.dsi.fastutil.longs.LongArrayList; -import me.cortex.zenith.common.util.MemoryBuffer; -import me.cortex.zenith.client.core.util.Mesher2D; import me.cortex.zenith.common.world.WorldEngine; import me.cortex.zenith.common.world.WorldSection; -import me.cortex.zenith.common.world.other.Mapper; import net.minecraft.client.MinecraftClient; -import net.minecraft.util.math.Direction; -import org.lwjgl.system.MemoryUtil; public class RenderDataFactory { - private final Mesher2D mesher = new Mesher2D(5,15);//15 - private final LongArrayList outData = new LongArrayList(1000); private final WorldEngine world; + private final QuadEncoder encoder; private final long[] sectionCache = new long[32*32*32]; private final long[] connectedSectionCache = new long[32*32*32]; - private final QuadEncoder encoder; public RenderDataFactory(WorldEngine world) { this.world = world; this.encoder = new QuadEncoder(world.getMapper(), MinecraftClient.getInstance().getBlockColors(), MinecraftClient.getInstance().world); @@ -32,304 +24,10 @@ public class RenderDataFactory { //buildMask in the lower 6 bits contains the faces to build, the next 6 bits are whether the edge face builds against // its neigbor or not (0 if it does 1 if it doesnt (0 is default behavior)) - public BuiltSectionGeometry generateMesh(WorldSection section, int buildMask) { - //TODO: to speed it up more, check like section.isEmpty() and stuff like that, have masks for if a slice/layer is entirly air etc - - //TODO: instead of having it check its neighbors with the same lod level, compare against 1 level lower, this will prevent cracks and seams from - // appearing between lods - - - //if (section.definitelyEmpty()) {//Fast path if its known the entire chunk is empty - // return new BuiltSectionGeometry(section.getKey(), null, null); - //} - + public BuiltSection generateMesh(WorldSection section, int buildMask) { section.copyDataTo(this.sectionCache); - var data = this.sectionCache; - long[] connectedData = null; - int dirId = Direction.UP.getId(); - if ((buildMask&(1<>(6+dirId))&1) == 0) { - //Load and copy the data into a local cache, TODO: optimize so its not doing billion of copies - if (connectedData == null) { - var connectedSection = this.world.acquire(section.lvl, section.x, section.y + 1, section.z); - connectedSection.copyDataTo(this.connectedSectionCache); - connectedData = this.connectedSectionCache; - connectedSection.release(); - } - up = connectedData[WorldSection.getIndex(x, 0, z)]; - if (!Mapper.isTranslucent(up)) { - continue; - } - } - //Recodes the id to include the correct lighting - this.mesher.put(x, z, (self&~(0xFFL<<56))|(up&(0xFFL<<56))); - } - } - - var count = this.mesher.process(); - var array = this.mesher.getArray(); - for (int i = 0; i < count; i++) { - var quad = array[i]; - this.outData.add(this.encoder.encode(this.mesher.getDataFromQuad(quad), 1, y, quad)); - } - } - connectedData = null; - } - - dirId = Direction.EAST.getId(); - if ((buildMask&(1<>(6+dirId))&1) == 0) { - //Load and copy the data into a local cache, TODO: optimize so its not doing billion of copies - if (connectedData == null) { - var connectedSection = this.world.acquire(section.lvl, section.x + 1, section.y, section.z); - connectedSection.copyDataTo(this.connectedSectionCache); - connectedData = this.connectedSectionCache; - connectedSection.release(); - } - up = connectedData[WorldSection.getIndex(0, y, z)]; - if (!Mapper.isTranslucent(up)) { - continue; - } - } - this.mesher.put(y, z, (self&~(0xFFL<<56))|(up&(0xFFL<<56))); - } - } - - var count = this.mesher.process(); - var array = this.mesher.getArray(); - for (int i = 0; i < count; i++) { - var quad = array[i]; - this.outData.add(this.encoder.encode(this.mesher.getDataFromQuad(quad), 5, x, quad)); - } - } - connectedData = null; - } - - dirId = Direction.SOUTH.getId(); - if ((buildMask&(1<>(6+dirId))&1) == 0) { - //Load and copy the data into a local cache, TODO: optimize so its not doing billion of copies - if (connectedData == null) { - var connectedSection = this.world.acquire(section.lvl, section.x, section.y, section.z + 1); - connectedSection.copyDataTo(this.connectedSectionCache); - connectedData = this.connectedSectionCache; - connectedSection.release(); - } - up = connectedData[WorldSection.getIndex(x, y, 0)]; - if (!Mapper.isTranslucent(up)) { - continue; - } - } - this.mesher.put(x, y, (self&~(0xFFL<<56))|(up&(0xFFL<<56))); - } - } - - var count = this.mesher.process(); - var array = this.mesher.getArray(); - for (int i = 0; i < count; i++) { - var quad = array[i]; - this.outData.add(this.encoder.encode(this.mesher.getDataFromQuad(quad), 3, z, quad)); - } - } - connectedData = null; - } - - dirId = Direction.WEST.getId(); - if ((buildMask&(1<>(6+dirId))&1) == 0) { - //Load and copy the data into a local cache, TODO: optimize so its not doing billion of copies - if (connectedData == null) { - var connectedSection = this.world.acquire(section.lvl, section.x - 1, section.y, section.z); - connectedSection.copyDataTo(this.connectedSectionCache); - connectedData = this.connectedSectionCache; - connectedSection.release(); - } - up = connectedData[WorldSection.getIndex(31, y, z)]; - if (!Mapper.isTranslucent(up)) { - continue; - } - } - this.mesher.put(y, z, (self&~(0xFFL<<56))|(up&(0xFFL<<56))); - } - } - - var count = this.mesher.process(); - var array = this.mesher.getArray(); - for (int i = 0; i < count; i++) { - var quad = array[i]; - this.outData.add(this.encoder.encode(this.mesher.getDataFromQuad(quad), 4, x, quad)); - } - } - connectedData = null; - } - - dirId = Direction.NORTH.getId(); - if ((buildMask&(1<>(6+dirId))&1) == 0) { - //Load and copy the data into a local cache, TODO: optimize so its not doing billion of copies - if (connectedData == null) { - var connectedSection = this.world.acquire(section.lvl, section.x, section.y, section.z - 1); - connectedSection.copyDataTo(this.connectedSectionCache); - connectedData = this.connectedSectionCache; - connectedSection.release(); - } - up = connectedData[WorldSection.getIndex(x, y, 31)]; - if (!Mapper.isTranslucent(up)) { - continue; - } - } - this.mesher.put(x, y, (self&~(0xFFL<<56))|(up&(0xFFL<<56))); - } - } - - var count = this.mesher.process(); - var array = this.mesher.getArray(); - for (int i = 0; i < count; i++) { - var quad = array[i]; - this.outData.add(this.encoder.encode(this.mesher.getDataFromQuad(quad), 2, z, quad)); - } - } - connectedData = null; - } - - dirId = Direction.DOWN.getId(); - if ((buildMask&(1<>(6+dirId))&1) == 0) { - //Load and copy the data into a local cache, TODO: optimize so its not doing billion of copies - if (connectedData == null) { - var connectedSection = this.world.acquire(section.lvl, section.x, section.y - 1, section.z); - connectedSection.copyDataTo(this.connectedSectionCache); - connectedData = this.connectedSectionCache; - connectedSection.release(); - } - up = connectedData[WorldSection.getIndex(x, 31, z)]; - if (!Mapper.isTranslucent(up)) { - continue; - } - } - this.mesher.put(x, z, (self&~(0xFFL<<56))|(up&(0xFFL<<56))); - } - } - - var count = this.mesher.process(); - var array = this.mesher.getArray(); - for (int i = 0; i < count; i++) { - var quad = array[i]; - this.outData.add(this.encoder.encode(this.mesher.getDataFromQuad(quad), 0, y, quad)); - } - } - connectedData = null; - } - - - if (this.outData.isEmpty()) { - return new BuiltSectionGeometry(section.getKey(), null, null); - } - - var output = new MemoryBuffer(this.outData.size()*8L); - for (int i = 0; i < this.outData.size(); i++) { - MemoryUtil.memPutLong(output.address + i * 8L, this.outData.getLong(i)); - } - - this.outData.clear(); - return new BuiltSectionGeometry(section.getKey(), output, null); + return new BuiltSection(section.getKey(), null, null); } } diff --git a/src/main/java/me/cortex/zenith/client/core/rendering/building/RenderDataFactoryOld.java b/src/main/java/me/cortex/zenith/client/core/rendering/building/RenderDataFactoryOld.java new file mode 100644 index 00000000..b2de5790 --- /dev/null +++ b/src/main/java/me/cortex/zenith/client/core/rendering/building/RenderDataFactoryOld.java @@ -0,0 +1,335 @@ +package me.cortex.zenith.client.core.rendering.building; + +import it.unimi.dsi.fastutil.longs.LongArrayList; +import me.cortex.zenith.common.util.MemoryBuffer; +import me.cortex.zenith.client.core.util.Mesher2D; +import me.cortex.zenith.common.world.WorldEngine; +import me.cortex.zenith.common.world.WorldSection; +import me.cortex.zenith.common.world.other.Mapper; +import net.minecraft.client.MinecraftClient; +import net.minecraft.util.math.Direction; +import org.lwjgl.system.MemoryUtil; + + +public class RenderDataFactoryOld { + private final Mesher2D mesher = new Mesher2D(5,15);//15 + private final LongArrayList outData = new LongArrayList(1000); + private final WorldEngine world; + private final long[] sectionCache = new long[32*32*32]; + private final long[] connectedSectionCache = new long[32*32*32]; + private final QuadEncoder encoder; + public RenderDataFactoryOld(WorldEngine world) { + this.world = world; + this.encoder = new QuadEncoder(world.getMapper(), MinecraftClient.getInstance().getBlockColors(), MinecraftClient.getInstance().world); + } + + + //TODO: MAKE a render cache that caches each WorldSection directional face generation, cause then can just pull that directly + // instead of needing to regen the entire thing + + + //section is already acquired and gets released by the parent + + //buildMask in the lower 6 bits contains the faces to build, the next 6 bits are whether the edge face builds against + // its neigbor or not (0 if it does 1 if it doesnt (0 is default behavior)) + public void generateMesh(WorldSection section, int buildMask) { + //TODO: to speed it up more, check like section.isEmpty() and stuff like that, have masks for if a slice/layer is entirly air etc + + //TODO: instead of having it check its neighbors with the same lod level, compare against 1 level lower, this will prevent cracks and seams from + // appearing between lods + + + //if (section.definitelyEmpty()) {//Fast path if its known the entire chunk is empty + // return new BuiltSectionGeometry(section.getKey(), null, null); + //} + + section.copyDataTo(this.sectionCache); + var data = this.sectionCache; + + long[] connectedData = null; + int dirId = Direction.UP.getId(); + if ((buildMask&(1<>(6+dirId))&1) == 0) { + //Load and copy the data into a local cache, TODO: optimize so its not doing billion of copies + if (connectedData == null) { + var connectedSection = this.world.acquire(section.lvl, section.x, section.y + 1, section.z); + connectedSection.copyDataTo(this.connectedSectionCache); + connectedData = this.connectedSectionCache; + connectedSection.release(); + } + up = connectedData[WorldSection.getIndex(x, 0, z)]; + if (!Mapper.isTranslucent(up)) { + continue; + } + } + //Recodes the id to include the correct lighting + this.mesher.put(x, z, (self&~(0xFFL<<56))|(up&(0xFFL<<56))); + } + } + + var count = this.mesher.process(); + var array = this.mesher.getArray(); + for (int i = 0; i < count; i++) { + var quad = array[i]; + this.outData.add(this.encoder.encode(this.mesher.getDataFromQuad(quad), 1, y, quad)); + } + } + connectedData = null; + } + + dirId = Direction.EAST.getId(); + if ((buildMask&(1<>(6+dirId))&1) == 0) { + //Load and copy the data into a local cache, TODO: optimize so its not doing billion of copies + if (connectedData == null) { + var connectedSection = this.world.acquire(section.lvl, section.x + 1, section.y, section.z); + connectedSection.copyDataTo(this.connectedSectionCache); + connectedData = this.connectedSectionCache; + connectedSection.release(); + } + up = connectedData[WorldSection.getIndex(0, y, z)]; + if (!Mapper.isTranslucent(up)) { + continue; + } + } + this.mesher.put(y, z, (self&~(0xFFL<<56))|(up&(0xFFL<<56))); + } + } + + var count = this.mesher.process(); + var array = this.mesher.getArray(); + for (int i = 0; i < count; i++) { + var quad = array[i]; + this.outData.add(this.encoder.encode(this.mesher.getDataFromQuad(quad), 5, x, quad)); + } + } + connectedData = null; + } + + dirId = Direction.SOUTH.getId(); + if ((buildMask&(1<>(6+dirId))&1) == 0) { + //Load and copy the data into a local cache, TODO: optimize so its not doing billion of copies + if (connectedData == null) { + var connectedSection = this.world.acquire(section.lvl, section.x, section.y, section.z + 1); + connectedSection.copyDataTo(this.connectedSectionCache); + connectedData = this.connectedSectionCache; + connectedSection.release(); + } + up = connectedData[WorldSection.getIndex(x, y, 0)]; + if (!Mapper.isTranslucent(up)) { + continue; + } + } + this.mesher.put(x, y, (self&~(0xFFL<<56))|(up&(0xFFL<<56))); + } + } + + var count = this.mesher.process(); + var array = this.mesher.getArray(); + for (int i = 0; i < count; i++) { + var quad = array[i]; + this.outData.add(this.encoder.encode(this.mesher.getDataFromQuad(quad), 3, z, quad)); + } + } + connectedData = null; + } + + dirId = Direction.WEST.getId(); + if ((buildMask&(1<>(6+dirId))&1) == 0) { + //Load and copy the data into a local cache, TODO: optimize so its not doing billion of copies + if (connectedData == null) { + var connectedSection = this.world.acquire(section.lvl, section.x - 1, section.y, section.z); + connectedSection.copyDataTo(this.connectedSectionCache); + connectedData = this.connectedSectionCache; + connectedSection.release(); + } + up = connectedData[WorldSection.getIndex(31, y, z)]; + if (!Mapper.isTranslucent(up)) { + continue; + } + } + this.mesher.put(y, z, (self&~(0xFFL<<56))|(up&(0xFFL<<56))); + } + } + + var count = this.mesher.process(); + var array = this.mesher.getArray(); + for (int i = 0; i < count; i++) { + var quad = array[i]; + this.outData.add(this.encoder.encode(this.mesher.getDataFromQuad(quad), 4, x, quad)); + } + } + connectedData = null; + } + + dirId = Direction.NORTH.getId(); + if ((buildMask&(1<>(6+dirId))&1) == 0) { + //Load and copy the data into a local cache, TODO: optimize so its not doing billion of copies + if (connectedData == null) { + var connectedSection = this.world.acquire(section.lvl, section.x, section.y, section.z - 1); + connectedSection.copyDataTo(this.connectedSectionCache); + connectedData = this.connectedSectionCache; + connectedSection.release(); + } + up = connectedData[WorldSection.getIndex(x, y, 31)]; + if (!Mapper.isTranslucent(up)) { + continue; + } + } + this.mesher.put(x, y, (self&~(0xFFL<<56))|(up&(0xFFL<<56))); + } + } + + var count = this.mesher.process(); + var array = this.mesher.getArray(); + for (int i = 0; i < count; i++) { + var quad = array[i]; + this.outData.add(this.encoder.encode(this.mesher.getDataFromQuad(quad), 2, z, quad)); + } + } + connectedData = null; + } + + dirId = Direction.DOWN.getId(); + if ((buildMask&(1<>(6+dirId))&1) == 0) { + //Load and copy the data into a local cache, TODO: optimize so its not doing billion of copies + if (connectedData == null) { + var connectedSection = this.world.acquire(section.lvl, section.x, section.y - 1, section.z); + connectedSection.copyDataTo(this.connectedSectionCache); + connectedData = this.connectedSectionCache; + connectedSection.release(); + } + up = connectedData[WorldSection.getIndex(x, 31, z)]; + if (!Mapper.isTranslucent(up)) { + continue; + } + } + this.mesher.put(x, z, (self&~(0xFFL<<56))|(up&(0xFFL<<56))); + } + } + + var count = this.mesher.process(); + var array = this.mesher.getArray(); + for (int i = 0; i < count; i++) { + var quad = array[i]; + this.outData.add(this.encoder.encode(this.mesher.getDataFromQuad(quad), 0, y, quad)); + } + } + connectedData = null; + } + + + if (this.outData.isEmpty()) { + //return new BuiltSectionGeometry(section.getKey(), null, null); + } + + var output = new MemoryBuffer(this.outData.size()*8L); + for (int i = 0; i < this.outData.size(); i++) { + MemoryUtil.memPutLong(output.address + i * 8L, this.outData.getLong(i)); + } + + this.outData.clear(); + //return new BuiltSectionGeometry(section.getKey(), output, null); + } + +} diff --git a/src/main/java/me/cortex/zenith/client/core/rendering/building/RenderGenerationService.java b/src/main/java/me/cortex/zenith/client/core/rendering/building/RenderGenerationService.java index a090bc66..7c361e6e 100644 --- a/src/main/java/me/cortex/zenith/client/core/rendering/building/RenderGenerationService.java +++ b/src/main/java/me/cortex/zenith/client/core/rendering/building/RenderGenerationService.java @@ -22,9 +22,9 @@ public class RenderGenerationService { private final Semaphore taskCounter = new Semaphore(0); private final WorldEngine world; - private final Consumer resultConsumer; + private final Consumer resultConsumer; - public RenderGenerationService(WorldEngine world, int workers, Consumer consumer) { + public RenderGenerationService(WorldEngine world, int workers, Consumer consumer) { this.world = world; this.resultConsumer = consumer; this.workers = new Thread[workers]; @@ -36,7 +36,7 @@ public class RenderGenerationService { } } - private final ConcurrentHashMap renderCache = new ConcurrentHashMap<>(1000,0.75f,10); + private final ConcurrentHashMap renderCache = new ConcurrentHashMap<>(1000,0.75f,10); //TODO: add a generated render data cache private void renderWorker() { @@ -156,6 +156,6 @@ public class RenderGenerationService { while (!this.taskQueue.isEmpty()) { this.taskQueue.removeFirst(); } - this.renderCache.values().forEach(BuiltSectionGeometry::free); + this.renderCache.values().forEach(BuiltSection::free); } }