diff --git a/src/main/java/me/cortex/zenith/client/core/DistanceTracker.java b/src/main/java/me/cortex/zenith/client/core/DistanceTracker.java index 4ec07d34..3300157e 100644 --- a/src/main/java/me/cortex/zenith/client/core/DistanceTracker.java +++ b/src/main/java/me/cortex/zenith/client/core/DistanceTracker.java @@ -28,15 +28,17 @@ public class DistanceTracker { this.minYSection = MinecraftClient.getInstance().world.getBottomSectionCoord()/2; this.maxYSection = MinecraftClient.getInstance().world.getTopSectionCoord()/2; - this.rings[0] = new TransitionRing2D(5, MinecraftClient.getInstance().options.getViewDistance().getValue()/2, (x, z)->{ - for (int y = this.minYSection; y <= this.maxYSection; y++) { - this.tracker.remLvl0(x, y, z); - } - }, (x, z) -> { - for (int y = this.minYSection; y <= this.maxYSection; y++) { - this.tracker.addLvl0(x, y, z); - } - }); + if (false) { + this.rings[0] = new TransitionRing2D(5, MinecraftClient.getInstance().options.getViewDistance().getValue() / 2, (x, z) -> { + for (int y = this.minYSection; y <= this.maxYSection; y++) { + this.tracker.remLvl0(x, y, z); + } + }, (x, z) -> { + for (int y = this.minYSection; y <= this.maxYSection; y++) { + this.tracker.addLvl0(x, y, z); + } + }); + } //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 // there will still be 32 chunks untill the first lod drop diff --git a/src/main/java/me/cortex/zenith/client/core/VoxelCore.java b/src/main/java/me/cortex/zenith/client/core/VoxelCore.java index f5fef648..3a15ab1d 100644 --- a/src/main/java/me/cortex/zenith/client/core/VoxelCore.java +++ b/src/main/java/me/cortex/zenith/client/core/VoxelCore.java @@ -66,7 +66,7 @@ public class VoxelCore { System.out.println("World engine"); this.renderTracker = new RenderTracker(this.world, this.renderer); - this.renderGen = new RenderGenerationService(this.world,ZenithConfig.CONFIG.renderThreads, this.renderTracker::processBuildResult); + this.renderGen = new RenderGenerationService(this.world, this.renderer.getModelManager(), ZenithConfig.CONFIG.renderThreads, this.renderTracker::processBuildResult); this.world.setDirtyCallback(this.renderTracker::sectionUpdated); this.renderTracker.setRenderGen(this.renderGen); System.out.println("Render tracker and generator initialized"); @@ -97,14 +97,10 @@ public class VoxelCore { boolean firstTime = true; public void renderSetup(Frustum frustum, Camera camera) { if (this.firstTime) { - //this.distanceTracker.init(camera.getBlockPos().getX(), camera.getBlockPos().getZ()); + this.distanceTracker.init(camera.getBlockPos().getX(), camera.getBlockPos().getZ()); this.firstTime = false; - - this.renderTracker.addLvl0(0,6,0); - - } - //this.distanceTracker.setCenter(camera.getBlockPos().getX(), camera.getBlockPos().getY(), camera.getBlockPos().getZ()); + this.distanceTracker.setCenter(camera.getBlockPos().getX(), camera.getBlockPos().getY(), camera.getBlockPos().getZ()); this.renderer.setupRender(frustum, camera); } 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 3b1fac57..a9fe5e84 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 @@ -212,6 +212,15 @@ public class ModelManager { metadata |= occludesFace?1:0; + + boolean canBeOccluded = true; + //TODO: make this an option on how far/close + canBeOccluded &= offset < 0.3;//If the face is rendered far away from the other face, then it cant be occluded + + metadata |= canBeOccluded?4:0; + + + //Scale face size from 0->this.modelTextureSize-1 to 0->15 for (int i = 0; i < 4; i++) { faceSize[i] = Math.round((((float)faceSize[i])/(this.modelTextureSize-1))*15); @@ -236,6 +245,28 @@ public class ModelManager { } + public static boolean faceExists(long metadata, int face) { + return ((metadata>>(8*face))&0xFF)!=0xFF; + } + + public static boolean faceCanBeOccluded(long metadata, int face) { + return ((metadata>>(8*face))&0b100)==0b100; + } + + public static boolean faceOccludes(long metadata, int face) { + return faceExists(metadata, face) && ((metadata>>(8*face))&0b1)==0b1; + } + + public static boolean isColoured(long metadata) { + //TODO: THIS + return false; + } + + public static boolean isTranslucent(long metadata) { + //TODO: THIS + return false; + } + diff --git a/src/main/java/me/cortex/zenith/client/core/rendering/building/QuadEncoder.java b/src/main/java/me/cortex/zenith/client/core/rendering/building/QuadEncoder.java index a75b5a07..4bc206f0 100644 --- a/src/main/java/me/cortex/zenith/client/core/rendering/building/QuadEncoder.java +++ b/src/main/java/me/cortex/zenith/client/core/rendering/building/QuadEncoder.java @@ -1,6 +1,8 @@ package me.cortex.zenith.client.core.rendering.building; +import me.cortex.zenith.client.core.model.ModelManager; +import me.cortex.zenith.client.core.rendering.GeometryManager; import me.cortex.zenith.client.core.util.Mesher2D; import me.cortex.zenith.common.world.other.Mapper; import net.minecraft.client.color.block.BlockColors; 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 9e904667..f412aecf 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,19 +1,27 @@ package me.cortex.zenith.client.core.rendering.building; +import it.unimi.dsi.fastutil.longs.LongArrayList; +import me.cortex.zenith.client.core.model.ModelManager; +import me.cortex.zenith.client.core.util.Mesher2D; import me.cortex.zenith.common.util.MemoryBuffer; 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 org.lwjgl.system.MemoryUtil; +import java.util.Map; + public class RenderDataFactory { private final WorldEngine world; + private final ModelManager modelMan; private final QuadEncoder encoder; private final long[] sectionCache = new long[32*32*32]; private final long[] connectedSectionCache = new long[32*32*32]; - public RenderDataFactory(WorldEngine world) { + public RenderDataFactory(WorldEngine world, ModelManager modelManager) { this.world = world; + this.modelMan = modelManager; this.encoder = new QuadEncoder(world.getMapper(), MinecraftClient.getInstance().getBlockColors(), MinecraftClient.getInstance().world); } @@ -33,15 +41,83 @@ public class RenderDataFactory { // if the connecting type of the translucent block is the same AND the face is full, discard it // this stops e.g. multiple layers of glass (and ocean) from having 3000 layers of quads etc - var buff = new MemoryBuffer(8*8); - MemoryUtil.memPutLong(buff.address, encodeRaw(2, 0,0,0,0,0,515,0, 0));//92 - MemoryUtil.memPutLong(buff.address+8, encodeRaw(3, 0,0,0,0,0,515,0, 0));//92 - MemoryUtil.memPutLong(buff.address+16, encodeRaw(4, 0,2,0,0,0,515,0, 0));//92 - MemoryUtil.memPutLong(buff.address+24, encodeRaw(5, 0,2,0,0,0,515,0, 0));//92 - MemoryUtil.memPutLong(buff.address+32, encodeRaw(2, 0,0,0,0,1,515,0, 0));//92 - MemoryUtil.memPutLong(buff.address+40, encodeRaw(3, 0,0,0,0,1,515,0, 0));//92 - MemoryUtil.memPutLong(buff.address+48, encodeRaw(2, 0,0,0,0,2,515,0, 0));//92 - MemoryUtil.memPutLong(buff.address+56, encodeRaw(3, 0,0,0,0,2,515,0, 0));//92 + + Mesher2D mesher = new Mesher2D(5,15); + + LongArrayList outData = new LongArrayList(1000); + + //Up direction + + for (int y = 0; y < 32; y++) { + mesher.reset(); + for (int x = 0; x < 32; x++) { + for (int z = 0; z < 32; z++) { + long self = this.sectionCache[WorldSection.getIndex(x, y, z)]; + if (Mapper.isAir(self)) continue; + + int selfBlockId = Mapper.getBlockId(self); + long metadata = this.modelMan.getModelMetadata(selfBlockId); + + //If the model doesnt have a face, then just skip it + if (!ModelManager.faceExists(metadata, 1)) { + continue; + } + + long facingState = Mapper.AIR; + //Need to access the other connecting section + if (y == 31) { + + } else { + facingState = this.sectionCache[WorldSection.getIndex(x, y+1, z)]; + } + + long facingMetadata = this.modelMan.getModelMetadata(Mapper.getBlockId(facingState)); + + //If face can be occluded and is occluded from the facing block, then dont render the face + if (ModelManager.faceCanBeOccluded(metadata, 1) && ModelManager.faceOccludes(facingMetadata, 0)) { + continue; + } + + int clientModelId = this.modelMan.getModelId(selfBlockId); + + mesher.put(x, z, ((long)clientModelId) | (((long) Mapper.getLightId(facingState))<<16) | (((long) Mapper.getBiomeId(self))<<24)); + } + } + + //TODO: encode translucents and double sided quads to different global buffers + int count = mesher.process(); + var array = mesher.getArray(); + for (int i = 0; i < count; i++) { + int quad = array[i]; + long data = mesher.getDataFromQuad(quad); + outData.add(Integer.toUnsignedLong(QuadEncoder.encodePosition(1, y, quad)) | ((data&0xFFFF)<<26) | (((data>>16)&0xFF)<<55) | (((data>>24)&0x1FF)<<46)); + //outData.add(Integer.toUnsignedLong(QuadEncoder.encodePosition(1, y, quad)) | (1<<26)); + } + } + + + + + + //var buff = new MemoryBuffer(8*8); + //MemoryUtil.memPutLong(buff.address, encodeRaw(2, 0,1,0,0,0,159,0, 0));//92 515 + //MemoryUtil.memPutLong(buff.address+8, encodeRaw(3, 0,1,0,0,0,159,0, 0));//92 515 + //MemoryUtil.memPutLong(buff.address+16, encodeRaw(4, 1,2,0,0,0,159,0, 0));//92 515 + //MemoryUtil.memPutLong(buff.address+24, encodeRaw(5, 1,2,0,0,0,159,0, 0));//92 515 + //MemoryUtil.memPutLong(buff.address+32, encodeRaw(2, 0,1,0,0,1,159,0, 0));//92 515 + //MemoryUtil.memPutLong(buff.address+40, encodeRaw(3, 0,1,0,0,1,159,0, 0));//92 515 + //MemoryUtil.memPutLong(buff.address+48, encodeRaw(2, 0,1,0,0,2,159,0, 0));//92 515 + //MemoryUtil.memPutLong(buff.address+56, encodeRaw(3, 0,1,0,0,2,159,0, 0));//92 515 + if (outData.isEmpty()) { + return new BuiltSection(section.getKey(), null, null); + } + + //outData.add(encodeRaw(3, 0,1,0,0,0,159,0, 0)); + var buff = new MemoryBuffer(outData.size()*8L); + long ptr = buff.address; + for (long data : outData) { + MemoryUtil.memPutLong(ptr, data); ptr+=8; + } return new BuiltSection(section.getKey(), new BuiltSectionGeometry(buff, new short[0]), 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 index b2de5790..70eedb32 100644 --- 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 @@ -12,6 +12,7 @@ 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; @@ -331,5 +332,6 @@ public class RenderDataFactoryOld { 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 7c361e6e..2ebf190c 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 @@ -1,6 +1,7 @@ package me.cortex.zenith.client.core.rendering.building; import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; +import me.cortex.zenith.client.core.model.ModelManager; import me.cortex.zenith.common.world.WorldEngine; import me.cortex.zenith.common.world.WorldSection; @@ -22,10 +23,12 @@ public class RenderGenerationService { private final Semaphore taskCounter = new Semaphore(0); private final WorldEngine world; + private final ModelManager modelManager; private final Consumer resultConsumer; - public RenderGenerationService(WorldEngine world, int workers, Consumer consumer) { + public RenderGenerationService(WorldEngine world, ModelManager modelManager, int workers, Consumer consumer) { this.world = world; + this.modelManager = modelManager; this.resultConsumer = consumer; this.workers = new Thread[workers]; for (int i = 0; i < workers; i++) { @@ -41,7 +44,7 @@ public class RenderGenerationService { //TODO: add a generated render data cache private void renderWorker() { //Thread local instance of the factory - var factory = new RenderDataFactory(this.world); + var factory = new RenderDataFactory(this.world, this.modelManager); while (this.running) { this.taskCounter.acquireUninterruptibly(); if (!this.running) break; diff --git a/src/main/java/me/cortex/zenith/client/mixin/sodium/MixinSodiumWorldRender.java b/src/main/java/me/cortex/zenith/client/mixin/sodium/MixinSodiumWorldRender.java new file mode 100644 index 00000000..be7ae1e8 --- /dev/null +++ b/src/main/java/me/cortex/zenith/client/mixin/sodium/MixinSodiumWorldRender.java @@ -0,0 +1,19 @@ +package me.cortex.zenith.client.mixin.sodium; + +import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; +import me.jellysquid.mods.sodium.client.render.chunk.occlusion.OcclusionCuller; +import net.minecraft.client.render.RenderLayer; +import net.minecraft.client.util.math.MatrixStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(value = SodiumWorldRenderer.class, remap = false) +public class MixinSodiumWorldRender { + @Inject(method = "drawChunkLayer", at = @At("HEAD"), cancellable = true) + private void cancelRender(RenderLayer renderLayer, MatrixStack matrixStack, double x, double y, double z, CallbackInfo ci) { + ci.cancel(); + } +} diff --git a/src/main/java/me/cortex/zenith/common/world/other/Mapper.java b/src/main/java/me/cortex/zenith/common/world/other/Mapper.java index 8e94130a..4dea991a 100644 --- a/src/main/java/me/cortex/zenith/common/world/other/Mapper.java +++ b/src/main/java/me/cortex/zenith/common/world/other/Mapper.java @@ -51,18 +51,20 @@ public class Mapper { } - public static boolean isTranslucent(long id) { - //Atm hardcode to air - return ((id>>27)&((1<<20)-1)) == 0; - } - public static boolean isAir(long id) { return ((id>>27)&((1<<20)-1)) == 0; } - public static boolean shouldRenderFace(int dirId, long self, long other) { - //TODO: fixme make it be with respect to the type itself e.g. water, glass etc - return isTranslucent(other); + public static int getBlockId(long id) { + return (int) ((id>>27)&((1<<20)-1)); + } + + public static int getBiomeId(long id) { + return (int) ((id>>47)&0x1FF); + } + + public static int getLightId(long id) { + return (int) ((id>>56)&0xFF); } public void setCallbacks(Consumer stateCallback, Consumer biomeCallback) { diff --git a/src/main/resources/assets/zenith/shaders/lod/gl46/bindings.glsl b/src/main/resources/assets/zenith/shaders/lod/gl46/bindings.glsl index b52fba54..da13de92 100644 --- a/src/main/resources/assets/zenith/shaders/lod/gl46/bindings.glsl +++ b/src/main/resources/assets/zenith/shaders/lod/gl46/bindings.glsl @@ -23,6 +23,8 @@ struct SectionMeta { uint _padA; uint ptr; uint cnt; + uint _padB; + uint _padC; }; //TODO: see if making the stride 2*4*4 bytes or something cause you get that 16 byte write diff --git a/src/main/resources/zenith.mixins.json b/src/main/resources/zenith.mixins.json index 93bb39f8..11b2dd81 100644 --- a/src/main/resources/zenith.mixins.json +++ b/src/main/resources/zenith.mixins.json @@ -15,6 +15,7 @@ "defaultRequire": 1 }, "mixins": [ - "sodium.MixinOcclusionCuller" + "sodium.MixinOcclusionCuller", + "sodium.MixinSodiumWorldRender" ] }