diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/SkyLightSectionStorageExtension.java b/common/src/backend/java/dev/engine_room/flywheel/backend/SkyLightSectionStorageExtension.java new file mode 100644 index 000000000..fe3596c1e --- /dev/null +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/SkyLightSectionStorageExtension.java @@ -0,0 +1,9 @@ +package dev.engine_room.flywheel.backend; + +import org.jetbrains.annotations.Nullable; + +import net.minecraft.world.level.chunk.DataLayer; + +public interface SkyLightSectionStorageExtension { + @Nullable DataLayer flywheel$skyDataLayer(long section); +} diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/LightStorage.java b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/LightStorage.java index 9b3f779f7..be9df4981 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/LightStorage.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/LightStorage.java @@ -10,8 +10,10 @@ import dev.engine_room.flywheel.api.visual.EffectVisual; import dev.engine_room.flywheel.api.visualization.VisualizationContext; import dev.engine_room.flywheel.api.visualization.VisualizationManager; +import dev.engine_room.flywheel.backend.SkyLightSectionStorageExtension; import dev.engine_room.flywheel.backend.engine.indirect.StagingBuffer; import dev.engine_room.flywheel.backend.gl.buffer.GlBuffer; +import dev.engine_room.flywheel.backend.mixin.light.LightEngineAccessor; import dev.engine_room.flywheel.lib.instance.InstanceTypes; import dev.engine_room.flywheel.lib.instance.TransformedInstance; import dev.engine_room.flywheel.lib.math.MoreMath; @@ -27,9 +29,10 @@ import net.minecraft.client.renderer.LightTexture; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; +import net.minecraft.core.Vec3i; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.LightLayer; -import net.minecraft.world.level.lighting.LayerLightEventListener; +import net.minecraft.world.level.chunk.DataLayer; /** * A managed arena of light sections for uploading to the GPU. @@ -55,6 +58,9 @@ public class LightStorage implements Effect { private static final int DEFAULT_ARENA_CAPACITY_SECTIONS = 64; private static final int INVALID_SECTION = -1; + private static final ConstantDataLayer EMPTY_BLOCK_DATA = new ConstantDataLayer(0); + private static final ConstantDataLayer EMPTY_SKY_DATA = new ConstantDataLayer(15); + private final LevelAccessor level; private final LightLut lut; private final CpuArena arena; @@ -194,11 +200,6 @@ public int capacity() { } public void collectSection(long section) { - var lightEngine = level.getLightEngine(); - - var blockLight = lightEngine.getLayerListener(LightLayer.BLOCK); - var skyLight = lightEngine.getLayerListener(LightLayer.SKY); - int index = indexForSection(section); changed.set(index); @@ -210,21 +211,21 @@ public void collectSection(long section) { collectSolidData(ptr, section); - collectCenter(blockLight, skyLight, ptr, section); + collectCenter(ptr, section); for (SectionEdge i : SectionEdge.values()) { - collectYZPlane(blockLight, skyLight, ptr, SectionPos.offset(section, i.sectionOffset, 0, 0), i); - collectXZPlane(blockLight, skyLight, ptr, SectionPos.offset(section, 0, i.sectionOffset, 0), i); - collectXYPlane(blockLight, skyLight, ptr, SectionPos.offset(section, 0, 0, i.sectionOffset), i); + collectYZPlane(ptr, SectionPos.offset(section, i.sectionOffset, 0, 0), i); + collectXZPlane(ptr, SectionPos.offset(section, 0, i.sectionOffset, 0), i); + collectXYPlane(ptr, SectionPos.offset(section, 0, 0, i.sectionOffset), i); for (SectionEdge j : SectionEdge.values()) { - collectXStrip(blockLight, skyLight, ptr, SectionPos.offset(section, 0, i.sectionOffset, j.sectionOffset), i, j); - collectYStrip(blockLight, skyLight, ptr, SectionPos.offset(section, i.sectionOffset, 0, j.sectionOffset), i, j); - collectZStrip(blockLight, skyLight, ptr, SectionPos.offset(section, i.sectionOffset, j.sectionOffset, 0), i, j); + collectXStrip(ptr, SectionPos.offset(section, 0, i.sectionOffset, j.sectionOffset), i, j); + collectYStrip(ptr, SectionPos.offset(section, i.sectionOffset, 0, j.sectionOffset), i, j); + collectZStrip(ptr, SectionPos.offset(section, i.sectionOffset, j.sectionOffset, 0), i, j); } } - collectCorners(blockLight, skyLight, ptr, section); + collectCorners(ptr, section); } private void collectSolidData(long ptr, long section) { @@ -259,64 +260,59 @@ private void collectSolidData(long ptr, long section) { } } - private void writeSolid(long ptr, int index, boolean blockValid) { - if (!blockValid) { - return; - } - int intIndex = index / Integer.SIZE; - int bitIndex = index % Integer.SIZE; + private DataLayer getSkyData(long section) { + var sky = level.getLightEngine() + .getLayerListener(LightLayer.SKY); + var skyStorage = (SkyLightSectionStorageExtension) ((LightEngineAccessor) sky).flywheel$storage(); - long offset = intIndex * Integer.BYTES; + var out = skyStorage.flywheel$skyDataLayer(section); - int bitField = MemoryUtil.memGetInt(ptr + offset); - bitField |= 1 << bitIndex; + if (out == null) { + return EMPTY_SKY_DATA; + } - MemoryUtil.memPutInt(ptr + offset, bitField); + return out; } - private void collectXStrip(LayerLightEventListener blockLight, LayerLightEventListener skyLight, long ptr, long section, SectionEdge y, SectionEdge z) { - var pos = SectionPos.of(section); - var blockData = blockLight.getDataLayerData(pos); - var skyData = skyLight.getDataLayerData(pos); - if (blockData == null || skyData == null) { - return; + private DataLayer getBlockData(long section) { + var out = ((LightEngineAccessor) level.getLightEngine() + .getLayerListener(LightLayer.BLOCK)).flywheel$storage() + .getDataLayerData(section); + + if (out == null) { + return EMPTY_BLOCK_DATA; } + + return out; + } + + private void collectXStrip(long ptr, long section, SectionEdge y, SectionEdge z) { + var blockData = getBlockData(section); + var skyData = getSkyData(section); for (int x = 0; x < 16; x++) { write(ptr, x, y.relative, z.relative, blockData.get(x, y.pos, z.pos), skyData.get(x, y.pos, z.pos)); } } - private void collectYStrip(LayerLightEventListener blockLight, LayerLightEventListener skyLight, long ptr, long section, SectionEdge x, SectionEdge z) { - var pos = SectionPos.of(section); - var blockData = blockLight.getDataLayerData(pos); - var skyData = skyLight.getDataLayerData(pos); - if (blockData == null || skyData == null) { - return; - } + private void collectYStrip(long ptr, long section, SectionEdge x, SectionEdge z) { + var blockData = getBlockData(section); + var skyData = getSkyData(section); for (int y = 0; y < 16; y++) { write(ptr, x.relative, y, z.relative, blockData.get(x.pos, y, z.pos), skyData.get(x.pos, y, z.pos)); } } - private void collectZStrip(LayerLightEventListener blockLight, LayerLightEventListener skyLight, long ptr, long section, SectionEdge x, SectionEdge y) { - var pos = SectionPos.of(section); - var blockData = blockLight.getDataLayerData(pos); - var skyData = skyLight.getDataLayerData(pos); - if (blockData == null || skyData == null) { - return; - } + private void collectZStrip(long ptr, long section, SectionEdge x, SectionEdge y) { + var blockData = getBlockData(section); + var skyData = getSkyData(section); for (int z = 0; z < 16; z++) { write(ptr, x.relative, y.relative, z, blockData.get(x.pos, y.pos, z), skyData.get(x.pos, y.pos, z)); } } - private void collectYZPlane(LayerLightEventListener blockLight, LayerLightEventListener skyLight, long ptr, long section, SectionEdge x) { - var pos = SectionPos.of(section); - var blockData = blockLight.getDataLayerData(pos); - var skyData = skyLight.getDataLayerData(pos); - if (blockData == null || skyData == null) { - return; - } + private void collectYZPlane(long ptr, long section, SectionEdge x) { + var blockData = getBlockData(section); + var skyData = getSkyData(section); for (int y = 0; y < 16; y++) { for (int z = 0; z < 16; z++) { write(ptr, x.relative, y, z, blockData.get(x.pos, y, z), skyData.get(x.pos, y, z)); @@ -324,13 +320,9 @@ private void collectYZPlane(LayerLightEventListener blockLight, LayerLightEventL } } - private void collectXZPlane(LayerLightEventListener blockLight, LayerLightEventListener skyLight, long ptr, long section, SectionEdge y) { - var pos = SectionPos.of(section); - var blockData = blockLight.getDataLayerData(pos); - var skyData = skyLight.getDataLayerData(pos); - if (blockData == null || skyData == null) { - return; - } + private void collectXZPlane(long ptr, long section, SectionEdge y) { + var blockData = getBlockData(section); + var skyData = getSkyData(section); for (int z = 0; z < 16; z++) { for (int x = 0; x < 16; x++) { write(ptr, x, y.relative, z, blockData.get(x, y.pos, z), skyData.get(x, y.pos, z)); @@ -338,13 +330,9 @@ private void collectXZPlane(LayerLightEventListener blockLight, LayerLightEventL } } - private void collectXYPlane(LayerLightEventListener blockLight, LayerLightEventListener skyLight, long ptr, long section, SectionEdge z) { - var pos = SectionPos.of(section); - var blockData = blockLight.getDataLayerData(pos); - var skyData = skyLight.getDataLayerData(pos); - if (blockData == null || skyData == null) { - return; - } + private void collectXYPlane(long ptr, long section, SectionEdge z) { + var blockData = getBlockData(section); + var skyData = getSkyData(section); for (int y = 0; y < 16; y++) { for (int x = 0; x < 16; x++) { write(ptr, x, y, z.relative, blockData.get(x, y, z.pos), skyData.get(x, y, z.pos)); @@ -352,13 +340,9 @@ private void collectXYPlane(LayerLightEventListener blockLight, LayerLightEventL } } - private void collectCenter(LayerLightEventListener blockLight, LayerLightEventListener skyLight, long ptr, long section) { - var pos = SectionPos.of(section); - var blockData = blockLight.getDataLayerData(pos); - var skyData = skyLight.getDataLayerData(pos); - if (blockData == null || skyData == null) { - return; - } + private void collectCenter(long ptr, long section) { + var blockData = getBlockData(section); + var skyData = getSkyData(section); for (int y = 0; y < 16; y++) { for (int z = 0; z < 16; z++) { for (int x = 0; x < 16; x++) { @@ -368,7 +352,12 @@ private void collectCenter(LayerLightEventListener blockLight, LayerLightEventLi } } - private void collectCorners(LayerLightEventListener blockLight, LayerLightEventListener skyLight, long ptr, long section) { + private void collectCorners(long ptr, long section) { + var lightEngine = level.getLightEngine(); + + var blockLight = lightEngine.getLayerListener(LightLayer.BLOCK); + var skyLight = lightEngine.getLayerListener(LightLayer.SKY); + var blockPos = new BlockPos.MutableBlockPos(); int xMin = SectionPos.sectionToBlockCoord(SectionPos.x(section)); int yMin = SectionPos.sectionToBlockCoord(SectionPos.y(section)); @@ -485,8 +474,10 @@ private enum SectionEdge { public class DebugVisual implements EffectVisual, SimpleDynamicVisual { private final InstanceRecycler boxes; + private final Vec3i renderOrigin; public DebugVisual(VisualizationContext ctx, float partialTick) { + renderOrigin = ctx.renderOrigin(); boxes = new InstanceRecycler<>(() -> ctx.instancerProvider() .instancer(InstanceTypes.TRANSFORMED, HitboxComponent.BOX_MODEL) .createInstance()); @@ -505,15 +496,15 @@ public void beginFrame(Context ctx) { private void setupSectionBoxes() { section2ArenaIndex.keySet() .forEach(l -> { - var x = SectionPos.x(l); - var y = SectionPos.y(l); - var z = SectionPos.z(l); + var x = SectionPos.x(l) * 16 - renderOrigin.getX(); + var y = SectionPos.y(l) * 16 - renderOrigin.getY(); + var z = SectionPos.z(l) * 16 - renderOrigin.getZ(); var instance = boxes.get(); instance.setIdentityTransform() - .scale(16) .translate(x, y, z) + .scale(16) .color(255, 255, 0) .light(LightTexture.FULL_BRIGHT) .setChanged(); @@ -526,6 +517,14 @@ private void setupLutRangeBoxes() { var base1 = first.base(); var size1 = first.size(); + float debug1 = base1 * 16 - renderOrigin.getY(); + + float min2 = Float.POSITIVE_INFINITY; + float max2 = Float.NEGATIVE_INFINITY; + + float min3 = Float.POSITIVE_INFINITY; + float max3 = Float.NEGATIVE_INFINITY; + for (int y = 0; y < size1; y++) { var second = first.getRaw(y); @@ -536,6 +535,16 @@ private void setupLutRangeBoxes() { var base2 = second.base(); var size2 = second.size(); + float y2 = (base1 + y) * 16 - renderOrigin.getY() + 7.5f; + + min2 = Math.min(min2, base2); + max2 = Math.max(max2, base2 + size2); + + float minLocal3 = Float.POSITIVE_INFINITY; + float maxLocal3 = Float.NEGATIVE_INFINITY; + + float debug2 = base2 * 16 - renderOrigin.getX(); + for (int x = 0; x < size2; x++) { var third = second.getRaw(x); @@ -546,55 +555,43 @@ private void setupLutRangeBoxes() { var base3 = third.base(); var size3 = third.size(); - for (int z = 0; z < size3; z++) { - float x1 = base2 * 16; - float y1 = base1 * 16; - float z1 = base3 * 16; + float x2 = (base2 + x) * 16 - renderOrigin.getX() + 7.5f; - float x2 = (base2 + x) * 16 + 7.5f; - float y2 = (base1 + y) * 16 + 7.5f; - float z2 = (base3 + z) * 16 + 7.5f; - boxes.get() - .setIdentityTransform() - .translate(x1, y2, z2) - .scale(size2 * 16, 1, 1) - .color(255, 0, 0) - .light(LightTexture.FULL_BRIGHT) - .setChanged(); + min3 = Math.min(min3, base3); + max3 = Math.max(max3, base3 + size3); - boxes.get() - .setIdentityTransform() - .translate(x2, y1, z2) - .scale(1, size1 * 16, 1) - .color(0, 255, 0) - .light(LightTexture.FULL_BRIGHT) - .setChanged(); + minLocal3 = Math.min(minLocal3, base3); + maxLocal3 = Math.max(maxLocal3, base3 + size3); + + float debug3 = base3 * 16 - renderOrigin.getZ(); + for (int z = 0; z < size3; z++) { boxes.get() .setIdentityTransform() - .translate(x2, y2, z1) + .translate(x2, y2, debug3) .scale(1, 1, size3 * 16) .color(0, 0, 255) .light(LightTexture.FULL_BRIGHT) .setChanged(); - - if (third.getRaw(z) == 0) { - float x3 = (base2 + x) * 16 + 6f; - float y3 = (base1 + y) * 16 + 6f; - float z3 = (base3 + z) * 16 + 6f; - - // Freely representable section that is not filled. - boxes.get() - .setIdentityTransform() - .translate(x3, y3, z3) - .scale(4) - .color(0, 255, 255) - .light(LightTexture.FULL_BRIGHT) - .setChanged(); - } } } + + boxes.get() + .setIdentityTransform() + .translate(debug2, y2, minLocal3 * 16 - renderOrigin.getZ()) + .scale(size2 * 16, 1, (maxLocal3 - minLocal3) * 16) + .color(255, 0, 0) + .light(LightTexture.FULL_BRIGHT) + .setChanged(); } + + boxes.get() + .setIdentityTransform() + .translate(min2 * 16 - renderOrigin.getX(), debug1, min3 * 16 - renderOrigin.getZ()) + .scale((max2 - min2) * 16, size1 * 16, (max3 - min3) * 16) + .color(0, 255, 0) + .light(LightTexture.FULL_BRIGHT) + .setChanged(); } @Override @@ -607,4 +604,17 @@ public void delete() { boxes.delete(); } } + + private static class ConstantDataLayer extends DataLayer { + private final int value; + + private ConstantDataLayer(int value) { + this.value = value; + } + + @Override + public int get(int x, int y, int z) { + return value; + } + } } diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/mixin/light/LightEngineAccessor.java b/common/src/backend/java/dev/engine_room/flywheel/backend/mixin/light/LightEngineAccessor.java new file mode 100644 index 000000000..5a6808216 --- /dev/null +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/mixin/light/LightEngineAccessor.java @@ -0,0 +1,14 @@ +package dev.engine_room.flywheel.backend.mixin.light; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import net.minecraft.world.level.lighting.DataLayerStorageMap; +import net.minecraft.world.level.lighting.LayerLightSectionStorage; +import net.minecraft.world.level.lighting.LightEngine; + +@Mixin(LightEngine.class) +public interface LightEngineAccessor, S extends LayerLightSectionStorage> { + @Accessor("storage") + S flywheel$storage(); +} diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/mixin/light/SkyDataLayerStorageMapAccessor.java b/common/src/backend/java/dev/engine_room/flywheel/backend/mixin/light/SkyDataLayerStorageMapAccessor.java new file mode 100644 index 000000000..b34c0ef31 --- /dev/null +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/mixin/light/SkyDataLayerStorageMapAccessor.java @@ -0,0 +1,15 @@ +package dev.engine_room.flywheel.backend.mixin.light; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap; + +@Mixin(targets = "net.minecraft.world.level.lighting.SkyLightSectionStorage.SkyDataLayerStorageMap") +public interface SkyDataLayerStorageMapAccessor { + @Accessor("currentLowestY") + int flywheel$currentLowestY(); + + @Accessor("topSections") + Long2IntOpenHashMap flywheel$topSections(); +} diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/mixin/light/SkyLightSectionStorageMixin.java b/common/src/backend/java/dev/engine_room/flywheel/backend/mixin/light/SkyLightSectionStorageMixin.java new file mode 100644 index 000000000..8e178e127 --- /dev/null +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/mixin/light/SkyLightSectionStorageMixin.java @@ -0,0 +1,46 @@ +package dev.engine_room.flywheel.backend.mixin.light; + +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; + +import dev.engine_room.flywheel.backend.SkyLightSectionStorageExtension; +import net.minecraft.core.Direction; +import net.minecraft.core.SectionPos; +import net.minecraft.world.level.chunk.DataLayer; +import net.minecraft.world.level.lighting.LayerLightSectionStorage; +import net.minecraft.world.level.lighting.SkyLightSectionStorage; + +@Mixin(SkyLightSectionStorage.class) +public abstract class SkyLightSectionStorageMixin extends LayerLightSectionStorage implements SkyLightSectionStorageExtension { + protected SkyLightSectionStorageMixin() { + super(null, null, null); + } + + @Override + @Nullable + public DataLayer flywheel$skyDataLayer(long section) { + // Logic copied from SkyLightSectionStorage#getLightValue, but here we directly return the DataLayer + + long l = section; + int i = SectionPos.y(l); + SkyDataLayerStorageMapAccessor skyDataLayerStorageMap = (SkyDataLayerStorageMapAccessor) this.visibleSectionData; + int j = skyDataLayerStorageMap.flywheel$topSections() + .get(SectionPos.getZeroNode(l)); + if (j != skyDataLayerStorageMap.flywheel$currentLowestY() && i < j) { + DataLayer dataLayer = this.getDataLayerData(l); + if (dataLayer == null) { + for (; dataLayer == null; dataLayer = this.getDataLayerData(l)) { + if (++i >= j) { + return null; + } + + l = SectionPos.offset(l, Direction.UP); + } + } + + return dataLayer; + } else { + return null; + } + } +} diff --git a/common/src/backend/resources/flywheel.backend.mixins.json b/common/src/backend/resources/flywheel.backend.mixins.json index 2d924bef0..b2aa8632a 100644 --- a/common/src/backend/resources/flywheel.backend.mixins.json +++ b/common/src/backend/resources/flywheel.backend.mixins.json @@ -9,7 +9,10 @@ "GlStateManagerMixin", "LevelRendererAccessor", "OptionsMixin", - "RenderSystemMixin" + "RenderSystemMixin", + "light.LightEngineAccessor", + "light.SkyDataLayerStorageMapAccessor", + "light.SkyLightSectionStorageMixin" ], "injectors": { "defaultRequire": 1