From e1a5db9934079f37b9051c810abbb0714e2effcc Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 21 Jul 2023 00:59:30 +0200 Subject: [PATCH 001/256] Add GFNI, a translucency sort triggering algorithm, the implementation is currently lacking some polish and features but will receive major changes to use an interval tree --- .../sodium/client/model/quad/ModelQuad.java | 25 ++ .../client/model/quad/ModelQuadView.java | 68 ++++ .../quad/properties/ModelQuadFacing.java | 12 + .../client/render/SodiumWorldRenderer.java | 11 +- .../render/chunk/RenderSectionManager.java | 7 +- .../compile/pipeline/BlockRenderContext.java | 5 +- .../chunk/compile/pipeline/BlockRenderer.java | 13 + .../chunk/compile/pipeline/FluidRenderer.java | 29 +- .../render/chunk/gfni/AccumulationGroup.java | 47 +++ .../client/render/chunk/gfni/Bucket.java | 206 +++++++++++ .../sodium/client/render/chunk/gfni/GFNI.java | 112 ++++++ .../client/render/chunk/gfni/Group.java | 63 ++++ .../render/chunk/gfni/GroupBuilder.java | 56 +++ .../client/render/chunk/gfni/NormalList.java | 321 ++++++++++++++++++ .../chunk/tasks/ChunkRenderRebuildTask.java | 12 +- .../sodium/client/util/ModelQuadUtil.java | 40 --- .../mixin/core/pipeline/MixinBakedQuad.java | 29 +- 17 files changed, 1000 insertions(+), 56 deletions(-) create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AccumulationGroup.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Bucket.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuad.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuad.java index 0f865ada3e..0c1261a4ff 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuad.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuad.java @@ -15,6 +15,9 @@ public class ModelQuad implements ModelQuadViewMutable { private Sprite sprite; private int colorIdx; private int normal; + private float normX; + private float normY; + private float normZ; @Override public void setX(int idx, float x) { @@ -120,4 +123,26 @@ public Sprite getSprite() { public int getNormal() { return this.normal; } + + @Override + public float getNormX() { + return this.normX; + } + + @Override + public float getNormY() { + return this.normY; + } + + @Override + public float getNormZ() { + return this.normZ; + } + + @Override + public void setAccurateNormal(float x, float y, float z) { + this.normX = x; + this.normY = y; + this.normZ = z; + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java index 623cdb8395..a15506be7c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java @@ -57,6 +57,74 @@ public interface ModelQuadView { */ int getNormal(); + /** + * @return The x coordinate of the unit normal vector + */ + float getNormX(); + + /** + * @return The y coordinate of the unit normal vector + */ + float getNormY(); + + /** + * @return The z coordinate of the unit normal vector + */ + float getNormZ(); + + /** + * Sets an accurate normal vector for this quad. This is used for GFNI. + * + * @param x The normal's x component + * @param y The normal's y component + * @param z The normal's z component + */ + void setAccurateNormal(float x, float y, float z); + + /** + * Calculates the normal vector for this quad using the cross product of the + * vertices. Ensures the normal vector returned by the getNorm methods is up to + * date (and a unit vector). + */ + default void calculateAccurateNormal() { + final float x0 = getX(0); + final float y0 = getY(0); + final float z0 = getZ(0); + + final float x1 = getX(1); + final float y1 = getY(1); + final float z1 = getZ(1); + + final float x2 = getX(2); + final float y2 = getY(2); + final float z2 = getZ(2); + + final float x3 = getX(3); + final float y3 = getY(3); + final float z3 = getZ(3); + + final float dx0 = x2 - x0; + final float dy0 = y2 - y0; + final float dz0 = z2 - z0; + final float dx1 = x3 - x1; + final float dy1 = y3 - y1; + final float dz1 = z3 - z1; + + float normX = dy0 * dz1 - dz0 * dy1; + float normY = dz0 * dx1 - dx0 * dz1; + float normZ = dx0 * dy1 - dy0 * dx1; + + float l = (float) Math.sqrt(normX * normX + normY * normY + normZ * normZ); + + if (l != 0) { + normX /= l; + normY /= l; + normZ /= l; + } + + this.setAccurateNormal(normX, normY, normZ); + } + default boolean hasColor() { return this.getColorIndex() != -1; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java index 092cb3bc84..463bd9d48a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java @@ -38,4 +38,16 @@ public ModelQuadFacing getOpposite() { default -> UNASSIGNED; }; } + + public Direction toDirection() { + return switch (this) { + case UP -> Direction.UP; + case DOWN -> Direction.DOWN; + case EAST -> Direction.EAST; + case WEST -> Direction.WEST; + case SOUTH -> Direction.SOUTH; + case NORTH -> Direction.NORTH; + default -> Direction.UP; + }; + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index ca196f4716..e0f53a5b1a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -11,6 +11,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.ChunkTracker; import me.jellysquid.mods.sodium.client.render.chunk.RenderSectionManager; import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderData; +import me.jellysquid.mods.sodium.client.render.chunk.gfni.GFNI; import me.jellysquid.mods.sodium.client.util.NativeBuffer; import me.jellysquid.mods.sodium.client.util.frustum.Frustum; import me.jellysquid.mods.sodium.client.world.WorldRendererExtended; @@ -50,6 +51,7 @@ public class SodiumWorldRenderer { private RenderSectionManager renderSectionManager; private ChunkTracker chunkTracker; + private GFNI gfni; /** * @return The SodiumWorldRenderer based on the current dimension @@ -169,9 +171,13 @@ public void updateChunks(Camera camera, Frustum frustum, @Deprecated(forRemoval float yaw = camera.getYaw(); float fogDistance = RenderSystem.getShaderFogEnd(); - boolean dirty = pos.x != this.lastCameraX || pos.y != this.lastCameraY || pos.z != this.lastCameraZ || + boolean cameraLocationChanged = pos.x != this.lastCameraX || pos.y != this.lastCameraY || pos.z != this.lastCameraZ; + boolean dirty = cameraLocationChanged || pitch != this.lastCameraPitch || yaw != this.lastCameraYaw || fogDistance != this.lastFogDistance; + if (cameraLocationChanged) { + gfni.processMovement(lastCameraX, lastCameraY, lastCameraZ, pos.x, pos.y, pos.z); + } if (dirty) { this.renderSectionManager.markGraphDirty(); } @@ -235,7 +241,8 @@ private void initRenderer(CommandList commandList) { this.renderDistance = this.client.options.getClampedViewDistance(); - this.renderSectionManager = new RenderSectionManager(this, this.world, this.renderDistance, commandList); + this.gfni = new GFNI(); + this.renderSectionManager = new RenderSectionManager(this, this.world, this.gfni, this.renderDistance, commandList); this.renderSectionManager.reloadChunks(this.chunkTracker); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index de9e816b7b..a185091843 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -19,6 +19,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildResult; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuilder; import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderData; +import me.jellysquid.mods.sodium.client.render.chunk.gfni.GFNI; import me.jellysquid.mods.sodium.client.render.chunk.graph.ChunkGraphInfo; import me.jellysquid.mods.sodium.client.render.chunk.graph.ChunkGraphIterationQueue; import me.jellysquid.mods.sodium.client.render.chunk.region.RenderRegionManager; @@ -82,6 +83,7 @@ public class RenderSectionManager { private final SodiumWorldRenderer worldRenderer; private final ClientWorld world; + private final GFNI gfni; private final int renderDistance; @@ -104,11 +106,12 @@ public class RenderSectionManager { private ChunkRenderList chunkRenderList; - public RenderSectionManager(SodiumWorldRenderer worldRenderer, ClientWorld world, int renderDistance, CommandList commandList) { + public RenderSectionManager(SodiumWorldRenderer worldRenderer, ClientWorld world, GFNI gfni, int renderDistance, CommandList commandList) { this.chunkRenderer = new RegionChunkRenderer(RenderDevice.INSTANCE, ChunkMeshFormats.COMPACT); this.worldRenderer = worldRenderer; this.world = world; + this.gfni = gfni; this.builder = new ChunkBuilder(ChunkMeshFormats.COMPACT); this.builder.init(world); @@ -432,7 +435,7 @@ public ChunkRenderBuildTask createRebuildTask(RenderSection render) { return new ChunkRenderEmptyBuildTask(render, frame); } - return new ChunkRenderRebuildTask(render, context, frame); + return new ChunkRenderRebuildTask(render, context, this.gfni, frame); } public void markGraphDirty() { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderContext.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderContext.java index 3554a98405..7f8c8b36f3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderContext.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderContext.java @@ -1,5 +1,6 @@ package me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline; +import me.jellysquid.mods.sodium.client.render.chunk.gfni.GroupBuilder; import me.jellysquid.mods.sodium.client.world.WorldSlice; import net.minecraft.block.BlockState; import net.minecraft.client.render.model.BakedModel; @@ -9,6 +10,7 @@ public class BlockRenderContext { private final WorldSlice world; + public final GroupBuilder groupBuilder; private final BlockPos.Mutable pos = new BlockPos.Mutable(); @@ -20,8 +22,9 @@ public class BlockRenderContext { private long seed; - public BlockRenderContext(WorldSlice world) { + public BlockRenderContext(WorldSlice world, GroupBuilder groupBuilder) { this.world = world; + this.groupBuilder = groupBuilder; } public void update(BlockPos pos, BlockPos origin, BlockState state, BakedModel model, long seed) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java index a6b969e80b..0f51c9aa55 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java @@ -143,6 +143,9 @@ private void writeGeometry(BlockRenderContext ctx, ModelQuadFacing normalFace = quad.getNormalFace(); + // if translucent, add this face to the GFNI group builder + boolean isTranslucent = material == DefaultMaterials.TRANSLUCENT; + for (int dstIndex = 0; dstIndex < 4; dstIndex++) { int srcIndex = orientation.getVertexIndex(dstIndex); @@ -151,6 +154,16 @@ private void writeGeometry(BlockRenderContext ctx, out.y = ctx.origin().y() + quad.getY(srcIndex) + (float) offset.getY(); out.z = ctx.origin().z() + quad.getZ(srcIndex) + (float) offset.getZ(); + if (isTranslucent && dstIndex == 0) { + if (normalFace == ModelQuadFacing.UNASSIGNED) { + ctx.groupBuilder.addUnalignedFace( + quad.getNormX(), quad.getNormY(), quad.getNormZ(), + out.x, out.y, out.z); + } else { + ctx.groupBuilder.addAlignedFace(normalFace, out.x, out.y, out.z); + } + } + out.color = ColorABGR.withAlpha(colors != null ? colors[srcIndex] : 0xFFFFFFFF, light.br[srcIndex]); out.u = quad.getTexU(srcIndex); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java index 095ef6f718..22818e0528 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java @@ -15,6 +15,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildBuffers; import me.jellysquid.mods.sodium.client.render.chunk.compile.buffers.ChunkModelBuilder; import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderBounds; +import me.jellysquid.mods.sodium.client.render.chunk.gfni.GroupBuilder; import me.jellysquid.mods.sodium.client.render.chunk.terrain.material.DefaultMaterials; import me.jellysquid.mods.sodium.client.render.chunk.terrain.material.Material; import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexEncoder; @@ -102,7 +103,7 @@ private boolean isSideExposed(BlockRenderView world, int x, int y, int z, Direct return true; } - public void render(WorldSlice world, FluidState fluidState, BlockPos pos, BlockPos offset, ChunkBuildBuffers buffers, ChunkRenderBounds.Builder bounds) { + public void render(WorldSlice world, FluidState fluidState, BlockPos pos, BlockPos offset, GroupBuilder groupBuilder, ChunkBuildBuffers buffers, ChunkRenderBounds.Builder bounds) { var material = DefaultMaterials.forFluidState(fluidState); var meshBuilder = buffers.get(material); @@ -220,10 +221,10 @@ public void render(WorldSlice world, FluidState fluidState, BlockPos pos, BlockP setVertex(quad, 3, 1.0F, h4, 0.0f, u4, v4); this.updateQuad(quad, world, pos, lighter, Direction.UP, 1.0F, colorProvider, fluidState); - this.writeQuad(meshBuilder, bounds, material, offset, quad, facing, false); + this.writeQuad(meshBuilder, groupBuilder, bounds, material, offset, quad, facing, false); if (fluidState.canFlowTo(world, this.scratchPos.set(posX, posY + 1, posZ))) { - this.writeQuad(meshBuilder, bounds, material, offset, quad, + this.writeQuad(meshBuilder, groupBuilder, bounds, material, offset, quad, ModelQuadFacing.DOWN, true); } @@ -245,7 +246,7 @@ public void render(WorldSlice world, FluidState fluidState, BlockPos pos, BlockP setVertex(quad, 3, 1.0F, yOffset, 1.0F, maxU, maxV); this.updateQuad(quad, world, pos, lighter, Direction.DOWN, 1.0F, colorProvider, fluidState); - this.writeQuad(meshBuilder, bounds, material, offset, quad, ModelQuadFacing.DOWN, false); + this.writeQuad(meshBuilder, groupBuilder, bounds, material, offset, quad, ModelQuadFacing.DOWN, false); } @@ -349,10 +350,10 @@ public void render(WorldSlice world, FluidState fluidState, BlockPos pos, BlockP ModelQuadFacing facing = ModelQuadFacing.fromDirection(dir); this.updateQuad(quad, world, pos, lighter, dir, br, colorProvider, fluidState); - this.writeQuad(meshBuilder, bounds, material, offset, quad, facing, false); + this.writeQuad(meshBuilder, groupBuilder, bounds, material, offset, quad, facing, false); if (!isOverlay) { - this.writeQuad(meshBuilder, bounds, material, offset, quad, facing.getOpposite(), true); + this.writeQuad(meshBuilder, groupBuilder, bounds, material, offset, quad, facing.getOpposite(), true); } } @@ -394,16 +395,30 @@ private void updateQuad(ModelQuadView quad, WorldSlice world, BlockPos pos, Ligh } } - private void writeQuad(ChunkModelBuilder builder, ChunkRenderBounds.Builder bounds, Material material, BlockPos offset, ModelQuadView quad, + private void writeQuad(ChunkModelBuilder builder, GroupBuilder groupBuilder, ChunkRenderBounds.Builder bounds, Material material, BlockPos offset, ModelQuadView quad, ModelQuadFacing facing, boolean flip) { var vertices = this.vertices; + // if translucent, add this face to the GFNI group builder + boolean isTranslucent = material == DefaultMaterials.TRANSLUCENT; + for (int i = 0; i < 4; i++) { var out = vertices[flip ? 3 - i : i]; out.x = offset.getX() + quad.getX(i); out.y = offset.getY() + quad.getY(i); out.z = offset.getZ() + quad.getZ(i); + if (isTranslucent && i == 0) { + if (facing == ModelQuadFacing.UNASSIGNED) { + quad.calculateAccurateNormal(); + groupBuilder.addUnalignedFace( + quad.getNormX(), quad.getNormY(), quad.getNormZ(), + out.x, out.y, out.z); + } else { + groupBuilder.addAlignedFace(facing, out.x, out.y, out.z); + } + } + bounds.add(out.x, out.y, out.z, facing); out.color = this.quadColors[i]; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AccumulationGroup.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AccumulationGroup.java new file mode 100644 index 0000000000..7898a038e8 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AccumulationGroup.java @@ -0,0 +1,47 @@ +package me.jellysquid.mods.sodium.client.render.chunk.gfni; + +import org.joml.Vector3fc; + +import it.unimi.dsi.fastutil.doubles.DoubleOpenHashSet; +import net.minecraft.util.math.ChunkSectionPos; + +public class AccumulationGroup { + final DoubleOpenHashSet relativeDistances = new DoubleOpenHashSet(16); + final Vector3fc normal; + final ChunkSectionPos sectionPos; + private double minDistance = Double.POSITIVE_INFINITY; + private double maxDistance = Double.NEGATIVE_INFINITY; + long relDistanceHash = 0; + + public AccumulationGroup(ChunkSectionPos sectionPos, Vector3fc normal) { + this.sectionPos = sectionPos; + this.normal = normal; + } + + void add(float vertexX, float vertexY, float vertexZ) { + add(this.normal.dot(vertexX, vertexY, vertexZ)); + } + + void add(double distance) { + // add the distance to the set and update the min/max distances if necessary + if (this.relativeDistances.add(distance)) { + this.minDistance = Math.min(this.minDistance, distance); + this.maxDistance = Math.max(this.maxDistance, distance); + + long distanceBits = Double.doubleToLongBits(distance); + this.relDistanceHash ^= distanceBits; + } + } + + boolean isRelevant() { + return relativeDistances.size() > 1; + } + + double getMinDistance(double baseDistance) { + return this.minDistance + baseDistance; + } + + double getMaxDistance(double baseDistance) { + return this.maxDistance + baseDistance; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Bucket.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Bucket.java new file mode 100644 index 0000000000..b8b953ccbb --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Bucket.java @@ -0,0 +1,206 @@ +package me.jellysquid.mods.sodium.client.render.chunk.gfni; + +import it.unimi.dsi.fastutil.doubles.Double2ReferenceAVLTreeMap; +import it.unimi.dsi.fastutil.objects.ReferenceArraySet; + +/** + * A bucket contains all groups of a normal list that fall within a certain + * distance range. The groups are non-overlapping but some sections may have two + * groups to deal with sections that cross bucket borders. The bucket size is + * chosen such that no section's faces can cover more than two buckets, even if + * the normal is diagonal to the axes. + * + * TODO: a more sophisticated structure instead of subbuckets that can + * efficiently range query overlapping groups. Traditional segment trees use + * integer segments so they aren't quite the right fit here. + */ +public class Bucket { + private static final int SUBBUCKETS = 4; + + /** + * The backing collection storing the groups in this bucket. An array of sets is + * used to cut down on the number of groups that need to be iterated in range + * queries. + */ + @SuppressWarnings("unchecked") + final ReferenceArraySet[] groups = new ReferenceArraySet[SUBBUCKETS]; + final Double2ReferenceAVLTreeMap allGroups = new Double2ReferenceAVLTreeMap<>(); + + /** + * The minimum and maximum distances of all the groups in this bucket. + */ + private double minDistance; + private double maxDistance; + + /** + * The starting distance of this bucket. There don't need to be face planes + * filling the whole bucket. + * + * NOTE: groups may protrude outside the bucket and the min/max distances + * reflect that. However, the normal list makes sure only groups that overlap + * with this bucket are added. + */ + final double startDistance; + final double endDistance; + + Bucket(double startDistance, double bucketLength) { + this.startDistance = startDistance; + this.endDistance = startDistance + bucketLength; + } + + private boolean isOutsideContentRange(double start, double end) { + return start >= this.maxDistance || end <= this.minDistance; + } + + private static int constrainIndex(int index) { + return Math.max(0, Math.min(index, SUBBUCKETS - 1)); + } + + private int getSubbucketStart(double start) { + return constrainIndex((int) Math.floor((start - this.startDistance) / SUBBUCKETS)); + } + + private int getSubbucketEnd(double end) { + return getSubbucketStart(end) + 1; + } + + double getStartBoundary() { + if (isEmpty()) { + return this.startDistance; + } + return Math.max(this.startDistance, this.minDistance); + } + + double getEndBoundary() { + if (isEmpty()) { + return this.endDistance; + } + return Math.min(this.endDistance, this.maxDistance); + } + + void triggerRange(GFNI gfni, double start, double end) { + // stop if the query range is outside the bucket + // (start of the query range is inclusive, end is exclusive) (?) + if (isOutsideContentRange(start, end)) { + return; + } + + // iterate subbuckets that fall within the range or all of them if the whole + // bucket is within the range + // TODO: even better heuristic, it's more efficient to iterate all groups if the + // the range is just _most_ of the whole bucket + int subbucketStart = getSubbucketStart(start); + int subbucketEnd = getSubbucketEnd(end); + if (subbucketEnd - subbucketStart == SUBBUCKETS) { + Group previousGroup = null; + for (Group group : this.allGroups.values()) { + // deduplicate groups since they're each entered twice + if (group != previousGroup) { + group.triggerRange(gfni, start, end); + } + previousGroup = group; + } + } else { + for (int i = subbucketStart; i < subbucketEnd; i++) { + ReferenceArraySet subbucket = this.groups[i]; + if (subbucket != null) { + for (Group group : subbucket) { + group.triggerRange(gfni, start, end); + } + } + } + } + } + + void addNewGroup(Group group) { + for (int i = getSubbucketStart(group.minDistance), + endIndex = getSubbucketEnd(group.maxDistance); i < endIndex; i++) { + ReferenceArraySet subbucket = this.groups[i]; + if (subbucket == null) { + subbucket = new ReferenceArraySet<>(); + this.groups[i] = subbucket; + } + subbucket.add(group); + } + + // if this is the first group being added, set the min/max distances directly + if (this.allGroups.isEmpty()) { + this.minDistance = group.minDistance; + this.maxDistance = group.maxDistance; + } else { + this.minDistance = Math.min(this.minDistance, group.minDistance); + this.maxDistance = Math.max(this.maxDistance, group.maxDistance); + } + this.allGroups.put(group.minDistance, group); + this.allGroups.put(group.maxDistance, group); + + } + + void removeGroup(Group group) { + for (int i = getSubbucketStart(group.minDistance), + endIndex = getSubbucketEnd(group.maxDistance); i < endIndex; i++) { + ReferenceArraySet subbucket = this.groups[i]; + if (subbucket != null) { + subbucket.remove(group); + + if (subbucket.isEmpty()) { + this.groups[i] = null; + } + } + } + + this.allGroups.remove(group.minDistance); + this.allGroups.remove(group.maxDistance); + if (!isEmpty()) { + this.minDistance = this.allGroups.firstDoubleKey(); + this.maxDistance = this.allGroups.lastDoubleKey(); + } + } + + void updateGroupRange(Group existingGroup, AccumulationGroup accGroup, + double accGroupMinDistance, double accGroupMaxDistance) { + // iterate the relevant subbuckets and add or remove the group from them + // the existing group contains the old range, the accGroup contains the new + int existingStart = getSubbucketStart(existingGroup.minDistance); + int existingEnd = getSubbucketEnd(existingGroup.maxDistance); + int newStart = getSubbucketStart(accGroupMinDistance); + int newEnd = getSubbucketEnd(accGroupMaxDistance); + for (int i = Math.min(existingStart, newStart), endIndex = Math.max(existingEnd, newEnd); i < endIndex; i++) { + ReferenceArraySet subbucket = this.groups[i]; + boolean inExisting = i >= existingStart && i < existingEnd; + boolean inNew = i >= newStart && i < newEnd; + + if (inNew && !inExisting) { + if (subbucket == null) { + subbucket = new ReferenceArraySet<>(); + this.groups[i] = subbucket; + } + subbucket.add(existingGroup); + } else if (inExisting && !inNew) { + if (subbucket == null) { + int a = 4; // TODO: remove + } + subbucket.remove(existingGroup); + + if (subbucket.isEmpty()) { + this.groups[i] = null; + } + } + } + + if (accGroupMinDistance != existingGroup.minDistance) { + this.allGroups.remove(existingGroup.minDistance); + this.allGroups.put(accGroupMinDistance, existingGroup); + this.minDistance = this.allGroups.firstDoubleKey(); + } + if (accGroupMaxDistance != existingGroup.maxDistance) { + this.allGroups.remove(existingGroup.maxDistance); + this.allGroups.put(accGroupMaxDistance, existingGroup); + this.maxDistance = this.allGroups.lastDoubleKey(); + } + } + + boolean isEmpty() { + return this.allGroups.isEmpty(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java new file mode 100644 index 0000000000..8237368ea9 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java @@ -0,0 +1,112 @@ +package me.jellysquid.mods.sodium.client.render.chunk.gfni; + +import org.joml.Vector3fc; + +import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; +import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; +import net.minecraft.util.math.ChunkSectionPos; + +/** + * Global Face Normal Indexing as described in + * https://hackmd.io/@douira100/sodium-sl-gfni + * + * Distances are stored as doubles and normals are stored as float vectors. + * + * TODO: make Group and Bucket relative to use floats instead of doubles + * + * TODO: synchronization is used for integrating group builders submitted from + * chunk build threads. It is assumed that integrating a group builder is fast + * and thus synchronization is not a big problem. However, if it is, it might be + * better to put the group builder in the ChunkBuildResult and have the main + * thread integrate it. The distadvantage is that the main thread would be busy + * with group integration while actually the chunk build thread could be doing + * it itself. If fine grained synchronization is needed, threads could also work + * on integrating individual normal lists in parallel. However, since normal + * lists are created (and possibly deleted) on demand, this would require a more + * complex synchronization scheme. + * + * TODO: destory functionality similar to RenderSectionManger's destroy method? + * + * TODO: handle unloading of sections, there are no updates when the section + * just goes away. this needs to be hooked into and handled like an update to an + * irrelevant new group. + * + * TODO: for some reason in the first time using a void world, blocks added with + * setblock are invisible. + * + * TODO: does teleporting and switching dimensions work? + */ +public class GFNI { + /** + * A map of all the normal lists, indexed by their normal. + */ + Object2ReferenceOpenHashMap normalLists = new Object2ReferenceOpenHashMap<>(50); + + ReferenceOpenHashSet triggeredSections = new ReferenceOpenHashSet<>(50); + + public void processMovement(double lastCameraX, double lastCameraY, double lastCameraZ, + double cameraX, double cameraY, double cameraZ) { + triggeredSections.clear(); + + try { + for (NormalList normalList : this.normalLists.values()) { + normalList.processMovement(this, lastCameraX, lastCameraY, lastCameraZ, cameraX, cameraY, cameraZ); + } + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + + // TODO: do something with the triggered sections + // for now just log the amount + int triggerCount = this.triggeredSections.size(); + if (triggerCount > 0) { + System.out.println("Triggered " + triggerCount + " sections"); + for (ChunkSectionPos section : this.triggeredSections) { + System.out.println(section.getX() + " " + section.getY() + " " + section.getZ()); + } + } + } + + void triggerSection(ChunkSectionPos section) { + this.triggeredSections.add(section); + } + + // TODO: synchronized because it's expected to be fast, see class comment + public synchronized void integrateGroupBuilder(GroupBuilder builder) { + try { + for (AccumulationGroup accGroup : builder.alignedFaceDistances) { + if (accGroup != null) { + updateGroup(accGroup); + } + } + for (AccumulationGroup accGroup : builder.unalignedDistances.values()) { + updateGroup(accGroup); + } + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + + private void updateGroup(AccumulationGroup accGroup) { + var normal = accGroup.normal; + NormalList normalList = this.normalLists.get(normal); + if (normalList == null) { + // skip even creating a normal list if the group is irrelevant + if (accGroup.isRelevant()) { + normalList = new NormalList(normal); + this.normalLists.put(normal, normalList); + normalList.updateGroup(accGroup); + } + } else { + // irrelevant groups do need to be updated on existing normal lists because + // existing data has to be removed + normalList.updateGroup(accGroup); + + if (normalList.isEmpty()) { + this.normalLists.remove(normal); + } + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java new file mode 100644 index 0000000000..af74b3df47 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java @@ -0,0 +1,63 @@ +package me.jellysquid.mods.sodium.client.render.chunk.gfni; + +import it.unimi.dsi.fastutil.doubles.DoubleAVLTreeSet; +import net.minecraft.util.math.ChunkSectionPos; + +/** + * A group represents a set of face planes of the same normal within a bucket. A + * group keeps a tree of its face plane distances to determine if it needs to be + * triggered. + */ +public class Group { + /** + * The section this group is for + */ + ChunkSectionPos sectionPos; + + /** + * A tree of all the face plane distances in this group, relative to the + * enclosing bucket's startDistance. + */ + DoubleAVLTreeSet facePlaneDistances = new DoubleAVLTreeSet(); + + /** + * A hash of all the face plane distances in this group (before adding the base + * distance) + */ + long relDistanceHash = 0; + + /** + * The minimum and maximum distances of all the faces planes in this + * group. + */ + double minDistance; + double maxDistance; + + Group(AccumulationGroup accGroup, double accGroupMinDistance, double accGroupMaxDistance, double baseDistance) { + replaceWith(accGroup, accGroupMinDistance, accGroupMaxDistance, baseDistance); + } + + void replaceWith(AccumulationGroup accGroup, + double accGroupMinDistance, double accGroupMaxDistance, + double baseDistance) { + this.sectionPos = accGroup.sectionPos; + this.minDistance = accGroupMinDistance; + this.maxDistance = accGroupMaxDistance; + this.relDistanceHash = accGroup.relDistanceHash; + + // clear the existing tree and add all the face plane distances but add the base + // distance to each relative distance + this.facePlaneDistances.clear(); + for (double distance : accGroup.relativeDistances) { + this.facePlaneDistances.add(distance + baseDistance); + } + } + + void triggerRange(GFNI gfni, double start, double end) { + // trigger self on the section if the query range overlaps with the group + if (start < this.maxDistance && end > this.minDistance + && !this.facePlaneDistances.subSet(start, end).isEmpty()) { + gfni.triggerSection(this.sectionPos); + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java new file mode 100644 index 0000000000..0aa9879a07 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java @@ -0,0 +1,56 @@ +package me.jellysquid.mods.sodium.client.render.chunk.gfni; + +import org.joml.Vector3f; +import org.joml.Vector3fc; + +import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import net.minecraft.util.math.ChunkSectionPos; + +public class GroupBuilder { + public static final Vector3fc[] ALIGNED_NORMALS = new Vector3fc[ModelQuadFacing.DIRECTIONS.length]; + + static { + for (int i = 0; i < ModelQuadFacing.DIRECTIONS.length; i++) { + ALIGNED_NORMALS[i] = new Vector3f(ModelQuadFacing.DIRECTIONS[i].toDirection().getUnitVector()); + } + } + + AccumulationGroup[] alignedFaceDistances = new AccumulationGroup[ModelQuadFacing.DIRECTIONS.length]; + Object2ReferenceOpenHashMap unalignedDistances = new Object2ReferenceOpenHashMap<>( + 4); + ChunkSectionPos sectionPos; + + public GroupBuilder(ChunkSectionPos sectionPos) { + this.sectionPos = sectionPos; + } + + public void addAlignedFace(ModelQuadFacing facing, float vertexX, float vertexY, float vertexZ) { + if (facing == ModelQuadFacing.UNASSIGNED) { + throw new IllegalArgumentException("Cannot add an unaligned face with addAlignedFace()"); + } + + int index = facing.ordinal(); + AccumulationGroup distances = this.alignedFaceDistances[index]; + + if (distances == null) { + distances = new AccumulationGroup(sectionPos, ALIGNED_NORMALS[index]); + this.alignedFaceDistances[index] = distances; + } + + distances.add(vertexX, vertexY, vertexZ); + } + + public void addUnalignedFace(float normalX, float normalY, float normalZ, + float vertexX, float vertexY, float vertexZ) { + Vector3fc normal = new Vector3f(normalX, normalY, normalZ); + AccumulationGroup distances = this.unalignedDistances.get(normal); + + if (distances == null) { + distances = new AccumulationGroup(sectionPos, normal); + this.unalignedDistances.put(normal, distances); + } + + distances.add(vertexX, vertexY, vertexZ); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java new file mode 100644 index 0000000000..d7fbc69327 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java @@ -0,0 +1,321 @@ +package me.jellysquid.mods.sodium.client.render.chunk.gfni; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.joml.Vector3d; +import org.joml.Vector3dc; +import org.joml.Vector3fc; + +import it.unimi.dsi.fastutil.doubles.Double2ReferenceAVLTreeMap; +import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; +import it.unimi.dsi.fastutil.objects.ReferenceArraySet; +import net.minecraft.util.math.ChunkSectionPos; + +/** + * A normal list contains all the face planes that have the same normal. + * + * TODO: instead of buckets, use an interval tree + * https://github.com/lodborg/interval-tree for each normal list with the groups + * in it. Since the interval tree is just a set of intervals, use a multi hash + * map to map the intervals to the groups. There can be multiple groups per + * interval. + */ +public class NormalList { + /** + * The normal of this normal list. + */ + final Vector3dc normal; + + /** + * The bucket size in terms of normal-relative distance, chosen such that no + * section can span more than two buckets. This is effectively length of a + * 16*16*16 chunk section in terms of normal-relative distance. + */ + final float bucketLength; + + /** + * map of bucket ranges to buckets, each bucket appears twice in this map. Since + * the bucket ranges are disjoint, this allows us to find the bucket for a given + * range even if the range is fully contained within a bucket. There can only + * ever be a single bucket at any key. + */ + final Double2ReferenceAVLTreeMap bucketRanges = new Double2ReferenceAVLTreeMap<>(); + + /** + * A separate hashmap of groups to enable fast retrieval of existing groups. + */ + final Object2ReferenceOpenHashMap groups = new Object2ReferenceOpenHashMap<>(); + + /** + * Constructs a new normal list with the given unit normal vector. + * + * @param normal The unit normal vector + */ + NormalList(Vector3fc normal) { + this.normal = new Vector3d(normal); + this.bucketLength = Math.abs(normal.x() * 16) + Math.abs(normal.y() * 16) + Math.abs(normal.z() * 16); + } + + /** + * Picks a bucket size for the given normal. The size must be chosen such that + * no section (16x16x16 cube) can span more than two buckets with respect to the + * normal. For axis-aligned normals, the size is 16. For diagonal normals with + * one axis-aligned component, the size is sqrt(16^2 + 16^2) ≈ 22.628 (rounded + * up). For fully diagonal normals the size is sqrt(16^2 + 16^2 + 16^2) ≈ 27.713 + * (rounded up). + * + * @param normal The unit normal vector + * @return The bucket size + */ + private static float getBucketSize(Vector3fc normal) { + int zeroComponents = 0; + if (normal.x() == 0) { + zeroComponents++; + } + if (normal.y() == 0) { + zeroComponents++; + } + if (normal.z() == 0) { + zeroComponents++; + } + if (zeroComponents == 3) { + throw new IllegalArgumentException("normal must not be zero"); + } else if (zeroComponents == 2) { + return 16f; + } else if (zeroComponents == 1) { + return 22.628f; + } else { + return 27.713f; + } + } + + /** + * Finds the 0-2 buckets that fall within the given range. However the range may + * be smaller than a bucket, in which case the enclosing bucket is returned. + * + * @param start The start of the range + * @param end The end of the range + * @return The buckets that fall within the range + */ + private Collection queryBuckets(double start, double end) { + if (start > end) { + throw new IllegalArgumentException("start must be less than or equal to end"); + } + + // do a simple range query to see which buckets fall within the range + // if there are any, simply return them as there can't be any buckets enclosing + // the range if there are bucket boundaries within the range + var innerBuckets = this.bucketRanges.subMap(start, end); + if (!innerBuckets.isEmpty()) { + // each bucket can appear twice in the map, so remove duplicates + if (innerBuckets.size() == 1) { + return innerBuckets.values(); + } else { + Bucket first = innerBuckets.get(innerBuckets.firstDoubleKey()); + Bucket last = innerBuckets.get(innerBuckets.lastDoubleKey()); + if (first == last) { + return Collections.singleton(first); + } else { + return List.of(first, last); + } + } + } + + // in this case the range is enclosed by a single bucket, or none + // there is an enclosing bucket if the two next bucket boundaries are the same + // bucket + // otherwise there is no enclosing bucket + var headMap = this.bucketRanges.headMap(start); + if (headMap.isEmpty()) { + return Collections.emptyList(); + } + var tailMap = this.bucketRanges.tailMap(end); + if (tailMap.isEmpty()) { + return Collections.emptyList(); + } + + var headEntry = headMap.get(headMap.lastDoubleKey()); + var tailEntry = tailMap.get(tailMap.firstDoubleKey()); + if (headEntry == tailEntry) { + return Collections.singleton(headEntry); + } else { + return Collections.emptyList(); + } + } + + void processMovement(GFNI gfni, double lastCameraX, double lastCameraY, double lastCameraZ, + double cameraX, double cameraY, double cameraZ) { + // calculate the distance range of the movement with respect to the normal + double start = this.normal.dot(lastCameraX, lastCameraY, lastCameraZ); + double end = this.normal.dot(cameraX, cameraY, cameraZ); + // double start = -100000; + // double end = 100000; + + // stop if the movement is reverse with regards to the normal + // this means it's moving against the normal + if (start > end) { + return; + } + + // range query for triggering the 0-2 buckets that fall within the range + var queryBuckets = queryBuckets(start, end); + if (!queryBuckets.isEmpty()) { + for (Bucket bucket : queryBuckets) { + bucket.triggerRange(gfni, start, end); + } + } + } + + private Bucket createBucketAt(double startDistance) { + return new Bucket(startDistance, this.bucketLength); + } + + void updateGroup(AccumulationGroup accGroup) { + // find the existing buckets that the group could be in + ChunkSectionPos pos = accGroup.sectionPos; + double baseDistance = accGroup.normal.dot(pos.getMinX(), pos.getMinY(), pos.getMinZ()); + double accGroupMinDistance = accGroup.getMinDistance(baseDistance); + double accGroupMaxDistance = accGroup.getMaxDistance(baseDistance); + + Group group = this.groups.get(pos); + boolean groupIsNew = false; + if (group == null) { + // stop on new irrelevant groups + if (!accGroup.isRelevant()) { + return; + } + + // make a new group for this accumulation group + group = new Group(accGroup, accGroupMinDistance, accGroupMaxDistance, baseDistance); + groupIsNew = true; + this.groups.put(pos, group); + } else { + // this is just a heuristic, but it assumes that if the size, bounds and + // hash are equal, they are most likely the same. We also know that the existing + // and new data is for the same section position since the group was retrieved + // from the map for the right position. + // TODO: how common are collisions and are they bad? + // If they are common, use second hash + if (group.facePlaneDistances.size() == accGroup.relativeDistances.size() + && group.minDistance == accGroupMinDistance + && group.maxDistance == accGroupMaxDistance + && group.relDistanceHash == accGroup.relDistanceHash) { + // don't update if they are the same + return; + } + } + + // determine the buckets in which the existing group is + var existingBuckets = queryBuckets(group.minDistance, group.maxDistance); + + // determine the buckets in which the new group will be + Collection newBuckets; + if (accGroup.isRelevant()) { + // find the new buckets for this group and create new ones if necessary. + // determine how many buckets this group will be in + double groupFirstBucketIndex = Math.floor(accGroupMinDistance / this.bucketLength); + double groupSecondBucketIndex = Math.floor(accGroupMaxDistance / this.bucketLength); + double groupFirstStartDistance = groupFirstBucketIndex * this.bucketLength; + double groupSecondStartDistance = groupSecondBucketIndex * this.bucketLength; + double groupSecondEndDistance = groupSecondStartDistance + this.bucketLength; + int neededBuckets = (int) (groupSecondBucketIndex - groupFirstBucketIndex + 1); + + newBuckets = queryBuckets(groupFirstStartDistance, groupSecondEndDistance); + + int newBucketCount = newBuckets.size(); + if (newBucketCount < neededBuckets) { + // create the missing buckets + if (neededBuckets == 1) { + // one bucket, groupStartBucketIndex == groupEndBucketIndex + newBuckets = Collections.singleton(createBucketAt(groupFirstStartDistance)); + } else if (newBucketCount == 0) { + // create two new buckets, one for the start and one for the end + var startBucket = createBucketAt(groupFirstStartDistance); + var endBucket = createBucketAt(groupSecondStartDistance); + newBuckets = List.of(startBucket, endBucket); + } else { + // one of the buckets is missing, find out which one and create it + // if only one bucket is needed but none were found, then the same process is + // ok, since groupSecondStartDistance == groupFirstStartDistance + var existingBucket = newBuckets.iterator().next(); + var missingBucketStartDistance = existingBucket.startDistance == groupFirstStartDistance + ? groupSecondStartDistance + : groupFirstStartDistance; + newBuckets = Collections.singleton(createBucketAt(missingBucketStartDistance)); + } + } + } else { + // use an empty set of new buckets to remove the group from all buckets + // if it is irrelevant (meaning it has none or only one face plane distance) + newBuckets = Collections.emptySet(); + } + + // go through the collected buckets (of which there can be at most two) + // and process additions/removals of the group in both buckets + var allBuckets = new ReferenceArraySet(2); + allBuckets.addAll(existingBuckets); + allBuckets.addAll(newBuckets); + for (Bucket bucket : allBuckets) { + var bucketPrevStartBoundary = bucket.getStartBoundary(); + var bucketPrevEndBoundary = bucket.getEndBoundary(); + + boolean inExisting = existingBuckets.contains(bucket); + if (newBuckets.contains(bucket)) { + if (inExisting) { + bucket.updateGroupRange(group, accGroup, accGroupMinDistance, accGroupMaxDistance); + } else { + bucket.addNewGroup(group); + } + } else if (inExisting) { + bucket.removeGroup(group); + + // remove buckets using their previous distance range because the bucket has + // already updates its own boundaries (but those aren't the ones used in the + // tree) + if (bucket.isEmpty()) { + this.bucketRanges.remove(bucketPrevStartBoundary); + this.bucketRanges.remove(bucketPrevEndBoundary); + + // prevent re-adding the bucket when its range is updated in the tree later + continue; + } + } else { + throw new RuntimeException("bucketChange called but group is neither in existing nor in new bucket"); + } + + // since bucket min/max distances can extend beyond the bucket boundaries + // make sure to limit this using their actual boundaries. + // this ensures the invariant that buckets don't overlap is maintained. + double bucketNewStartBoundary = bucket.getStartBoundary(); + if (bucketNewStartBoundary != bucketPrevStartBoundary) { + this.bucketRanges.remove(bucketPrevStartBoundary); + this.bucketRanges.put(bucketNewStartBoundary, bucket); + } + double bucketNewEndBoundary = bucket.getEndBoundary(); + if (bucketNewEndBoundary != bucketPrevEndBoundary) { + this.bucketRanges.remove(bucketPrevEndBoundary); + this.bucketRanges.put(bucketNewEndBoundary, bucket); + } + } + + // if the group is new, then it won't be removed from all buckets + // it also doesn't need to be replaced with updated data + if (!groupIsNew) { + // entirely remove the group if it has been removed from all buckets + // this means it no longer needs to trigger at all + if (newBuckets.isEmpty()) { + this.groups.remove(pos); + } else { + // replace the group with the new data from accGroup + // up until this point the group is unchanged + group.replaceWith(accGroup, accGroupMinDistance, accGroupMaxDistance, baseDistance); + } + } + } + + boolean isEmpty() { + return this.groups.isEmpty(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java index 40c084e4c9..1a8a0dfb8f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java @@ -12,6 +12,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkMeshData; import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderBounds; import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderData; +import me.jellysquid.mods.sodium.client.render.chunk.gfni.*; import me.jellysquid.mods.sodium.client.util.task.CancellationSource; import me.jellysquid.mods.sodium.client.world.WorldSlice; import me.jellysquid.mods.sodium.client.world.cloned.ChunkRenderContext; @@ -37,11 +38,13 @@ public class ChunkRenderRebuildTask extends ChunkRenderBuildTask { private final RenderSection render; private final ChunkRenderContext renderContext; + private final GFNI gfni; private final int frame; - public ChunkRenderRebuildTask(RenderSection render, ChunkRenderContext renderContext, int frame) { + public ChunkRenderRebuildTask(RenderSection render, ChunkRenderContext renderContext, GFNI gfni, int frame) { this.render = render; this.renderContext = renderContext; + this.gfni = gfni; this.frame = frame; } @@ -70,7 +73,8 @@ public ChunkBuildResult performBuild(ChunkBuildContext buildContext, Cancellatio BlockPos.Mutable blockPos = new BlockPos.Mutable(); BlockPos.Mutable modelOffset = new BlockPos.Mutable(); - BlockRenderContext context = new BlockRenderContext(slice); + GroupBuilder groupBuilder = new GroupBuilder(render.getChunkPos()); + BlockRenderContext context = new BlockRenderContext(slice, groupBuilder); for (int y = minY; y < maxY; y++) { if (cancellationSource.isCancelled()) { @@ -102,7 +106,7 @@ public ChunkBuildResult performBuild(ChunkBuildContext buildContext, Cancellatio FluidState fluidState = blockState.getFluidState(); if (!fluidState.isEmpty()) { - cache.getFluidRenderer().render(slice, fluidState, blockPos, modelOffset, buffers, bounds); + cache.getFluidRenderer().render(slice, fluidState, blockPos, modelOffset, groupBuilder, buffers, bounds); } if (blockState.hasBlockEntity()) { @@ -138,6 +142,8 @@ public ChunkBuildResult performBuild(ChunkBuildContext buildContext, Cancellatio renderData.setOcclusionData(occluder.build()); renderData.setBounds(bounds.build(this.render.getChunkPos())); + this.gfni.integrateGroupBuilder(context.groupBuilder); + return new ChunkBuildResult(this.render, renderData.build(), meshes, this.frame); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/ModelQuadUtil.java b/src/main/java/me/jellysquid/mods/sodium/client/util/ModelQuadUtil.java index 12f445faeb..3208748fb1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/ModelQuadUtil.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/ModelQuadUtil.java @@ -1,6 +1,5 @@ package me.jellysquid.mods.sodium.client.util; -import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.common.util.DirectionUtil; import net.caffeinemc.mods.sodium.api.util.NormI8; @@ -70,43 +69,4 @@ public static ModelQuadFacing findNormalFace(float x, float y, float z) { public static ModelQuadFacing findNormalFace(int normal) { return findNormalFace(NormI8.unpackX(normal), NormI8.unpackY(normal), NormI8.unpackZ(normal)); } - - public static int calculateNormal(ModelQuadView quad) { - final float x0 = quad.getX(0); - final float y0 = quad.getY(0); - final float z0 = quad.getZ(0); - - final float x1 = quad.getX(1); - final float y1 = quad.getY(1); - final float z1 = quad.getZ(1); - - final float x2 = quad.getX(2); - final float y2 = quad.getY(2); - final float z2 = quad.getZ(2); - - final float x3 = quad.getX(3); - final float y3 = quad.getY(3); - final float z3 = quad.getZ(3); - - final float dx0 = x2 - x0; - final float dy0 = y2 - y0; - final float dz0 = z2 - z0; - final float dx1 = x3 - x1; - final float dy1 = y3 - y1; - final float dz1 = z3 - z1; - - float normX = dy0 * dz1 - dz0 * dy1; - float normY = dz0 * dx1 - dx0 * dz1; - float normZ = dx0 * dy1 - dy0 * dx1; - - float l = (float) Math.sqrt(normX * normX + normY * normY + normZ * normZ); - - if (l != 0) { - normX /= l; - normY /= l; - normZ /= l; - } - - return NormI8.pack(normX, normY, normZ); - } } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinBakedQuad.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinBakedQuad.java index 322946f9cc..f35fe150ad 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinBakedQuad.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinBakedQuad.java @@ -4,6 +4,7 @@ import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFlags; import me.jellysquid.mods.sodium.client.util.ModelQuadUtil; +import net.caffeinemc.mods.sodium.api.util.NormI8; import net.minecraft.client.render.model.BakedQuad; import net.minecraft.client.texture.Sprite; import net.minecraft.util.math.Direction; @@ -42,11 +43,15 @@ public abstract class MixinBakedQuad implements BakedQuadView { private int flags; private int normal; + private float normX; + private float normY; + private float normZ; private ModelQuadFacing normalFace; @Inject(method = "", at = @At("RETURN")) private void init(int[] vertexData, int colorIndex, Direction face, Sprite sprite, boolean shade, CallbackInfo ci) { - this.normal = ModelQuadUtil.calculateNormal(this); + this.calculateAccurateNormal(); + this.normal = NormI8.pack(this.normX, this.normY, this.normZ); this.normalFace = ModelQuadUtil.findNormalFace(this.normal); this.flags = ModelQuadFlags.getQuadFlags(this, face); @@ -82,6 +87,28 @@ public int getNormal() { return this.normal; } + @Override + public float getNormX() { + return this.normX; + } + + @Override + public float getNormY() { + return this.normY; + } + + @Override + public float getNormZ() { + return this.normZ; + } + + @Override + public void setAccurateNormal(float x, float y, float z) { + this.normX = x; + this.normY = y; + this.normZ = z; + } + @Override public float getTexU(int idx) { return Float.intBitsToFloat(this.vertexData[vertexOffset(idx) + TEXTURE_INDEX]); From cafb28da338a0f8ebb90ba7039ae6c0c3e6492d2 Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 21 Jul 2023 23:18:46 +0200 Subject: [PATCH 002/256] GFNI using interval trees (with debuggin) --- build.gradle | 2 + .../sodium/client/model/quad/ModelQuad.java | 14 +- .../client/model/quad/ModelQuadView.java | 16 +- .../render/chunk/RenderSectionManager.java | 5 +- .../render/chunk/gfni/AccumulationGroup.java | 39 +- .../client/render/chunk/gfni/Bucket.java | 206 ---------- .../sodium/client/render/chunk/gfni/GFNI.java | 142 ++++--- .../client/render/chunk/gfni/Group.java | 21 +- .../render/chunk/gfni/GroupBuilder.java | 81 +++- .../client/render/chunk/gfni/NormalList.java | 368 ++++++------------ .../mixin/core/pipeline/MixinBakedQuad.java | 14 +- 11 files changed, 341 insertions(+), 567 deletions(-) delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Bucket.java diff --git a/build.gradle b/build.gradle index 8ce4c0a8ee..1b9ba33fb1 100644 --- a/build.gradle +++ b/build.gradle @@ -80,6 +80,8 @@ dependencies { mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" + implementation "com.lodborg:interval-tree:1.0.0" + // Fabric API modIncludeImplementation(fabricApi.module("fabric-api-base", project.fabric_version)) modIncludeImplementation(fabricApi.module("fabric-rendering-fluids-v1", project.fabric_version)) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuad.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuad.java index 0c1261a4ff..23d39b8994 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuad.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuad.java @@ -15,9 +15,9 @@ public class ModelQuad implements ModelQuadViewMutable { private Sprite sprite; private int colorIdx; private int normal; - private float normX; - private float normY; - private float normZ; + private int normX; + private int normY; + private int normZ; @Override public void setX(int idx, float x) { @@ -125,22 +125,22 @@ public int getNormal() { } @Override - public float getNormX() { + public int getNormX() { return this.normX; } @Override - public float getNormY() { + public int getNormY() { return this.normY; } @Override - public float getNormZ() { + public int getNormZ() { return this.normZ; } @Override - public void setAccurateNormal(float x, float y, float z) { + public void setAccurateNormal(int x, int y, int z) { this.normX = x; this.normY = y; this.normZ = z; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java index a15506be7c..7ef18ed147 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java @@ -2,6 +2,7 @@ import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFlags; import net.minecraft.client.texture.Sprite; +import net.minecraft.util.math.MathHelper; /** * Provides a read-only view of a model quad. For mutable access to a model quad, see {@link ModelQuadViewMutable}. @@ -60,17 +61,17 @@ public interface ModelQuadView { /** * @return The x coordinate of the unit normal vector */ - float getNormX(); + int getNormX(); /** * @return The y coordinate of the unit normal vector */ - float getNormY(); + int getNormY(); /** * @return The z coordinate of the unit normal vector */ - float getNormZ(); + int getNormZ(); /** * Sets an accurate normal vector for this quad. This is used for GFNI. @@ -79,7 +80,7 @@ public interface ModelQuadView { * @param y The normal's y component * @param z The normal's z component */ - void setAccurateNormal(float x, float y, float z); + void setAccurateNormal(int x, int y, int z); /** * Calculates the normal vector for this quad using the cross product of the @@ -116,13 +117,16 @@ default void calculateAccurateNormal() { float l = (float) Math.sqrt(normX * normX + normY * normY + normZ * normZ); - if (l != 0) { + if (l != 0 && l != 1) { normX /= l; normY /= l; normZ /= l; } - this.setAccurateNormal(normX, normY, normZ); + this.setAccurateNormal( + (int) (normX * 32), + (int) (normY * 32), + (int) (normZ * 32)); } default boolean hasColor() { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index a185091843..d88f4ea8ba 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -272,7 +272,8 @@ private boolean loadSection(int x, int y, int z) { } private boolean unloadSection(int x, int y, int z) { - RenderSection chunk = this.sections.remove(ChunkSectionPos.asLong(x, y, z)); + long chunkSectionLongPos = ChunkSectionPos.asLong(x, y, z); + RenderSection chunk = this.sections.remove(chunkSectionLongPos); if (chunk == null) { throw new IllegalStateException("Chunk is not loaded: " + ChunkSectionPos.from(x, y, z)); @@ -287,6 +288,8 @@ private boolean unloadSection(int x, int y, int z) { this.disconnectNeighborNodes(chunk); + this.gfni.removeSection(chunkSectionLongPos); + return true; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AccumulationGroup.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AccumulationGroup.java index 7898a038e8..97a2a1ce16 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AccumulationGroup.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AccumulationGroup.java @@ -2,46 +2,47 @@ import org.joml.Vector3fc; +import com.lodborg.intervaltree.DoubleInterval; +import com.lodborg.intervaltree.Interval.Bounded; + import it.unimi.dsi.fastutil.doubles.DoubleOpenHashSet; import net.minecraft.util.math.ChunkSectionPos; public class AccumulationGroup { final DoubleOpenHashSet relativeDistances = new DoubleOpenHashSet(16); final Vector3fc normal; + final int groupBuilderKey; final ChunkSectionPos sectionPos; - private double minDistance = Double.POSITIVE_INFINITY; - private double maxDistance = Double.NEGATIVE_INFINITY; long relDistanceHash = 0; - public AccumulationGroup(ChunkSectionPos sectionPos, Vector3fc normal) { + private double relMinDistance = Double.POSITIVE_INFINITY; + private double relMaxDistance = Double.NEGATIVE_INFINITY; + + public AccumulationGroup(ChunkSectionPos sectionPos, Vector3fc normal, int groupBuilderKey) { this.sectionPos = sectionPos; this.normal = normal; + this.groupBuilderKey = groupBuilderKey; } - void add(float vertexX, float vertexY, float vertexZ) { - add(this.normal.dot(vertexX, vertexY, vertexZ)); - } + boolean add(float vertexX, float vertexY, float vertexZ) { + double distance = this.normal.dot(vertexX, vertexY, vertexZ); - void add(double distance) { // add the distance to the set and update the min/max distances if necessary if (this.relativeDistances.add(distance)) { - this.minDistance = Math.min(this.minDistance, distance); - this.maxDistance = Math.max(this.maxDistance, distance); + this.relMinDistance = Math.min(this.relMinDistance, distance); + this.relMaxDistance = Math.max(this.relMaxDistance, distance); long distanceBits = Double.doubleToLongBits(distance); this.relDistanceHash ^= distanceBits; + return true; } + return false; } - boolean isRelevant() { - return relativeDistances.size() > 1; - } - - double getMinDistance(double baseDistance) { - return this.minDistance + baseDistance; - } - - double getMaxDistance(double baseDistance) { - return this.maxDistance + baseDistance; + DoubleInterval getDistanceInterval(double baseDistance) { + return new DoubleInterval( + this.relMinDistance + baseDistance, + this.relMaxDistance + baseDistance, + Bounded.CLOSED); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Bucket.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Bucket.java deleted file mode 100644 index b8b953ccbb..0000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Bucket.java +++ /dev/null @@ -1,206 +0,0 @@ -package me.jellysquid.mods.sodium.client.render.chunk.gfni; - -import it.unimi.dsi.fastutil.doubles.Double2ReferenceAVLTreeMap; -import it.unimi.dsi.fastutil.objects.ReferenceArraySet; - -/** - * A bucket contains all groups of a normal list that fall within a certain - * distance range. The groups are non-overlapping but some sections may have two - * groups to deal with sections that cross bucket borders. The bucket size is - * chosen such that no section's faces can cover more than two buckets, even if - * the normal is diagonal to the axes. - * - * TODO: a more sophisticated structure instead of subbuckets that can - * efficiently range query overlapping groups. Traditional segment trees use - * integer segments so they aren't quite the right fit here. - */ -public class Bucket { - private static final int SUBBUCKETS = 4; - - /** - * The backing collection storing the groups in this bucket. An array of sets is - * used to cut down on the number of groups that need to be iterated in range - * queries. - */ - @SuppressWarnings("unchecked") - final ReferenceArraySet[] groups = new ReferenceArraySet[SUBBUCKETS]; - final Double2ReferenceAVLTreeMap allGroups = new Double2ReferenceAVLTreeMap<>(); - - /** - * The minimum and maximum distances of all the groups in this bucket. - */ - private double minDistance; - private double maxDistance; - - /** - * The starting distance of this bucket. There don't need to be face planes - * filling the whole bucket. - * - * NOTE: groups may protrude outside the bucket and the min/max distances - * reflect that. However, the normal list makes sure only groups that overlap - * with this bucket are added. - */ - final double startDistance; - final double endDistance; - - Bucket(double startDistance, double bucketLength) { - this.startDistance = startDistance; - this.endDistance = startDistance + bucketLength; - } - - private boolean isOutsideContentRange(double start, double end) { - return start >= this.maxDistance || end <= this.minDistance; - } - - private static int constrainIndex(int index) { - return Math.max(0, Math.min(index, SUBBUCKETS - 1)); - } - - private int getSubbucketStart(double start) { - return constrainIndex((int) Math.floor((start - this.startDistance) / SUBBUCKETS)); - } - - private int getSubbucketEnd(double end) { - return getSubbucketStart(end) + 1; - } - - double getStartBoundary() { - if (isEmpty()) { - return this.startDistance; - } - return Math.max(this.startDistance, this.minDistance); - } - - double getEndBoundary() { - if (isEmpty()) { - return this.endDistance; - } - return Math.min(this.endDistance, this.maxDistance); - } - - void triggerRange(GFNI gfni, double start, double end) { - // stop if the query range is outside the bucket - // (start of the query range is inclusive, end is exclusive) (?) - if (isOutsideContentRange(start, end)) { - return; - } - - // iterate subbuckets that fall within the range or all of them if the whole - // bucket is within the range - // TODO: even better heuristic, it's more efficient to iterate all groups if the - // the range is just _most_ of the whole bucket - int subbucketStart = getSubbucketStart(start); - int subbucketEnd = getSubbucketEnd(end); - if (subbucketEnd - subbucketStart == SUBBUCKETS) { - Group previousGroup = null; - for (Group group : this.allGroups.values()) { - // deduplicate groups since they're each entered twice - if (group != previousGroup) { - group.triggerRange(gfni, start, end); - } - previousGroup = group; - } - } else { - for (int i = subbucketStart; i < subbucketEnd; i++) { - ReferenceArraySet subbucket = this.groups[i]; - if (subbucket != null) { - for (Group group : subbucket) { - group.triggerRange(gfni, start, end); - } - } - } - } - } - - void addNewGroup(Group group) { - for (int i = getSubbucketStart(group.minDistance), - endIndex = getSubbucketEnd(group.maxDistance); i < endIndex; i++) { - ReferenceArraySet subbucket = this.groups[i]; - if (subbucket == null) { - subbucket = new ReferenceArraySet<>(); - this.groups[i] = subbucket; - } - subbucket.add(group); - } - - // if this is the first group being added, set the min/max distances directly - if (this.allGroups.isEmpty()) { - this.minDistance = group.minDistance; - this.maxDistance = group.maxDistance; - } else { - this.minDistance = Math.min(this.minDistance, group.minDistance); - this.maxDistance = Math.max(this.maxDistance, group.maxDistance); - } - this.allGroups.put(group.minDistance, group); - this.allGroups.put(group.maxDistance, group); - - } - - void removeGroup(Group group) { - for (int i = getSubbucketStart(group.minDistance), - endIndex = getSubbucketEnd(group.maxDistance); i < endIndex; i++) { - ReferenceArraySet subbucket = this.groups[i]; - if (subbucket != null) { - subbucket.remove(group); - - if (subbucket.isEmpty()) { - this.groups[i] = null; - } - } - } - - this.allGroups.remove(group.minDistance); - this.allGroups.remove(group.maxDistance); - if (!isEmpty()) { - this.minDistance = this.allGroups.firstDoubleKey(); - this.maxDistance = this.allGroups.lastDoubleKey(); - } - } - - void updateGroupRange(Group existingGroup, AccumulationGroup accGroup, - double accGroupMinDistance, double accGroupMaxDistance) { - // iterate the relevant subbuckets and add or remove the group from them - // the existing group contains the old range, the accGroup contains the new - int existingStart = getSubbucketStart(existingGroup.minDistance); - int existingEnd = getSubbucketEnd(existingGroup.maxDistance); - int newStart = getSubbucketStart(accGroupMinDistance); - int newEnd = getSubbucketEnd(accGroupMaxDistance); - for (int i = Math.min(existingStart, newStart), endIndex = Math.max(existingEnd, newEnd); i < endIndex; i++) { - ReferenceArraySet subbucket = this.groups[i]; - boolean inExisting = i >= existingStart && i < existingEnd; - boolean inNew = i >= newStart && i < newEnd; - - if (inNew && !inExisting) { - if (subbucket == null) { - subbucket = new ReferenceArraySet<>(); - this.groups[i] = subbucket; - } - subbucket.add(existingGroup); - } else if (inExisting && !inNew) { - if (subbucket == null) { - int a = 4; // TODO: remove - } - subbucket.remove(existingGroup); - - if (subbucket.isEmpty()) { - this.groups[i] = null; - } - } - } - - if (accGroupMinDistance != existingGroup.minDistance) { - this.allGroups.remove(existingGroup.minDistance); - this.allGroups.put(accGroupMinDistance, existingGroup); - this.minDistance = this.allGroups.firstDoubleKey(); - } - if (accGroupMaxDistance != existingGroup.maxDistance) { - this.allGroups.remove(existingGroup.maxDistance); - this.allGroups.put(accGroupMaxDistance, existingGroup); - this.maxDistance = this.allGroups.lastDoubleKey(); - } - } - - boolean isEmpty() { - return this.allGroups.isEmpty(); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java index 8237368ea9..2dc44bf94e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java @@ -1,9 +1,12 @@ package me.jellysquid.mods.sodium.client.render.chunk.gfni; +import java.time.Duration; +import java.time.Instant; + import org.joml.Vector3fc; import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; -import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import net.minecraft.util.math.ChunkSectionPos; /** @@ -12,7 +15,7 @@ * * Distances are stored as doubles and normals are stored as float vectors. * - * TODO: make Group and Bucket relative to use floats instead of doubles + * TODO: make Group and Bucket relative to use floats instead of doubles? * * TODO: synchronization is used for integrating group builders submitted from * chunk build threads. It is assumed that integrating a group builder is fast @@ -27,34 +30,28 @@ * * TODO: destory functionality similar to RenderSectionManger's destroy method? * - * TODO: handle unloading of sections, there are no updates when the section - * just goes away. this needs to be hooked into and handled like an update to an - * irrelevant new group. - * - * TODO: for some reason in the first time using a void world, blocks added with - * setblock are invisible. - * * TODO: does teleporting and switching dimensions work? */ public class GFNI { /** * A map of all the normal lists, indexed by their normal. */ - Object2ReferenceOpenHashMap normalLists = new Object2ReferenceOpenHashMap<>(50); + private Object2ReferenceOpenHashMap normalLists = new Object2ReferenceOpenHashMap<>(50); - ReferenceOpenHashSet triggeredSections = new ReferenceOpenHashSet<>(50); + /** + * A temporary set of sections that were triggered during movement. A set is + * needed because the same section can be triggered multiple times by different + * normal lists. + */ + ObjectOpenHashSet triggeredSections = new ObjectOpenHashSet<>(50); public void processMovement(double lastCameraX, double lastCameraY, double lastCameraZ, double cameraX, double cameraY, double cameraZ) { + var startTime = Instant.now(); triggeredSections.clear(); - try { - for (NormalList normalList : this.normalLists.values()) { - normalList.processMovement(this, lastCameraX, lastCameraY, lastCameraZ, cameraX, cameraY, cameraZ); - } - } catch (Exception e) { - e.printStackTrace(); - throw e; + for (var normalList : this.normalLists.values()) { + normalList.processMovement(this, lastCameraX, lastCameraY, lastCameraZ, cameraX, cameraY, cameraZ); } // TODO: do something with the triggered sections @@ -66,47 +63,102 @@ public void processMovement(double lastCameraX, double lastCameraY, double lastC System.out.println(section.getX() + " " + section.getY() + " " + section.getZ()); } } + + // TODO: remove + var duration = Duration.between(startTime, Instant.now()); + System.out.println("Processed movement in " + (float) duration.toNanos() / 1_000_000 + " ms"); } void triggerSection(ChunkSectionPos section) { this.triggeredSections.add(section); } - // TODO: synchronized because it's expected to be fast, see class comment - public synchronized void integrateGroupBuilder(GroupBuilder builder) { - try { - for (AccumulationGroup accGroup : builder.alignedFaceDistances) { - if (accGroup != null) { - updateGroup(accGroup); - } - } - for (AccumulationGroup accGroup : builder.unalignedDistances.values()) { - updateGroup(accGroup); - } - } catch (Exception e) { - e.printStackTrace(); - throw e; + private void removeSectionFromList(NormalList normalList, long chunkSectionLongPos) { + normalList.removeSection(chunkSectionLongPos); + if (normalList.isEmpty()) { + this.normalLists.remove(normalList.getNormal()); + } + } + + public void removeSection(long chunkSectionLongPos) { + var startTime = Instant.now(); + int normalListCount = this.normalLists.size(); + + for (var normalList : this.normalLists.values()) { + removeSectionFromList(normalList, chunkSectionLongPos); + } + + // TODO: remove + if (normalListCount != this.normalLists.size()) { + System.out.println(normalLists.size() + " normal lists"); } + var duration = Duration.between(startTime, Instant.now()); + System.out.println("Processed section removal in " + (float) duration.toNanos() / 1_000_000 + " ms"); + } - private void updateGroup(AccumulationGroup accGroup) { + private void addSectionInNewNormalLists(AccumulationGroup accGroup) { var normal = accGroup.normal; - NormalList normalList = this.normalLists.get(normal); + var normalList = this.normalLists.get(normal); if (normalList == null) { - // skip even creating a normal list if the group is irrelevant - if (accGroup.isRelevant()) { - normalList = new NormalList(normal); - this.normalLists.put(normal, normalList); - normalList.updateGroup(accGroup); + normalList = new NormalList(normal, accGroup.groupBuilderKey); + this.normalLists.put(normal, normalList); + normalList.addSection(accGroup, accGroup.sectionPos.asLong()); + } + } + + // TODO: synchronized because it's expected to be fast, see class comment + public synchronized void integrateGroupBuilder(GroupBuilder builder) { + long chunkSectionLongPos = builder.sectionPos.asLong(); + + // if the builder is irrelevant, remove it from the normal lists + if (!builder.isRelevant()) { + removeSection(chunkSectionLongPos); + return; + } + + var startTime = Instant.now(); + + int normalListCount = this.normalLists.size(); + + // go through all normal lists and check against the normals that the group + // builder has. if the normal list has data for the section, but the group + // builder doesn't, the group is removed. otherwise, the group is updated. + for (var normalList : this.normalLists.values()) { + // check if the group builder includes data for this normal. + var accGroup = builder.getGroupForNormal(normalList); + if (normalList.hasSection(chunkSectionLongPos)) { + if (accGroup == null) { + removeSectionFromList(normalList, chunkSectionLongPos); + } else { + normalList.updateSection(accGroup, chunkSectionLongPos); + } + } else if (accGroup != null) { + normalList.addSection(accGroup, chunkSectionLongPos); } - } else { - // irrelevant groups do need to be updated on existing normal lists because - // existing data has to be removed - normalList.updateGroup(accGroup); + } - if (normalList.isEmpty()) { - this.normalLists.remove(normal); + // go through the data of the group builder to check for data of new normals + // for which there are no normal lists yet. This only checks for new normal + // lists since new data for existing normal lists is handled above. + if (builder.axisAlignedDistances != null) { + for (var accGroup : builder.axisAlignedDistances) { + if (accGroup != null) { + addSectionInNewNormalLists(accGroup); + } } } + if (builder.unalignedDistances != null) { + for (var accGroup : builder.unalignedDistances.values()) { + addSectionInNewNormalLists(accGroup); + } + } + + // TODO: remove + if (normalListCount != this.normalLists.size()) { + System.out.println(normalLists.size() + " normal lists"); + } + var duration = Duration.between(startTime, Instant.now()); + System.out.println("Processed section add/update in " + (float) duration.toNanos() / 1_000_000 + " ms"); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java index af74b3df47..9ffca1f23b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java @@ -1,5 +1,7 @@ package me.jellysquid.mods.sodium.client.render.chunk.gfni; +import com.lodborg.intervaltree.DoubleInterval; + import it.unimi.dsi.fastutil.doubles.DoubleAVLTreeSet; import net.minecraft.util.math.ChunkSectionPos; @@ -27,22 +29,17 @@ public class Group { long relDistanceHash = 0; /** - * The minimum and maximum distances of all the faces planes in this - * group. + * The closed (inclusive of both boundaries) minimum and maximum distances. */ - double minDistance; - double maxDistance; + DoubleInterval distances; - Group(AccumulationGroup accGroup, double accGroupMinDistance, double accGroupMaxDistance, double baseDistance) { - replaceWith(accGroup, accGroupMinDistance, accGroupMaxDistance, baseDistance); + Group(AccumulationGroup accGroup, DoubleInterval accGroupDistances, double baseDistance) { + replaceWith(accGroup, accGroupDistances, baseDistance); } - void replaceWith(AccumulationGroup accGroup, - double accGroupMinDistance, double accGroupMaxDistance, - double baseDistance) { + void replaceWith(AccumulationGroup accGroup, DoubleInterval accGroupDistances, double baseDistance) { this.sectionPos = accGroup.sectionPos; - this.minDistance = accGroupMinDistance; - this.maxDistance = accGroupMaxDistance; + this.distances = accGroupDistances; this.relDistanceHash = accGroup.relDistanceHash; // clear the existing tree and add all the face plane distances but add the base @@ -55,7 +52,7 @@ void replaceWith(AccumulationGroup accGroup, void triggerRange(GFNI gfni, double start, double end) { // trigger self on the section if the query range overlaps with the group - if (start < this.maxDistance && end > this.minDistance + if (start < this.distances.getEnd() && end > this.distances.getStart() && !this.facePlaneDistances.subSet(start, end).isEmpty()) { gfni.triggerSection(this.sectionPos); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java index 0aa9879a07..fd799bbbef 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java @@ -3,7 +3,7 @@ import org.joml.Vector3f; import org.joml.Vector3fc; -import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; +import it.unimi.dsi.fastutil.ints.Int2ReferenceLinkedOpenHashMap; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import net.minecraft.util.math.ChunkSectionPos; @@ -16,10 +16,11 @@ public class GroupBuilder { } } - AccumulationGroup[] alignedFaceDistances = new AccumulationGroup[ModelQuadFacing.DIRECTIONS.length]; - Object2ReferenceOpenHashMap unalignedDistances = new Object2ReferenceOpenHashMap<>( - 4); - ChunkSectionPos sectionPos; + AccumulationGroup[] axisAlignedDistances; + Int2ReferenceLinkedOpenHashMap unalignedDistances; + + final ChunkSectionPos sectionPos; + private int facePlaneCount = 0; public GroupBuilder(ChunkSectionPos sectionPos) { this.sectionPos = sectionPos; @@ -30,27 +31,77 @@ public void addAlignedFace(ModelQuadFacing facing, float vertexX, float vertexY, throw new IllegalArgumentException("Cannot add an unaligned face with addAlignedFace()"); } + if (this.axisAlignedDistances == null) { + this.axisAlignedDistances = new AccumulationGroup[ModelQuadFacing.DIRECTIONS.length]; + } + int index = facing.ordinal(); - AccumulationGroup distances = this.alignedFaceDistances[index]; + AccumulationGroup distances = this.axisAlignedDistances[index]; if (distances == null) { - distances = new AccumulationGroup(sectionPos, ALIGNED_NORMALS[index]); - this.alignedFaceDistances[index] = distances; + distances = new AccumulationGroup(sectionPos, ALIGNED_NORMALS[index], index); + this.axisAlignedDistances[index] = distances; } - distances.add(vertexX, vertexY, vertexZ); + addVertex(distances, vertexX, vertexY, vertexZ); } - public void addUnalignedFace(float normalX, float normalY, float normalZ, + public void addUnalignedFace(int normalX, int normalY, int normalZ, float vertexX, float vertexY, float vertexZ) { - Vector3fc normal = new Vector3f(normalX, normalY, normalZ); - AccumulationGroup distances = this.unalignedDistances.get(normal); + if (this.unalignedDistances == null) { + this.unalignedDistances = new Int2ReferenceLinkedOpenHashMap<>(4); + } + + // the key for the hash map is the normal packed into an int + // the lowest byte is 0xFF to prevent collisions with axis-aligned normals + // (assuming quantization with 32, which is 5 bits per component) + int normalKey = 0xFF | (normalX & 0xFF << 8) | (normalY & 0xFF << 15) | (normalZ & 0xFF << 22); + AccumulationGroup distances = this.unalignedDistances.get(normalKey); if (distances == null) { - distances = new AccumulationGroup(sectionPos, normal); - this.unalignedDistances.put(normal, distances); + // actually normalize the vector to ensure it's a unit vector + // for the rest of the process which requires that + Vector3f normal = new Vector3f(normalX, normalY, normalZ); + normal.normalize(); + distances = new AccumulationGroup(sectionPos, normal, normalKey); + this.unalignedDistances.put(normalKey, distances); } - distances.add(vertexX, vertexY, vertexZ); + addVertex(distances, vertexX, vertexY, vertexZ); + } + + private void addVertex(AccumulationGroup accGroup, float vertexX, float vertexY, float vertexZ) { + if (accGroup.add(vertexX, vertexY, vertexZ)) { + this.facePlaneCount++; + } + } + + AccumulationGroup getGroupForNormal(NormalList normalList) { + int groupBuilderKey = normalList.getGroupBuilderKey(); + if (groupBuilderKey < 0xFF) { + if (this.axisAlignedDistances == null) { + return null; + } + return this.axisAlignedDistances[groupBuilderKey]; + } else { + if (this.unalignedDistances == null) { + return null; + } + return this.unalignedDistances.get(groupBuilderKey); + } + } + + /** + * Checks if this group builder is relevant for translucency sort triggering. If + * there are no or only one normal, this builder can be considered practically + * empty. + * + * More heuristics can be performed here to conservatively determine if this + * section could possibly have more than one translucent sort order. + * + * @return true if this group builder is relevant + */ + boolean isRelevant() { + return this.facePlaneCount > 1; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java index d7fbc69327..615f0125a8 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java @@ -1,148 +1,90 @@ package me.jellysquid.mods.sodium.client.render.chunk.gfni; import java.util.Collection; -import java.util.Collections; -import java.util.List; import org.joml.Vector3d; import org.joml.Vector3dc; import org.joml.Vector3fc; -import it.unimi.dsi.fastutil.doubles.Double2ReferenceAVLTreeMap; +import com.lodborg.intervaltree.DoubleInterval; +import com.lodborg.intervaltree.Interval; +import com.lodborg.intervaltree.Interval.Bounded; +import com.lodborg.intervaltree.IntervalTree; + +import it.unimi.dsi.fastutil.longs.Long2ReferenceOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; import it.unimi.dsi.fastutil.objects.ReferenceArraySet; +import it.unimi.dsi.fastutil.objects.ReferenceLinkedOpenHashSet; import net.minecraft.util.math.ChunkSectionPos; /** * A normal list contains all the face planes that have the same normal. - * - * TODO: instead of buckets, use an interval tree - * https://github.com/lodborg/interval-tree for each normal list with the groups - * in it. Since the interval tree is just a set of intervals, use a multi hash - * map to map the intervals to the groups. There can be multiple groups per - * interval. */ public class NormalList { /** - * The normal of this normal list. + * Size threshold after which group sets in {@link #groupsByInterval} are + * replaced with hash sets to improve update performance. */ - final Vector3dc normal; + private static final int HASH_SET_THRESHOLD = 40; /** - * The bucket size in terms of normal-relative distance, chosen such that no - * section can span more than two buckets. This is effectively length of a - * 16*16*16 chunk section in terms of normal-relative distance. + * Size threshold under which group sets in {@link #groupsByInterval} are + * downgraded to array sets to improve reduce memory usage. */ - final float bucketLength; + private static final int ARRAY_SET_THRESHOLD = 10; /** - * map of bucket ranges to buckets, each bucket appears twice in this map. Since - * the bucket ranges are disjoint, this allows us to find the bucket for a given - * range even if the range is fully contained within a bucket. There can only - * ever be a single bucket at any key. + * The normal of this normal list. */ - final Double2ReferenceAVLTreeMap bucketRanges = new Double2ReferenceAVLTreeMap<>(); + private final Vector3dc normal; + private final Vector3fc normalf; /** - * A separate hashmap of groups to enable fast retrieval of existing groups. + * If this normal list is for an axis-aligned normal, this is the index of it + * for querying in {@link GroupBuilder#getGroupForNormal(Vector3fc)}. + * + * If this normal list is for an unaligned normal, this is the key for the + * hash map of quantized normals. */ - final Object2ReferenceOpenHashMap groups = new Object2ReferenceOpenHashMap<>(); + private final int groupBuilderKey; /** - * Constructs a new normal list with the given unit normal vector. - * - * @param normal The unit normal vector + * An interval tree of group intervals. Since this only stores intervals, the + * stored intervals are mapped to groups in a separate hashmap. */ - NormalList(Vector3fc normal) { - this.normal = new Vector3d(normal); - this.bucketLength = Math.abs(normal.x() * 16) + Math.abs(normal.y() * 16) + Math.abs(normal.z() * 16); - } + private final IntervalTree groupIntervals = new IntervalTree<>(); /** - * Picks a bucket size for the given normal. The size must be chosen such that - * no section (16x16x16 cube) can span more than two buckets with respect to the - * normal. For axis-aligned normals, the size is 16. For diagonal normals with - * one axis-aligned component, the size is sqrt(16^2 + 16^2) ≈ 22.628 (rounded - * up). For fully diagonal normals the size is sqrt(16^2 + 16^2 + 16^2) ≈ 27.713 - * (rounded up). - * - * @param normal The unit normal vector - * @return The bucket size + * A separate hashmap of groups. This is what actually stores the groups since + * the interval tree just contains intervals. */ - private static float getBucketSize(Vector3fc normal) { - int zeroComponents = 0; - if (normal.x() == 0) { - zeroComponents++; - } - if (normal.y() == 0) { - zeroComponents++; - } - if (normal.z() == 0) { - zeroComponents++; - } - if (zeroComponents == 3) { - throw new IllegalArgumentException("normal must not be zero"); - } else if (zeroComponents == 2) { - return 16f; - } else if (zeroComponents == 1) { - return 22.628f; - } else { - return 27.713f; - } - } + private final Object2ReferenceOpenHashMap> groupsByInterval = new Object2ReferenceOpenHashMap<>(); /** - * Finds the 0-2 buckets that fall within the given range. However the range may - * be smaller than a bucket, in which case the enclosing bucket is returned. - * - * @param start The start of the range - * @param end The end of the range - * @return The buckets that fall within the range + * A hashmap from chunk sections to groups. This is for finding groups during + * updates. */ - private Collection queryBuckets(double start, double end) { - if (start > end) { - throw new IllegalArgumentException("start must be less than or equal to end"); - } + private final Long2ReferenceOpenHashMap groupsBySection = new Long2ReferenceOpenHashMap<>(); - // do a simple range query to see which buckets fall within the range - // if there are any, simply return them as there can't be any buckets enclosing - // the range if there are bucket boundaries within the range - var innerBuckets = this.bucketRanges.subMap(start, end); - if (!innerBuckets.isEmpty()) { - // each bucket can appear twice in the map, so remove duplicates - if (innerBuckets.size() == 1) { - return innerBuckets.values(); - } else { - Bucket first = innerBuckets.get(innerBuckets.firstDoubleKey()); - Bucket last = innerBuckets.get(innerBuckets.lastDoubleKey()); - if (first == last) { - return Collections.singleton(first); - } else { - return List.of(first, last); - } - } - } + /** + * Constructs a new normal list with the given unit normal vector and aligned + * normal index. + * + * @param normal The unit normal vector + * @param groupBuilderKey The group builder index + */ + NormalList(Vector3fc normal, int groupBuilderKey) { + this.normalf = normal; + this.normal = new Vector3d(normal); + this.groupBuilderKey = groupBuilderKey; + } - // in this case the range is enclosed by a single bucket, or none - // there is an enclosing bucket if the two next bucket boundaries are the same - // bucket - // otherwise there is no enclosing bucket - var headMap = this.bucketRanges.headMap(start); - if (headMap.isEmpty()) { - return Collections.emptyList(); - } - var tailMap = this.bucketRanges.tailMap(end); - if (tailMap.isEmpty()) { - return Collections.emptyList(); - } + public Vector3fc getNormal() { + return normalf; + } - var headEntry = headMap.get(headMap.lastDoubleKey()); - var tailEntry = tailMap.get(tailMap.firstDoubleKey()); - if (headEntry == tailEntry) { - return Collections.singleton(headEntry); - } else { - return Collections.emptyList(); - } + public int getGroupBuilderKey() { + return groupBuilderKey; } void processMovement(GFNI gfni, double lastCameraX, double lastCameraY, double lastCameraZ, @@ -150,172 +92,100 @@ void processMovement(GFNI gfni, double lastCameraX, double lastCameraY, double l // calculate the distance range of the movement with respect to the normal double start = this.normal.dot(lastCameraX, lastCameraY, lastCameraZ); double end = this.normal.dot(cameraX, cameraY, cameraZ); - // double start = -100000; - // double end = 100000; // stop if the movement is reverse with regards to the normal - // this means it's moving against the normal + // since this means it's moving against the normal if (start > end) { return; } - // range query for triggering the 0-2 buckets that fall within the range - var queryBuckets = queryBuckets(start, end); - if (!queryBuckets.isEmpty()) { - for (Bucket bucket : queryBuckets) { - bucket.triggerRange(gfni, start, end); + // perform the interval query on the group intervals and resolve each interval + // to the collection of groups it maps to + var interval = new DoubleInterval(start, end, Bounded.CLOSED); + for (Interval groupInterval : groupIntervals.query(interval)) { + for (Group group : groupsByInterval.get(groupInterval)) { + group.triggerRange(gfni, start, end); } } } - private Bucket createBucketAt(double startDistance) { - return new Bucket(startDistance, this.bucketLength); - } - - void updateGroup(AccumulationGroup accGroup) { - // find the existing buckets that the group could be in - ChunkSectionPos pos = accGroup.sectionPos; - double baseDistance = accGroup.normal.dot(pos.getMinX(), pos.getMinY(), pos.getMinZ()); - double accGroupMinDistance = accGroup.getMinDistance(baseDistance); - double accGroupMaxDistance = accGroup.getMaxDistance(baseDistance); - - Group group = this.groups.get(pos); - boolean groupIsNew = false; - if (group == null) { - // stop on new irrelevant groups - if (!accGroup.isRelevant()) { - return; - } - - // make a new group for this accumulation group - group = new Group(accGroup, accGroupMinDistance, accGroupMaxDistance, baseDistance); - groupIsNew = true; - this.groups.put(pos, group); - } else { - // this is just a heuristic, but it assumes that if the size, bounds and - // hash are equal, they are most likely the same. We also know that the existing - // and new data is for the same section position since the group was retrieved - // from the map for the right position. - // TODO: how common are collisions and are they bad? - // If they are common, use second hash - if (group.facePlaneDistances.size() == accGroup.relativeDistances.size() - && group.minDistance == accGroupMinDistance - && group.maxDistance == accGroupMaxDistance - && group.relDistanceHash == accGroup.relDistanceHash) { - // don't update if they are the same - return; + private void removeGroupInterval(Group group) { + this.groupIntervals.remove(group.distances); + + var groups = this.groupsByInterval.get(group.distances); + if (groups != null) { + groups.remove(group); + if (groups.isEmpty()) { + this.groupsByInterval.remove(group.distances); + } else if (groups.size() <= ARRAY_SET_THRESHOLD) { + groups = new ReferenceArraySet<>(groups); + this.groupsByInterval.put(group.distances, groups); } } + } - // determine the buckets in which the existing group is - var existingBuckets = queryBuckets(group.minDistance, group.maxDistance); - - // determine the buckets in which the new group will be - Collection newBuckets; - if (accGroup.isRelevant()) { - // find the new buckets for this group and create new ones if necessary. - // determine how many buckets this group will be in - double groupFirstBucketIndex = Math.floor(accGroupMinDistance / this.bucketLength); - double groupSecondBucketIndex = Math.floor(accGroupMaxDistance / this.bucketLength); - double groupFirstStartDistance = groupFirstBucketIndex * this.bucketLength; - double groupSecondStartDistance = groupSecondBucketIndex * this.bucketLength; - double groupSecondEndDistance = groupSecondStartDistance + this.bucketLength; - int neededBuckets = (int) (groupSecondBucketIndex - groupFirstBucketIndex + 1); - - newBuckets = queryBuckets(groupFirstStartDistance, groupSecondEndDistance); + private void addGroupInterval(Group group) { + this.groupIntervals.add(group.distances); - int newBucketCount = newBuckets.size(); - if (newBucketCount < neededBuckets) { - // create the missing buckets - if (neededBuckets == 1) { - // one bucket, groupStartBucketIndex == groupEndBucketIndex - newBuckets = Collections.singleton(createBucketAt(groupFirstStartDistance)); - } else if (newBucketCount == 0) { - // create two new buckets, one for the start and one for the end - var startBucket = createBucketAt(groupFirstStartDistance); - var endBucket = createBucketAt(groupSecondStartDistance); - newBuckets = List.of(startBucket, endBucket); - } else { - // one of the buckets is missing, find out which one and create it - // if only one bucket is needed but none were found, then the same process is - // ok, since groupSecondStartDistance == groupFirstStartDistance - var existingBucket = newBuckets.iterator().next(); - var missingBucketStartDistance = existingBucket.startDistance == groupFirstStartDistance - ? groupSecondStartDistance - : groupFirstStartDistance; - newBuckets = Collections.singleton(createBucketAt(missingBucketStartDistance)); - } - } - } else { - // use an empty set of new buckets to remove the group from all buckets - // if it is irrelevant (meaning it has none or only one face plane distance) - newBuckets = Collections.emptySet(); + var groups = this.groupsByInterval.get(group.distances); + if (groups == null) { + groups = new ReferenceArraySet<>(); + this.groupsByInterval.put(group.distances, groups); + } else if (groups.size() >= HASH_SET_THRESHOLD) { + groups = new ReferenceLinkedOpenHashSet<>(groups); + this.groupsByInterval.put(group.distances, groups); } + groups.add(group); + } - // go through the collected buckets (of which there can be at most two) - // and process additions/removals of the group in both buckets - var allBuckets = new ReferenceArraySet(2); - allBuckets.addAll(existingBuckets); - allBuckets.addAll(newBuckets); - for (Bucket bucket : allBuckets) { - var bucketPrevStartBoundary = bucket.getStartBoundary(); - var bucketPrevEndBoundary = bucket.getEndBoundary(); + boolean hasSection(long chunkSectionLongPos) { + return this.groupsBySection.containsKey(chunkSectionLongPos); + } + + boolean isEmpty() { + return this.groupsBySection.isEmpty(); + } - boolean inExisting = existingBuckets.contains(bucket); - if (newBuckets.contains(bucket)) { - if (inExisting) { - bucket.updateGroupRange(group, accGroup, accGroupMinDistance, accGroupMaxDistance); - } else { - bucket.addNewGroup(group); - } - } else if (inExisting) { - bucket.removeGroup(group); + void addSection(AccumulationGroup accGroup, long chunkSectionLongPos) { + ChunkSectionPos pos = accGroup.sectionPos; + double baseDistance = accGroup.normal.dot(pos.getMinX(), pos.getMinY(), pos.getMinZ()); + DoubleInterval accGroupDistances = accGroup.getDistanceInterval(baseDistance); - // remove buckets using their previous distance range because the bucket has - // already updates its own boundaries (but those aren't the ones used in the - // tree) - if (bucket.isEmpty()) { - this.bucketRanges.remove(bucketPrevStartBoundary); - this.bucketRanges.remove(bucketPrevEndBoundary); + var group = new Group(accGroup, accGroupDistances, baseDistance); - // prevent re-adding the bucket when its range is updated in the tree later - continue; - } - } else { - throw new RuntimeException("bucketChange called but group is neither in existing nor in new bucket"); - } + this.groupsBySection.put(chunkSectionLongPos, group); + addGroupInterval(group); + } - // since bucket min/max distances can extend beyond the bucket boundaries - // make sure to limit this using their actual boundaries. - // this ensures the invariant that buckets don't overlap is maintained. - double bucketNewStartBoundary = bucket.getStartBoundary(); - if (bucketNewStartBoundary != bucketPrevStartBoundary) { - this.bucketRanges.remove(bucketPrevStartBoundary); - this.bucketRanges.put(bucketNewStartBoundary, bucket); - } - double bucketNewEndBoundary = bucket.getEndBoundary(); - if (bucketNewEndBoundary != bucketPrevEndBoundary) { - this.bucketRanges.remove(bucketPrevEndBoundary); - this.bucketRanges.put(bucketNewEndBoundary, bucket); - } + void removeSection(long chunkSectionLongPos) { + Group group = this.groupsBySection.remove(chunkSectionLongPos); + if (group != null) { + removeGroupInterval(group); } + } - // if the group is new, then it won't be removed from all buckets - // it also doesn't need to be replaced with updated data - if (!groupIsNew) { - // entirely remove the group if it has been removed from all buckets - // this means it no longer needs to trigger at all - if (newBuckets.isEmpty()) { - this.groups.remove(pos); - } else { - // replace the group with the new data from accGroup - // up until this point the group is unchanged - group.replaceWith(accGroup, accGroupMinDistance, accGroupMaxDistance, baseDistance); - } + void updateSection(AccumulationGroup accGroup, long chunkSectionLongPos) { + ChunkSectionPos pos = accGroup.sectionPos; + double baseDistance = accGroup.normal.dot(pos.getMinX(), pos.getMinY(), pos.getMinZ()); + DoubleInterval accGroupDistances = accGroup.getDistanceInterval(baseDistance); + + Group group = this.groupsBySection.get(chunkSectionLongPos); + + // this is just a heuristic, but it assumes that if the size, bounds and + // hash are equal, they are most likely the same. We also know that the existing + // and new data is for the same section position since the group was retrieved + // from the map for the right position. + // TODO: how common are collisions and are they bad? + // If they are common, use second hash + if (group.facePlaneDistances.size() == accGroup.relativeDistances.size() + && group.distances.equals(accGroupDistances) + && group.relDistanceHash == accGroup.relDistanceHash) { + // don't update if they are the same + return; } - } - boolean isEmpty() { - return this.groups.isEmpty(); + removeGroupInterval(group); + group.replaceWith(accGroup, accGroupDistances, baseDistance); + addGroupInterval(group); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinBakedQuad.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinBakedQuad.java index f35fe150ad..bc69e8962f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinBakedQuad.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinBakedQuad.java @@ -43,9 +43,9 @@ public abstract class MixinBakedQuad implements BakedQuadView { private int flags; private int normal; - private float normX; - private float normY; - private float normZ; + private int normX; + private int normY; + private int normZ; private ModelQuadFacing normalFace; @Inject(method = "", at = @At("RETURN")) @@ -88,22 +88,22 @@ public int getNormal() { } @Override - public float getNormX() { + public int getNormX() { return this.normX; } @Override - public float getNormY() { + public int getNormY() { return this.normY; } @Override - public float getNormZ() { + public int getNormZ() { return this.normZ; } @Override - public void setAccurateNormal(float x, float y, float z) { + public void setAccurateNormal(int x, int y, int z) { this.normX = x; this.normY = y; this.normZ = z; From b772e0acc2986f7b8a779d1bc99593405a04b9e1 Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 22 Jul 2023 00:00:21 +0200 Subject: [PATCH 003/256] move gfni instance to render section manager --- .../sodium/client/render/SodiumWorldRenderer.java | 7 ++----- .../client/render/chunk/RenderSectionManager.java | 10 ++++++++-- .../mods/sodium/client/render/chunk/gfni/GFNI.java | 13 +++---------- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index e0f53a5b1a..829cb34b33 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -11,7 +11,6 @@ import me.jellysquid.mods.sodium.client.render.chunk.ChunkTracker; import me.jellysquid.mods.sodium.client.render.chunk.RenderSectionManager; import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderData; -import me.jellysquid.mods.sodium.client.render.chunk.gfni.GFNI; import me.jellysquid.mods.sodium.client.util.NativeBuffer; import me.jellysquid.mods.sodium.client.util.frustum.Frustum; import me.jellysquid.mods.sodium.client.world.WorldRendererExtended; @@ -51,7 +50,6 @@ public class SodiumWorldRenderer { private RenderSectionManager renderSectionManager; private ChunkTracker chunkTracker; - private GFNI gfni; /** * @return The SodiumWorldRenderer based on the current dimension @@ -176,7 +174,7 @@ public void updateChunks(Camera camera, Frustum frustum, @Deprecated(forRemoval pitch != this.lastCameraPitch || yaw != this.lastCameraYaw || fogDistance != this.lastFogDistance; if (cameraLocationChanged) { - gfni.processMovement(lastCameraX, lastCameraY, lastCameraZ, pos.x, pos.y, pos.z); + this.renderSectionManager.processGFNIMovement(lastCameraX, lastCameraY, lastCameraZ, pos.x, pos.y, pos.z); } if (dirty) { this.renderSectionManager.markGraphDirty(); @@ -241,8 +239,7 @@ private void initRenderer(CommandList commandList) { this.renderDistance = this.client.options.getClampedViewDistance(); - this.gfni = new GFNI(); - this.renderSectionManager = new RenderSectionManager(this, this.world, this.gfni, this.renderDistance, commandList); + this.renderSectionManager = new RenderSectionManager(this, this.world, this.renderDistance, commandList); this.renderSectionManager.reloadChunks(this.chunkTracker); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index 471f4ac275..15f9797229 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -106,12 +106,12 @@ public class RenderSectionManager { private ChunkRenderList chunkRenderList; - public RenderSectionManager(SodiumWorldRenderer worldRenderer, ClientWorld world, GFNI gfni, int renderDistance, CommandList commandList) { + public RenderSectionManager(SodiumWorldRenderer worldRenderer, ClientWorld world, int renderDistance, CommandList commandList) { this.chunkRenderer = new RegionChunkRenderer(RenderDevice.INSTANCE, ChunkMeshFormats.COMPACT); this.worldRenderer = worldRenderer; this.world = world; - this.gfni = gfni; + this.gfni = new GFNI(); this.builder = new ChunkBuilder(ChunkMeshFormats.COMPACT); this.builder.init(world); @@ -441,6 +441,12 @@ public ChunkRenderBuildTask createRebuildTask(RenderSection render) { return new ChunkRenderRebuildTask(render, context, this.gfni, frame); } + public void processGFNIMovement( + double lastCameraX, double lastCameraY, double lastCameraZ, + double cameraX, double cameraY, double cameraZ) { + this.gfni.processMovement(lastCameraX, lastCameraY, lastCameraZ, cameraX, cameraY, cameraZ); + } + public void markGraphDirty() { this.needsUpdate = true; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java index 2dc44bf94e..fe83879524 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java @@ -28,9 +28,10 @@ * lists are created (and possibly deleted) on demand, this would require a more * complex synchronization scheme. * - * TODO: destory functionality similar to RenderSectionManger's destroy method? + * Maximum add/update and remove durations are 0.4ms and 0.06ms respectively in + * a 32rd world with around 230 normal lists. * - * TODO: does teleporting and switching dimensions work? + * TODO: destory functionality similar to RenderSectionManger's destroy method? */ public class GFNI { /** @@ -81,7 +82,6 @@ private void removeSectionFromList(NormalList normalList, long chunkSectionLongP } public void removeSection(long chunkSectionLongPos) { - var startTime = Instant.now(); int normalListCount = this.normalLists.size(); for (var normalList : this.normalLists.values()) { @@ -92,9 +92,6 @@ public void removeSection(long chunkSectionLongPos) { if (normalListCount != this.normalLists.size()) { System.out.println(normalLists.size() + " normal lists"); } - var duration = Duration.between(startTime, Instant.now()); - System.out.println("Processed section removal in " + (float) duration.toNanos() / 1_000_000 + " ms"); - } private void addSectionInNewNormalLists(AccumulationGroup accGroup) { @@ -117,8 +114,6 @@ public synchronized void integrateGroupBuilder(GroupBuilder builder) { return; } - var startTime = Instant.now(); - int normalListCount = this.normalLists.size(); // go through all normal lists and check against the normals that the group @@ -158,7 +153,5 @@ public synchronized void integrateGroupBuilder(GroupBuilder builder) { if (normalListCount != this.normalLists.size()) { System.out.println(normalLists.size() + " normal lists"); } - var duration = Duration.between(startTime, Instant.now()); - System.out.println("Processed section add/update in " + (float) duration.toNanos() / 1_000_000 + " ms"); } } From ae60fc7db4b5b833b17f4cb6cbf024c66debe065 Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 22 Jul 2023 00:17:42 +0200 Subject: [PATCH 004/256] rename methods for getting quantized normals --- .../mods/sodium/client/model/quad/ModelQuad.java | 8 ++++---- .../sodium/client/model/quad/ModelQuadView.java | 13 ++++++------- .../chunk/compile/pipeline/BlockRenderer.java | 2 +- .../chunk/compile/pipeline/FluidRenderer.java | 4 ++-- .../mods/sodium/client/render/chunk/gfni/GFNI.java | 14 +++++++++++--- .../sodium/mixin/core/pipeline/MixinBakedQuad.java | 10 +++++----- 6 files changed, 29 insertions(+), 22 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuad.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuad.java index 23d39b8994..e2edbd021a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuad.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuad.java @@ -125,22 +125,22 @@ public int getNormal() { } @Override - public int getNormX() { + public int getGFNINormX() { return this.normX; } @Override - public int getNormY() { + public int getGFNINormY() { return this.normY; } @Override - public int getNormZ() { + public int getGFNINormZ() { return this.normZ; } @Override - public void setAccurateNormal(int x, int y, int z) { + public void setGFNINormal(int x, int y, int z) { this.normX = x; this.normY = y; this.normZ = z; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java index 7ef18ed147..4e76884f08 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java @@ -2,7 +2,6 @@ import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFlags; import net.minecraft.client.texture.Sprite; -import net.minecraft.util.math.MathHelper; /** * Provides a read-only view of a model quad. For mutable access to a model quad, see {@link ModelQuadViewMutable}. @@ -61,17 +60,17 @@ public interface ModelQuadView { /** * @return The x coordinate of the unit normal vector */ - int getNormX(); + int getGFNINormX(); /** * @return The y coordinate of the unit normal vector */ - int getNormY(); + int getGFNINormY(); /** * @return The z coordinate of the unit normal vector */ - int getNormZ(); + int getGFNINormZ(); /** * Sets an accurate normal vector for this quad. This is used for GFNI. @@ -80,14 +79,14 @@ public interface ModelQuadView { * @param y The normal's y component * @param z The normal's z component */ - void setAccurateNormal(int x, int y, int z); + void setGFNINormal(int x, int y, int z); /** * Calculates the normal vector for this quad using the cross product of the * vertices. Ensures the normal vector returned by the getNorm methods is up to * date (and a unit vector). */ - default void calculateAccurateNormal() { + default void calculateGFNINormal() { final float x0 = getX(0); final float y0 = getY(0); final float z0 = getZ(0); @@ -123,7 +122,7 @@ default void calculateAccurateNormal() { normZ /= l; } - this.setAccurateNormal( + this.setGFNINormal( (int) (normX * 32), (int) (normY * 32), (int) (normZ * 32)); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java index 0f51c9aa55..412afc3129 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java @@ -157,7 +157,7 @@ private void writeGeometry(BlockRenderContext ctx, if (isTranslucent && dstIndex == 0) { if (normalFace == ModelQuadFacing.UNASSIGNED) { ctx.groupBuilder.addUnalignedFace( - quad.getNormX(), quad.getNormY(), quad.getNormZ(), + quad.getGFNINormX(), quad.getGFNINormY(), quad.getGFNINormZ(), out.x, out.y, out.z); } else { ctx.groupBuilder.addAlignedFace(normalFace, out.x, out.y, out.z); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java index 898c3ee196..0799151c45 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java @@ -407,9 +407,9 @@ private void writeQuad(ChunkModelBuilder builder, GroupBuilder groupBuilder, Chu if (isTranslucent && i == 0) { if (facing == ModelQuadFacing.UNASSIGNED) { - quad.calculateAccurateNormal(); + quad.calculateGFNINormal(); groupBuilder.addUnalignedFace( - quad.getNormX(), quad.getNormY(), quad.getNormZ(), + quad.getGFNINormX(), quad.getGFNINormY(), quad.getGFNINormZ(), out.x, out.y, out.z); } else { groupBuilder.addAlignedFace(facing, out.x, out.y, out.z); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java index fe83879524..e15217b19a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java @@ -15,8 +15,6 @@ * * Distances are stored as doubles and normals are stored as float vectors. * - * TODO: make Group and Bucket relative to use floats instead of doubles? - * * TODO: synchronization is used for integrating group builders submitted from * chunk build threads. It is assumed that integrating a group builder is fast * and thus synchronization is not a big problem. However, if it is, it might be @@ -31,7 +29,17 @@ * Maximum add/update and remove durations are 0.4ms and 0.06ms respectively in * a 32rd world with around 230 normal lists. * - * TODO: destory functionality similar to RenderSectionManger's destroy method? + * TODO: + * - update GFNI document about how this implementation works with the + * interval tree and update the diagram. + * - do some benchmarking with spark to figure out if there are bottlenecks + * - filter the triggered sections by visibility in the frame (using the graph + * search result) + * - sort the triggered sections by camera distance and possibly also use number + * of translucent faces as a heuristic for importance + * - fix the quantization to actually convert to polar form and back? just + * quanitzing the normal components generates more different normals than + * necessary */ public class GFNI { /** diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinBakedQuad.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinBakedQuad.java index bc69e8962f..aa90ecc9d8 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinBakedQuad.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinBakedQuad.java @@ -50,7 +50,7 @@ public abstract class MixinBakedQuad implements BakedQuadView { @Inject(method = "", at = @At("RETURN")) private void init(int[] vertexData, int colorIndex, Direction face, Sprite sprite, boolean shade, CallbackInfo ci) { - this.calculateAccurateNormal(); + this.calculateGFNINormal(); this.normal = NormI8.pack(this.normX, this.normY, this.normZ); this.normalFace = ModelQuadUtil.findNormalFace(this.normal); @@ -88,22 +88,22 @@ public int getNormal() { } @Override - public int getNormX() { + public int getGFNINormX() { return this.normX; } @Override - public int getNormY() { + public int getGFNINormY() { return this.normY; } @Override - public int getNormZ() { + public int getGFNINormZ() { return this.normZ; } @Override - public void setAccurateNormal(int x, int y, int z) { + public void setGFNINormal(int x, int y, int z) { this.normX = x; this.normY = y; this.normZ = z; From eb4fb8609c38ed8399e6efdc74b42aae674f22a1 Mon Sep 17 00:00:00 2001 From: douira Date: Tue, 25 Jul 2023 03:26:09 +0200 Subject: [PATCH 005/256] use cube surface normal quantization, fix normal handling in model quad view, added more sophisticated group builder discard heuristics --- .../sodium/client/model/quad/ModelQuad.java | 21 ++--- .../client/model/quad/ModelQuadView.java | 52 ++++++++---- .../chunk/compile/pipeline/BlockRenderer.java | 10 ++- .../chunk/compile/pipeline/FluidRenderer.java | 13 ++- .../sodium/client/render/chunk/gfni/GFNI.java | 27 +++--- .../client/render/chunk/gfni/Group.java | 6 +- .../render/chunk/gfni/GroupBuilder.java | 84 ++++++++++++++++++- .../client/render/chunk/gfni/NormalList.java | 4 +- .../mixin/core/pipeline/MixinBakedQuad.java | 24 +++--- 9 files changed, 175 insertions(+), 66 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuad.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuad.java index e2edbd021a..f298e8338d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuad.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuad.java @@ -5,7 +5,8 @@ import static me.jellysquid.mods.sodium.client.util.ModelQuadUtil.*; /** - * A simple implementation of the {@link ModelQuadViewMutable} interface which can provide an on-heap scratch area + * A simple implementation of the {@link ModelQuadViewMutable} interface which + * can provide an on-heap scratch area * for storing quad vertex data. */ public class ModelQuad implements ModelQuadViewMutable { @@ -15,9 +16,9 @@ public class ModelQuad implements ModelQuadViewMutable { private Sprite sprite; private int colorIdx; private int normal; - private int normX; - private int normY; - private int normZ; + private int GFNINormX; + private int GFNINormY; + private int GFNINormZ; @Override public void setX(int idx, float x) { @@ -126,23 +127,23 @@ public int getNormal() { @Override public int getGFNINormX() { - return this.normX; + return this.GFNINormX; } @Override public int getGFNINormY() { - return this.normY; + return this.GFNINormY; } @Override public int getGFNINormZ() { - return this.normZ; + return this.GFNINormZ; } @Override public void setGFNINormal(int x, int y, int z) { - this.normX = x; - this.normY = y; - this.normZ = z; + this.GFNINormX = x; + this.GFNINormY = y; + this.GFNINormZ = z; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java index 4e76884f08..e30f5313de 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java @@ -1,10 +1,13 @@ package me.jellysquid.mods.sodium.client.model.quad; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFlags; +import me.jellysquid.mods.sodium.client.render.chunk.gfni.GFNI; +import net.caffeinemc.mods.sodium.api.util.NormI8; import net.minecraft.client.texture.Sprite; /** - * Provides a read-only view of a model quad. For mutable access to a model quad, see {@link ModelQuadViewMutable}. + * Provides a read-only view of a model quad. For mutable access to a model + * quad, see {@link ModelQuadViewMutable}. */ public interface ModelQuadView { /** @@ -38,7 +41,8 @@ public interface ModelQuadView { float getTexV(int idx); /** - * @return The integer bit flags containing the {@link ModelQuadFlags} for this quad + * @return The integer bit flags containing the {@link ModelQuadFlags} for this + * quad */ int getFlags(); @@ -81,12 +85,7 @@ public interface ModelQuadView { */ void setGFNINormal(int x, int y, int z); - /** - * Calculates the normal vector for this quad using the cross product of the - * vertices. Ensures the normal vector returned by the getNorm methods is up to - * date (and a unit vector). - */ - default void calculateGFNINormal() { + default int calculateNormals(boolean calculateUnitNormal) { final float x0 = getX(0); final float y0 = getY(0); final float z0 = getZ(0); @@ -114,18 +113,37 @@ default void calculateGFNINormal() { float normY = dz0 * dx1 - dx0 * dz1; float normZ = dx0 * dy1 - dy0 * dx1; - float l = (float) Math.sqrt(normX * normX + normY * normY + normZ * normZ); + int packedNormal = -1; + if (calculateUnitNormal) { + // normalize by length for the packed normal + float length = (float) Math.sqrt(normX * normX + normY * normY + normZ * normZ); + if (length != 0.0 && length != 1.0) { + normX /= length; + normY /= length; + normZ /= length; + } + + packedNormal = NormI8.pack(normX, normY, normZ); + } - if (l != 0 && l != 1) { - normX /= l; - normY /= l; - normZ /= l; + // normalize onto the surface of a cube by dividing by the length of the longest + // component + float infNormLength = Math.max(Math.abs(normX), Math.max(Math.abs(normY), Math.abs(normZ))); + if (infNormLength != 0 && infNormLength != 1) { + normX /= infNormLength; + normY /= infNormLength; + normZ /= infNormLength; } - this.setGFNINormal( - (int) (normX * 32), - (int) (normY * 32), - (int) (normZ * 32)); + // quantize the coordinates on the surface of the cube. + // in each axis the number of values is 2 * QUANTIZATION_FACTOR + 1. + // the total number of normals is the number of points on that cube's surface. + setGFNINormal( + (int) (normX * GFNI.QUANTIZATION_FACTOR), + (int) (normY * GFNI.QUANTIZATION_FACTOR), + (int) (normZ * GFNI.QUANTIZATION_FACTOR)); + + return packedNormal; } default boolean hasColor() { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java index 412afc3129..8dd51439f6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java @@ -154,13 +154,17 @@ private void writeGeometry(BlockRenderContext ctx, out.y = ctx.origin().y() + quad.getY(srcIndex) + (float) offset.getY(); out.z = ctx.origin().z() + quad.getZ(srcIndex) + (float) offset.getZ(); - if (isTranslucent && dstIndex == 0) { + if (isTranslucent) { if (normalFace == ModelQuadFacing.UNASSIGNED) { - ctx.groupBuilder.addUnalignedFace( + if (dstIndex == 0) { + ctx.groupBuilder.addUnalignedFace( quad.getGFNINormX(), quad.getGFNINormY(), quad.getGFNINormZ(), out.x, out.y, out.z); - } else { + } + } else if (dstIndex == 0) { ctx.groupBuilder.addAlignedFace(normalFace, out.x, out.y, out.z); + } else { + ctx.groupBuilder.updateAlignedBounds(out.x, out.y, out.z); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java index 0799151c45..a23672023f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java @@ -405,14 +405,19 @@ private void writeQuad(ChunkModelBuilder builder, GroupBuilder groupBuilder, Chu out.y = offset.getY() + quad.getY(i); out.z = offset.getZ() + quad.getZ(i); - if (isTranslucent && i == 0) { + if (isTranslucent) { if (facing == ModelQuadFacing.UNASSIGNED) { - quad.calculateGFNINormal(); - groupBuilder.addUnalignedFace( + if (i == 0) { + // calculate the current GFNI normal but not the unit normal + quad.calculateNormals(false); + groupBuilder.addUnalignedFace( quad.getGFNINormX(), quad.getGFNINormY(), quad.getGFNINormZ(), out.x, out.y, out.z); - } else { + } + } else if (i == 0) { groupBuilder.addAlignedFace(facing, out.x, out.y, out.z); + } else { + groupBuilder.updateAlignedBounds(out.x, out.y, out.z); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java index e15217b19a..6eb072b623 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java @@ -1,8 +1,5 @@ package me.jellysquid.mods.sodium.client.render.chunk.gfni; -import java.time.Duration; -import java.time.Instant; - import org.joml.Vector3fc; import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; @@ -29,19 +26,25 @@ * Maximum add/update and remove durations are 0.4ms and 0.06ms respectively in * a 32rd world with around 230 normal lists. * + * It triggers 600 sections for normal (0, 1, 0) at distance + * 62.88788890838623 in a 32rd world because of flooded caves that make the + * ocean surface heuristic not work. The distance being triggered on is the + * overworld water surface height. Flooded caves have water surfaces below solid + * blocks above the water source blocks. + * * TODO: * - update GFNI document about how this implementation works with the * interval tree and update the diagram. - * - do some benchmarking with spark to figure out if there are bottlenecks * - filter the triggered sections by visibility in the frame (using the graph * search result) * - sort the triggered sections by camera distance and possibly also use number * of translucent faces as a heuristic for importance - * - fix the quantization to actually convert to polar form and back? just - * quanitzing the normal components generates more different normals than - * necessary + * - baked models could possibly precompute normals and then just calculate + * distances when processing a chunk? */ public class GFNI { + public static final int QUANTIZATION_FACTOR = 4; + /** * A map of all the normal lists, indexed by their normal. */ @@ -53,11 +56,12 @@ public class GFNI { * normal lists. */ ObjectOpenHashSet triggeredSections = new ObjectOpenHashSet<>(50); + ObjectOpenHashSet triggeredNormals = new ObjectOpenHashSet<>(50); // TODO: for debugging public void processMovement(double lastCameraX, double lastCameraY, double lastCameraZ, double cameraX, double cameraY, double cameraZ) { - var startTime = Instant.now(); triggeredSections.clear(); + triggeredNormals.clear(); for (var normalList : this.normalLists.values()) { normalList.processMovement(this, lastCameraX, lastCameraY, lastCameraZ, cameraX, cameraY, cameraZ); @@ -72,14 +76,11 @@ public void processMovement(double lastCameraX, double lastCameraY, double lastC System.out.println(section.getX() + " " + section.getY() + " " + section.getZ()); } } - - // TODO: remove - var duration = Duration.between(startTime, Instant.now()); - System.out.println("Processed movement in " + (float) duration.toNanos() / 1_000_000 + " ms"); } - void triggerSection(ChunkSectionPos section) { + void triggerSection(ChunkSectionPos section, Vector3fc normal) { this.triggeredSections.add(section); + this.triggeredNormals.add(normal); } private void removeSectionFromList(NormalList normalList, long chunkSectionLongPos) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java index 9ffca1f23b..11646ba22c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java @@ -1,5 +1,7 @@ package me.jellysquid.mods.sodium.client.render.chunk.gfni; +import org.joml.Vector3fc; + import com.lodborg.intervaltree.DoubleInterval; import it.unimi.dsi.fastutil.doubles.DoubleAVLTreeSet; @@ -50,11 +52,11 @@ void replaceWith(AccumulationGroup accGroup, DoubleInterval accGroupDistances, d } } - void triggerRange(GFNI gfni, double start, double end) { + void triggerRange(GFNI gfni, double start, double end, Vector3fc normal) { // trigger self on the section if the query range overlaps with the group if (start < this.distances.getEnd() && end > this.distances.getStart() && !this.facePlaneDistances.subSet(start, end).isEmpty()) { - gfni.triggerSection(this.sectionPos); + gfni.triggerSection(this.sectionPos, normal); } } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java index fd799bbbef..1693587371 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java @@ -21,6 +21,9 @@ public class GroupBuilder { final ChunkSectionPos sectionPos; private int facePlaneCount = 0; + private int alignedNormalBitmap = 0; + private Vector3f minBounds = new Vector3f(16, 16, 16); + private Vector3f maxBounds = new Vector3f(0, 0, 0); public GroupBuilder(ChunkSectionPos sectionPos) { this.sectionPos = sectionPos; @@ -41,11 +44,24 @@ public void addAlignedFace(ModelQuadFacing facing, float vertexX, float vertexY, if (distances == null) { distances = new AccumulationGroup(sectionPos, ALIGNED_NORMALS[index], index); this.axisAlignedDistances[index] = distances; + this.alignedNormalBitmap |= 1 << index; } addVertex(distances, vertexX, vertexY, vertexZ); } + public void updateAlignedBounds(float vertexX, float vertexY, float vertexZ) { + if (this.unalignedDistances == null) { + minBounds.x = Math.min(minBounds.x, vertexX); + minBounds.y = Math.min(minBounds.y, vertexY); + minBounds.z = Math.min(minBounds.z, vertexZ); + + maxBounds.x = Math.max(maxBounds.x, vertexX); + maxBounds.y = Math.max(maxBounds.y, vertexY); + maxBounds.z = Math.max(maxBounds.z, vertexZ); + } + } + public void addUnalignedFace(int normalX, int normalY, int normalZ, float vertexX, float vertexY, float vertexZ) { if (this.unalignedDistances == null) { @@ -92,9 +108,23 @@ AccumulationGroup getGroupForNormal(NormalList normalList) { } /** - * Checks if this group builder is relevant for translucency sort triggering. If - * there are no or only one normal, this builder can be considered practically - * empty. + * Checks if this group builder is relevant for translucency sort triggering. + * + * If there are no or only one normal, this builder can be considered + * practically empty. + * + * If there are two face planes with opposing normals at the same distance, then + * they can't be seen through each other and this section can be ignored. + * + * If the translucent faces are on the surface of the convex hull of all + * translucent faces in the section and face outwards, then there is no way to + * see one through the other. Since convex nulls are hard, a simpler case only + * uses the axis aligned normals: Under the condition that only aligned normals + * are used in the section, tracking the bounding box of the translucent + * geometry (the vertices) in the section and then checking if the normal + * distances line up with the bounding box allows the exclusion of some + * sections containing a single convex translucent cuboid (of which not all + * faces need to exist). * * More heuristics can be performed here to conservatively determine if this * section could possibly have more than one translucent sort order. @@ -102,6 +132,52 @@ AccumulationGroup getGroupForNormal(NormalList normalList) { * @return true if this group builder is relevant */ boolean isRelevant() { - return this.facePlaneCount > 1; + if (facePlaneCount <= 1) { + return false; + } + + if (this.unalignedDistances == null) { + // if there are just two normals, they are exact opposites of eachother and they + // each only have one distance, there is no way to see through one face to the + // other. + if (this.facePlaneCount == 2 + && (this.alignedNormalBitmap == 0b11 + || this.alignedNormalBitmap == 0b1100 + || this.alignedNormalBitmap == 0b110000)) { + return false; + } + + // the more complex test that checks for distances aligned with the bounding box + // of the geometry added to the group builder + if (this.facePlaneCount <= ModelQuadFacing.DIRECTIONS.length) { + boolean passesBoundingBoxTest = true; + for (AccumulationGroup accGroup : this.axisAlignedDistances) { + if (accGroup == null) { + continue; + } + + if (accGroup.relativeDistances.size() > 1) { + passesBoundingBoxTest = false; + break; + } + + // check the distance against the bounding box + float outwardBoundDistance = (accGroup.normal.x() < 0 + || accGroup.normal.y() < 0 + || accGroup.normal.z() < 0) + ? accGroup.normal.dot(minBounds) + : accGroup.normal.dot(maxBounds); + if (accGroup.relativeDistances.iterator().nextDouble() != outwardBoundDistance) { + passesBoundingBoxTest = false; + break; + } + } + if (passesBoundingBoxTest) { + return false; + } + } + } + + return true; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java index 615f0125a8..2dc616671c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java @@ -95,7 +95,7 @@ void processMovement(GFNI gfni, double lastCameraX, double lastCameraY, double l // stop if the movement is reverse with regards to the normal // since this means it's moving against the normal - if (start > end) { + if (start >= end) { return; } @@ -104,7 +104,7 @@ void processMovement(GFNI gfni, double lastCameraX, double lastCameraY, double l var interval = new DoubleInterval(start, end, Bounded.CLOSED); for (Interval groupInterval : groupIntervals.query(interval)) { for (Group group : groupsByInterval.get(groupInterval)) { - group.triggerRange(gfni, start, end); + group.triggerRange(gfni, start, end, this.normalf); } } } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinBakedQuad.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinBakedQuad.java index aa90ecc9d8..55a56016b9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinBakedQuad.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinBakedQuad.java @@ -3,6 +3,7 @@ import me.jellysquid.mods.sodium.client.model.quad.BakedQuadView; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFlags; +import me.jellysquid.mods.sodium.client.render.chunk.gfni.GFNI; import me.jellysquid.mods.sodium.client.util.ModelQuadUtil; import net.caffeinemc.mods.sodium.api.util.NormI8; import net.minecraft.client.render.model.BakedQuad; @@ -43,15 +44,16 @@ public abstract class MixinBakedQuad implements BakedQuadView { private int flags; private int normal; - private int normX; - private int normY; - private int normZ; + private int GFNINormX; + private int GFNINormY; + private int GFNINormZ; private ModelQuadFacing normalFace; @Inject(method = "", at = @At("RETURN")) private void init(int[] vertexData, int colorIndex, Direction face, Sprite sprite, boolean shade, CallbackInfo ci) { - this.calculateGFNINormal(); - this.normal = NormI8.pack(this.normX, this.normY, this.normZ); + // calculates the GFNI normal (side effect) and returns the packed unit normal + this.normal = calculateNormals(true); + this.normalFace = ModelQuadUtil.findNormalFace(this.normal); this.flags = ModelQuadFlags.getQuadFlags(this, face); @@ -89,24 +91,24 @@ public int getNormal() { @Override public int getGFNINormX() { - return this.normX; + return this.GFNINormX; } @Override public int getGFNINormY() { - return this.normY; + return this.GFNINormY; } @Override public int getGFNINormZ() { - return this.normZ; + return this.GFNINormZ; } @Override public void setGFNINormal(int x, int y, int z) { - this.normX = x; - this.normY = y; - this.normZ = z; + this.GFNINormX = x; + this.GFNINormY = y; + this.GFNINormZ = z; } @Override From 99c6e797faf0dd5b54e06d8c92a0e4bfc7b54cb1 Mon Sep 17 00:00:00 2001 From: douira Date: Tue, 25 Jul 2023 21:38:11 +0200 Subject: [PATCH 006/256] add another special case to the heuristic, avoids half the distances in cases of opposing normals and few face planes --- .../sodium/client/render/chunk/gfni/GFNI.java | 3 +- .../render/chunk/gfni/GroupBuilder.java | 66 ++++++++++++++++--- 2 files changed, 58 insertions(+), 11 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java index 6eb072b623..96f88ac029 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java @@ -118,7 +118,8 @@ public synchronized void integrateGroupBuilder(GroupBuilder builder) { long chunkSectionLongPos = builder.sectionPos.asLong(); // if the builder is irrelevant, remove it from the normal lists - if (!builder.isRelevant()) { + // if the builder is relevant, this may also simplify it as a side effect + if (!builder.calculateRelevanceAndSimplify()) { removeSection(chunkSectionLongPos); return; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java index 1693587371..98fa10bca7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java @@ -110,13 +110,14 @@ AccumulationGroup getGroupForNormal(NormalList normalList) { /** * Checks if this group builder is relevant for translucency sort triggering. * - * If there are no or only one normal, this builder can be considered + * A: If there are no or only one normal, this builder can be considered * practically empty. * - * If there are two face planes with opposing normals at the same distance, then + * B: If there are two face planes with opposing normals at the same distance, + * then * they can't be seen through each other and this section can be ignored. * - * If the translucent faces are on the surface of the convex hull of all + * C: If the translucent faces are on the surface of the convex hull of all * translucent faces in the section and face outwards, then there is no way to * see one through the other. Since convex nulls are hard, a simpler case only * uses the axis aligned normals: Under the condition that only aligned normals @@ -126,29 +127,47 @@ AccumulationGroup getGroupForNormal(NormalList normalList) { * sections containing a single convex translucent cuboid (of which not all * faces need to exist). * + * D1: If there are up to two normals with each up to two distances, then only + * the larger distance of each normal needs to be triggered on. + * + * TODO: However, for this to work, the initial sort needs to happen fully above + * or below both of the distances. Otherwise there can be cases where it's + * wrong. + * + * D2: More generally, if there are only two normals which are opposites of + * each other, then a special fixed sort order is always a correct sort order. + * This ordering sorts the two sets of face planes by their ascending + * normal-relative distance. The ordering between the two normals is irrelevant + * as they can't be seen through each other anyways. This case in includes case + * D1 and makes it unnecessary. Sections in D2 don't need to be triggered on at + * all. (not yet implemented since there is no sorting backend yet) + * * More heuristics can be performed here to conservatively determine if this * section could possibly have more than one translucent sort order. * * @return true if this group builder is relevant */ - boolean isRelevant() { - if (facePlaneCount <= 1) { + boolean calculateRelevanceAndSimplify() { + // special case A + if (this.facePlaneCount <= 1) { return false; } if (this.unalignedDistances == null) { + boolean twoOpposingNormals = this.alignedNormalBitmap == 0b11 + || this.alignedNormalBitmap == 0b1100 + || this.alignedNormalBitmap == 0b110000; + + // special case B // if there are just two normals, they are exact opposites of eachother and they // each only have one distance, there is no way to see through one face to the // other. - if (this.facePlaneCount == 2 - && (this.alignedNormalBitmap == 0b11 - || this.alignedNormalBitmap == 0b1100 - || this.alignedNormalBitmap == 0b110000)) { + if (this.facePlaneCount == 2 && twoOpposingNormals) { return false; } + // special case C // the more complex test that checks for distances aligned with the bounding box - // of the geometry added to the group builder if (this.facePlaneCount <= ModelQuadFacing.DIRECTIONS.length) { boolean passesBoundingBoxTest = true; for (AccumulationGroup accGroup : this.axisAlignedDistances) { @@ -176,6 +195,33 @@ boolean isRelevant() { return false; } } + + // special case D1 + if (this.facePlaneCount <= 2 || this.facePlaneCount <= 4 && twoOpposingNormals) { + // remove the lesser distance of each normal, even if it only has one + for (AccumulationGroup accGroup : this.axisAlignedDistances) { + if (accGroup == null) { + continue; + } + + var distanceIterator = accGroup.relativeDistances.iterator(); + var lesserDistance = distanceIterator.nextDouble(); + if (distanceIterator.hasNext()) { + lesserDistance = Math.min(lesserDistance, distanceIterator.nextDouble()); + } + accGroup.relativeDistances.remove(lesserDistance); + this.facePlaneCount--; + + if (accGroup.relativeDistances.isEmpty()) { + this.axisAlignedDistances[accGroup.groupBuilderKey] = null; + this.alignedNormalBitmap ^= 1 << accGroup.groupBuilderKey; + } + } + + // in case D1 the group will always still need sorting, just now less often. + // the case where the only remaining face plane is removed is handled in A. + return true; + } } return true; From 8a9303428c1bf18cf0c5412dca3f085ca012d838 Mon Sep 17 00:00:00 2001 From: douira Date: Thu, 27 Jul 2023 03:23:40 +0200 Subject: [PATCH 007/256] initial sorting implementation, very WIP, parts with varying levels of completion, sorting and task scheduling is implemented, handling of sort results and buffers is unclear, uploading is not implemented --- .../client/render/SodiumWorldRenderer.java | 16 +++-- .../client/render/chunk/ChunkUpdateType.java | 1 + .../client/render/chunk/RenderSection.java | 12 +++- .../render/chunk/RenderSectionManager.java | 41 +++++++++--- .../chunk/compile/ChunkBuildBuffers.java | 10 ++- .../chunk/compile/ChunkBuildContext.java | 3 +- .../chunk/compile/ChunkBuildResult.java | 24 ++----- .../chunk/compile/ChunkMeshBuildResult.java | 36 ++++++++++ .../chunk/compile/ChunkSortBuildResult.java | 31 +++++++++ .../render/chunk/data/ChunkRenderData.java | 13 +++- .../chunk/data/DynamicTranslucentData.java | 44 ++++++++++++ .../render/chunk/data/IndexedPrimitives.java | 57 ++++++++++++++++ .../chunk/data/StaticTranslucentData.java | 67 +++++++++++++++++++ .../render/chunk/data/TranslucentData.java | 36 ++++++++++ .../sodium/client/render/chunk/gfni/GFNI.java | 44 ++++++++---- .../render/chunk/gfni/GroupBuilder.java | 12 ++-- .../client/render/chunk/gfni/SortType.java | 37 ++++++++++ .../chunk/region/RenderRegionManager.java | 44 +++++++----- .../chunk/tasks/ChunkRenderBuildTask.java | 13 ++++ .../tasks/ChunkRenderEmptyBuildTask.java | 13 ++-- .../chunk/tasks/ChunkRenderRebuildTask.java | 39 ++++++++--- .../chunk/tasks/ChunkSortBuildTask.java | 27 ++++++++ .../format/impl/CompactChunkVertex.java | 4 ++ .../client/util/sorting/VertexSorters.java | 37 ++++++++++ 24 files changed, 569 insertions(+), 92 deletions(-) create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkMeshBuildResult.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortBuildResult.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/DynamicTranslucentData.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/IndexedPrimitives.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/StaticTranslucentData.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/TranslucentData.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/SortType.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkSortBuildTask.java diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index 4fb83dc6d9..7e047d1c32 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -176,16 +176,11 @@ public void updateChunks(Camera camera, Viewport viewport, @Deprecated(forRemova boolean dirty = cameraLocationChanged || pitch != this.lastCameraPitch || yaw != this.lastCameraYaw || fogDistance != this.lastFogDistance; - if (cameraLocationChanged) { - this.renderSectionManager.processGFNIMovement(lastCameraX, lastCameraY, lastCameraZ, pos.x, pos.y, pos.z); - } if (dirty) { this.renderSectionManager.markGraphDirty(); } - this.lastCameraX = pos.x; - this.lastCameraY = pos.y; - this.lastCameraZ = pos.z; + this.lastCameraPitch = pitch; this.lastCameraYaw = yaw; this.lastFogDistance = fogDistance; @@ -195,6 +190,15 @@ public void updateChunks(Camera camera, Viewport viewport, @Deprecated(forRemova this.chunkTracker.update(); this.renderSectionManager.updateChunks(); + if (cameraLocationChanged) { + profiler.swap("gfni_query"); + + this.renderSectionManager.processGFNIMovement(lastCameraX, lastCameraY, lastCameraZ, pos.x, pos.y, pos.z); + this.lastCameraX = pos.x; + this.lastCameraY = pos.y; + this.lastCameraZ = pos.z; + } + if (this.renderSectionManager.isGraphDirty()) { profiler.swap("chunk_graph_rebuild"); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkUpdateType.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkUpdateType.java index 547a376690..10e369a812 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkUpdateType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkUpdateType.java @@ -1,6 +1,7 @@ package me.jellysquid.mods.sodium.client.render.chunk; public enum ChunkUpdateType { + TRANSLUCENT_SORT(false), // the other types include a sort INITIAL_BUILD(false), REBUILD(false), IMPORTANT_REBUILD(true); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java index be4ebcb31a..7095374852 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java @@ -3,6 +3,7 @@ import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildResult; import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderData; +import me.jellysquid.mods.sodium.client.render.chunk.data.TranslucentData; import me.jellysquid.mods.sodium.client.render.chunk.graph.VisibilityEncoding; import me.jellysquid.mods.sodium.client.render.chunk.region.RenderRegion; import me.jellysquid.mods.sodium.client.render.texture.SpriteUtil; @@ -29,6 +30,7 @@ public class RenderSection { private final RenderSection[] adjacent = new RenderSection[DirectionUtil.ALL_DIRECTIONS.length]; private ChunkRenderData data = ChunkRenderData.ABSENT; + private TranslucentData translucentData; private CompletableFuture rebuildTask = null; private ChunkUpdateType pendingUpdate; @@ -88,6 +90,14 @@ public ChunkRenderData getData() { return this.data; } + public TranslucentData getTranslucentData() { + return this.translucentData; + } + + public void setTranslucentData(TranslucentData translucentData) { + this.translucentData = translucentData; + } + /** * Deletes all data attached to this render and drops any pending tasks. This should be used when the render falls * out of view or otherwise needs to be destroyed. After the render has been destroyed, the object can no longer @@ -243,7 +253,7 @@ public boolean canAcceptBuildResults(ChunkBuildResult result) { } public void onBuildFinished(ChunkBuildResult result) { - this.setData(result.data); + result.setDataOn(this); this.lastAcceptedBuildTime = result.buildTime; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index 8e75633e87..7f6a135fdd 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -23,6 +23,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.tasks.ChunkRenderBuildTask; import me.jellysquid.mods.sodium.client.render.chunk.tasks.ChunkRenderEmptyBuildTask; import me.jellysquid.mods.sodium.client.render.chunk.tasks.ChunkRenderRebuildTask; +import me.jellysquid.mods.sodium.client.render.chunk.tasks.ChunkSortBuildTask; import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkMeshFormats; import me.jellysquid.mods.sodium.client.render.viewport.Viewport; @@ -39,6 +40,7 @@ import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.ChunkSection; import org.apache.commons.lang3.Validate; +import org.joml.Vector3f; import java.util.*; import java.util.concurrent.CompletableFuture; @@ -69,7 +71,7 @@ public class RenderSectionManager { private final int renderDistance; private int effectiveRenderDistance; - private float cameraX, cameraY, cameraZ; + private Vector3f cameraPos = new Vector3f(); private int centerChunkX, centerChunkY, centerChunkZ; private boolean needsUpdate; @@ -130,9 +132,7 @@ public void update(Camera camera, Viewport viewport, int frame, boolean spectato private void setup(Camera camera) { Vec3d cameraPos = camera.getPos(); - this.cameraX = (float) cameraPos.x; - this.cameraY = (float) cameraPos.y; - this.cameraZ = (float) cameraPos.z; + this.cameraPos.set(cameraPos.x, cameraPos.y, cameraPos.z); var options = SodiumClientMod.options(); @@ -344,6 +344,7 @@ public void updateAllChunksNow() { private void updateChunks(boolean allImmediately) { var blockingFutures = new LinkedList>(); + this.submitRebuildTasks(ChunkUpdateType.TRANSLUCENT_SORT, blockingFutures); this.submitRebuildTasks(ChunkUpdateType.IMPORTANT_REBUILD, blockingFutures); this.submitRebuildTasks(ChunkUpdateType.INITIAL_BUILD, allImmediately ? blockingFutures : null); this.submitRebuildTasks(ChunkUpdateType.REBUILD, allImmediately ? blockingFutures : null); @@ -377,7 +378,13 @@ private void submitRebuildTasks(ChunkUpdateType filterType, LinkedList future; if (immediateFutures != null) { @@ -444,16 +451,22 @@ public ChunkRenderBuildTask createRebuildTask(RenderSection render) { int frame = this.currentFrame; if (context == null) { - return new ChunkRenderEmptyBuildTask(render, frame); + return new ChunkRenderEmptyBuildTask(render, frame, this.cameraPos); } - return new ChunkRenderRebuildTask(render, context, this.gfni, frame); + return new ChunkRenderRebuildTask(render, frame, this.cameraPos, context, this.gfni); + } + + public ChunkRenderBuildTask createSortTask(RenderSection render) { + return new ChunkSortBuildTask(render, this.currentFrame, this.cameraPos); } public void processGFNIMovement( double lastCameraX, double lastCameraY, double lastCameraZ, double cameraX, double cameraY, double cameraZ) { - this.gfni.processMovement(lastCameraX, lastCameraY, lastCameraZ, cameraX, cameraY, cameraZ); + this.gfni.findTriggeredSections(this::scheduleSort, + lastCameraX, lastCameraY, lastCameraZ, + cameraX, cameraY, cameraZ); } public void markGraphDirty() { @@ -495,6 +508,16 @@ public int getVisibleChunkCount() { return sections; } + public void scheduleSort(ChunkSectionPos pos) { + // TODO: Does this need to invalidate the section cache? + + RenderSection section = this.sectionByPosition.get(pos.asLong()); + + if (section != null) { + section.markForUpdate(ChunkUpdateType.TRANSLUCENT_SORT); + } + } + public void scheduleRebuild(int x, int y, int z, boolean important) { this.sectionCache.invalidate(x, y, z); @@ -512,7 +535,7 @@ public void scheduleRebuild(int x, int y, int z, boolean important) { } public boolean isChunkPrioritized(RenderSection render) { - return render.getSquaredDistance(this.cameraX, this.cameraY, this.cameraZ) <= NEARBY_CHUNK_DISTANCE; + return render.getSquaredDistance(this.cameraPos.x, this.cameraPos.y, this.cameraPos.z) <= NEARBY_CHUNK_DISTANCE; } public void onChunkRenderUpdates(int x, int y, int z, ChunkRenderData data) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildBuffers.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildBuffers.java index 450c3934fe..f2dad1cac4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildBuffers.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildBuffers.java @@ -59,7 +59,7 @@ public ChunkModelBuilder get(Material material) { * have been rendered to pass the finished meshes over to the graphics card. This function can be called multiple * times to return multiple copies. */ - public ChunkMeshData createMesh(TerrainRenderPass pass) { + public ChunkMeshData createMesh(TerrainRenderPass pass, boolean forceUnassigned) { var builder = this.builders.get(pass); List vertexBuffers = new ArrayList<>(); @@ -75,11 +75,17 @@ public ChunkMeshData createMesh(TerrainRenderPass pass) { } vertexBuffers.add(buffer.slice()); - vertexRanges.put(facing, new VertexRange(vertexCount, buffer.count())); + if (!forceUnassigned) { + vertexRanges.put(facing, new VertexRange(vertexCount, buffer.count())); + } vertexCount += buffer.count(); } + if (forceUnassigned) { + vertexRanges.put(ModelQuadFacing.UNASSIGNED, new VertexRange(0, vertexCount)); + } + if (vertexRanges.isEmpty()) { return null; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildContext.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildContext.java index ae8f7b36c9..936945a30c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildContext.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildContext.java @@ -1,7 +1,6 @@ package me.jellysquid.mods.sodium.client.render.chunk.compile; import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexType; -import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildBuffers; import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.BlockRenderCache; import net.minecraft.client.MinecraftClient; import net.minecraft.world.World; @@ -9,10 +8,12 @@ public class ChunkBuildContext { public final ChunkBuildBuffers buffers; public final BlockRenderCache cache; + public final ChunkVertexType vertexType; public ChunkBuildContext(World world, ChunkVertexType vertexType) { this.buffers = new ChunkBuildBuffers(vertexType); this.cache = new BlockRenderCache(MinecraftClient.getInstance(), world); + this.vertexType = vertexType; } public void release() { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildResult.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildResult.java index 4df9b0edda..de8e5fe462 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildResult.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildResult.java @@ -1,38 +1,22 @@ package me.jellysquid.mods.sodium.client.render.chunk.compile; -import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; -import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkMeshData; -import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderData; - -import java.util.Map; /** * The result of a chunk rebuild task which contains any and all data that needs to be processed or uploaded on * the main thread. If a task is cancelled after finishing its work and not before the result is processed, the result * will instead be discarded. */ -public class ChunkBuildResult { +public abstract class ChunkBuildResult { public final RenderSection render; - public final ChunkRenderData data; - public final Map meshes; public final int buildTime; - public ChunkBuildResult(RenderSection render, ChunkRenderData data, Map meshes, int buildTime) { + public ChunkBuildResult(RenderSection render, int buildTime) { this.render = render; - this.data = data; - this.meshes = meshes; this.buildTime = buildTime; } - public ChunkMeshData getMesh(TerrainRenderPass pass) { - return this.meshes.get(pass); - } + public abstract void setDataOn(RenderSection section); - public void delete() { - for (ChunkMeshData data : this.meshes.values()) { - data.getVertexData() - .free(); - } - } + public abstract void delete(); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkMeshBuildResult.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkMeshBuildResult.java new file mode 100644 index 0000000000..c82dc0d56d --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkMeshBuildResult.java @@ -0,0 +1,36 @@ +package me.jellysquid.mods.sodium.client.render.chunk.compile; + +import java.util.Map; + +import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; +import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkMeshData; +import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderData; +import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; + +public class ChunkMeshBuildResult extends ChunkBuildResult { + public final ChunkRenderData data; + public final Map meshes; + + public ChunkMeshBuildResult(RenderSection render, int buildTime, ChunkRenderData data, + Map meshes) { + super(render, buildTime); + this.data = data; + this.meshes = meshes; + } + + public ChunkMeshData getMesh(TerrainRenderPass pass) { + return this.meshes.get(pass); + } + + @Override + public void setDataOn(RenderSection section) { + section.setData(this.data); + } + + @Override + public void delete() { + for (ChunkMeshData data : this.meshes.values()) { + data.getVertexData().free(); + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortBuildResult.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortBuildResult.java new file mode 100644 index 0000000000..d0800365e7 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortBuildResult.java @@ -0,0 +1,31 @@ +package me.jellysquid.mods.sodium.client.render.chunk.compile; + +import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; +import me.jellysquid.mods.sodium.client.render.chunk.data.TranslucentData; + +/** + * TODO: is passing a result around explicitly necessary? Somehow we have to + * notify the system about an update to the change in index data, but if we + * store a reference to the TranslucentData on the render section, then setting + * it here would do nothing. Is it even permissible to modify the translucent + * data directly or does a copy have to be made? + */ +public class ChunkSortBuildResult extends ChunkBuildResult { + public final TranslucentData data; + + public ChunkSortBuildResult(RenderSection render, int buildTime, TranslucentData data) { + super(render, buildTime); + this.data = data; + } + + @Override + public void setDataOn(RenderSection section) { + // TODO: necessary? see note in class javadoc + section.setTranslucentData(this.data); + } + + @Override + public void delete() { + // TODO: necessary? only if there are native buffers involved + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderData.java index 713da7ef4c..aa95c124d0 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderData.java @@ -25,10 +25,15 @@ public class ChunkRenderData { private List globalBlockEntities; private List blockEntities; + private TranslucentData translucentData; private ChunkOcclusionData occlusionData; private List animatedSprites; + public TranslucentData getTranslucentData() { + return this.translucentData; + } + public ChunkOcclusionData getOcclusionData() { return this.occlusionData; } @@ -76,6 +81,7 @@ public static class Builder { private final List blockEntities = new ArrayList<>(); private final Set animatedSprites = new ObjectOpenHashSet<>(); + private TranslucentData translucentData; private ChunkOcclusionData occlusionData; public void addRenderPass(TerrainRenderPass pass) { @@ -106,6 +112,10 @@ public void addBlockEntity(BlockEntity entity, boolean cull) { (cull ? this.blockEntities : this.globalBlockEntities).add(entity); } + public void addTranslucentData(TranslucentData data) { + this.translucentData = data; + } + public ChunkRenderData build() { ChunkRenderData data = new ChunkRenderData(); data.globalBlockEntities = this.globalBlockEntities; @@ -113,6 +123,7 @@ public ChunkRenderData build() { data.occlusionData = this.occlusionData; data.animatedSprites = new ObjectArrayList<>(this.animatedSprites); data.blockRenderPasses = this.renderPasses; + data.translucentData = this.translucentData; return data; } @@ -127,4 +138,4 @@ private static ChunkRenderData createEmptyData() { return meshInfo.build(); } -} \ No newline at end of file +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/DynamicTranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/DynamicTranslucentData.java new file mode 100644 index 0000000000..fa1f9099bd --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/DynamicTranslucentData.java @@ -0,0 +1,44 @@ +package me.jellysquid.mods.sodium.client.render.chunk.data; + +import org.joml.Vector3f; + +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexType; +import me.jellysquid.mods.sodium.client.util.sorting.VertexSorters; + +public class DynamicTranslucentData implements TranslucentData { + private IndexedPrimitives data; + + public DynamicTranslucentData(ChunkVertexType vertexType, ChunkMeshData meshData) { + var buffer = meshData.getVertexData().getDirectBuffer(); + int primitiveCount = meshData.getVertexCount() / 4; // TODO: is it quads or triangles? + var vertexRange = meshData.getPart(ModelQuadFacing.UNASSIGNED); + this.data = new IndexedPrimitives(vertexType, buffer, vertexRange, primitiveCount); + } + + @Override + public Vector3f[] getCenters(ModelQuadFacing facing) { + if (facing != ModelQuadFacing.UNASSIGNED) { + throw new UnsupportedOperationException("Cannot get centers for facing other than UNASSIGNED"); + } + return this.data.centers; + } + + @Override + public int[] getIndexes(ModelQuadFacing facing) { + if (facing != ModelQuadFacing.UNASSIGNED) { + throw new UnsupportedOperationException("Cannot get indexes for facing other than UNASSIGNED"); + } + return this.data.indexes; + } + + @Override + public boolean isDynamic() { + return true; + } + + @Override + public void sort(Vector3f cameraPos) { + this.data.indexes = VertexSorters.sortByDistance(cameraPos).sort(this.data.centers); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/IndexedPrimitives.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/IndexedPrimitives.java new file mode 100644 index 0000000000..799091d435 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/IndexedPrimitives.java @@ -0,0 +1,57 @@ +package me.jellysquid.mods.sodium.client.render.chunk.data; + +import java.nio.ByteBuffer; + +import org.joml.Vector3f; + +import me.jellysquid.mods.sodium.client.gl.util.VertexRange; +import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexType; +import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.impl.CompactChunkVertex; + +public class IndexedPrimitives { + public final Vector3f[] centers; + public int[] indexes; + + public IndexedPrimitives( + ChunkVertexType vertexType, + ByteBuffer buffer, + VertexRange vertexRange, + int primitiveCount) { + this.centers = new Vector3f[primitiveCount]; + this.indexes = new int[primitiveCount]; + if (!(vertexType instanceof CompactChunkVertex)) { + throw new UnsupportedOperationException("Unknown vertex type: " + vertexType); + } + int vertexStride = vertexType.getVertexFormat().getStride(); + int primitiveStride = vertexStride * 4; // TODO: is it quads or triangles? + for (int i = 0; i < primitiveCount; i ++) { + // calculate the primitive center + int offset = i * primitiveStride + vertexRange.vertexStart(); + short x = buffer.getShort(offset + 0); + short y = buffer.getShort(offset + 2); + short z = buffer.getShort(offset + 4); + + offset += vertexStride; + x += buffer.getShort(offset + 0); + y += buffer.getShort(offset + 2); + z += buffer.getShort(offset + 4); + + offset += vertexStride; + x += buffer.getShort(offset + 0); + y += buffer.getShort(offset + 2); + z += buffer.getShort(offset + 4); + + offset += vertexStride; + x += buffer.getShort(offset + 0); + y += buffer.getShort(offset + 2); + z += buffer.getShort(offset + 4); + + float xCenter = CompactChunkVertex.decodePositionSum(x, 4); + float yCenter = CompactChunkVertex.decodePositionSum(y, 4); + float zCenter = CompactChunkVertex.decodePositionSum(z, 4); + + this.centers[i] = new Vector3f(xCenter, yCenter, zCenter); + this.indexes[i] = i; + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/StaticTranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/StaticTranslucentData.java new file mode 100644 index 0000000000..9380fa3701 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/StaticTranslucentData.java @@ -0,0 +1,67 @@ +package me.jellysquid.mods.sodium.client.render.chunk.data; + +import java.util.EnumMap; +import java.util.Map; + +import org.joml.Vector3f; + +import com.mojang.blaze3d.systems.VertexSorter; + +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexType; +import me.jellysquid.mods.sodium.client.util.sorting.VertexSorters; + +public class StaticTranslucentData implements TranslucentData { + private static final Map SORTERS = new EnumMap<>(ModelQuadFacing.class); + + static { + for (ModelQuadFacing facing : ModelQuadFacing.DIRECTIONS) { + SORTERS.put(facing, VertexSorters.sortByAxis(facing)); + } + } + + private final Map data = new EnumMap<>(ModelQuadFacing.class); + + public StaticTranslucentData(ChunkVertexType vertexType, ChunkMeshData meshData) { + var buffer = meshData.getVertexData().getDirectBuffer(); + int primitiveCount = meshData.getVertexCount() / 4; // TODO: is it quads or triangles? + + for (ModelQuadFacing facing : ModelQuadFacing.DIRECTIONS) { + var vertexRange = meshData.getPart(facing); + if (vertexRange != null) { + this.data.put(facing, new IndexedPrimitives(vertexType, buffer, vertexRange, primitiveCount)); + } + } + } + + @Override + public Vector3f[] getCenters(ModelQuadFacing facing) { + if (facing == ModelQuadFacing.UNASSIGNED) { + throw new UnsupportedOperationException("Cannot get centers for UNASSIGNED facing"); + } + return this.data.get(facing).centers; + } + + @Override + public int[] getIndexes(ModelQuadFacing facing) { + if (facing == ModelQuadFacing.UNASSIGNED) { + throw new UnsupportedOperationException("Cannot get indexes for UNASSIGNED facing"); + } + return this.data.get(facing).indexes; + } + + @Override + public boolean isDynamic() { + return false; + } + + @Override + public void sort(Vector3f cameraPos) { + for (ModelQuadFacing facing : ModelQuadFacing.DIRECTIONS) { + var dataForFacing = this.data.get(facing); + if (dataForFacing != null) { + dataForFacing.indexes = SORTERS.get(facing).sort(dataForFacing.centers); + } + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/TranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/TranslucentData.java new file mode 100644 index 0000000000..53239442e0 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/TranslucentData.java @@ -0,0 +1,36 @@ +package me.jellysquid.mods.sodium.client.render.chunk.data; + +import org.joml.Vector3f; + +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import me.jellysquid.mods.sodium.client.render.chunk.gfni.SortType; +import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexType; + +/** + * TODO: figure out if the encoded vertex data should be decoded or taken from + * the BlockRenderer directly without decoding the buffers. It would be less + * decoding work, but it would also be unnecessary in some cases where GFNI + * later decides that it's not necessary. + */ +public interface TranslucentData { + public static TranslucentData fromMeshData(ChunkVertexType vertexType, ChunkMeshData meshData, SortType sortType) { + switch (sortType) { + case NONE: + return null; + case STATIC_NORMAL_RELATIVE: + return new StaticTranslucentData(vertexType, meshData); + case DYNAMIC: + return new DynamicTranslucentData(vertexType, meshData); + default: + throw new UnsupportedOperationException("Unknown sort type: " + sortType); + } + } + + public Vector3f[] getCenters(ModelQuadFacing facing); + + public int[] getIndexes(ModelQuadFacing facing); + + public boolean isDynamic(); + + public void sort(Vector3f cameraPos); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java index 96f88ac029..a421adf692 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java @@ -1,8 +1,11 @@ package me.jellysquid.mods.sodium.client.render.chunk.gfni; +import java.util.function.Consumer; + import org.joml.Vector3fc; import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; +import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import net.minecraft.util.math.ChunkSectionPos; @@ -41,6 +44,11 @@ * of translucent faces as a heuristic for importance * - baked models could possibly precompute normals and then just calculate * distances when processing a chunk? + * - many sections can be marked as needing an update but they are only actually + * scheduled for sorting when the RenderSectionManager makes them visible. This + * may result in many sections suddenly needing sorting when the camera moves. + * Maybe it's better to schedule them to be sorted gradually even if not + * visible, if there are idle threads. */ public class GFNI { public static final int QUANTIZATION_FACTOR = 4; @@ -50,25 +58,25 @@ public class GFNI { */ private Object2ReferenceOpenHashMap normalLists = new Object2ReferenceOpenHashMap<>(50); - /** - * A temporary set of sections that were triggered during movement. A set is - * needed because the same section can be triggered multiple times by different - * normal lists. - */ - ObjectOpenHashSet triggeredSections = new ObjectOpenHashSet<>(50); - ObjectOpenHashSet triggeredNormals = new ObjectOpenHashSet<>(50); // TODO: for debugging + private Consumer triggerSectionCallback; + + // TODO: both of these are for debugging + ObjectLinkedOpenHashSet triggeredSections = new ObjectLinkedOpenHashSet<>(50); + ObjectOpenHashSet triggeredNormals = new ObjectOpenHashSet<>(50); - public void processMovement(double lastCameraX, double lastCameraY, double lastCameraZ, + public void findTriggeredSections( + Consumer triggerSectionCallback, + double lastCameraX, double lastCameraY, double lastCameraZ, double cameraX, double cameraY, double cameraZ) { triggeredSections.clear(); triggeredNormals.clear(); + this.triggerSectionCallback = triggerSectionCallback; for (var normalList : this.normalLists.values()) { normalList.processMovement(this, lastCameraX, lastCameraY, lastCameraZ, cameraX, cameraY, cameraZ); } - // TODO: do something with the triggered sections - // for now just log the amount + // TODO: the collections for tracking sections are only used for debugging int triggerCount = this.triggeredSections.size(); if (triggerCount > 0) { System.out.println("Triggered " + triggerCount + " sections"); @@ -76,11 +84,18 @@ public void processMovement(double lastCameraX, double lastCameraY, double lastC System.out.println(section.getX() + " " + section.getY() + " " + section.getZ()); } } + + triggerSectionCallback = null; } void triggerSection(ChunkSectionPos section, Vector3fc normal) { this.triggeredSections.add(section); this.triggeredNormals.add(normal); + + // by simply setting a chunk update type on the section, it naturally only gets + // updated once the section becomes visible. + // by definition, all sections in GFNI have SortType.DYNAMIC + this.triggerSectionCallback.accept(section); } private void removeSectionFromList(NormalList normalList, long chunkSectionLongPos) { @@ -114,14 +129,15 @@ private void addSectionInNewNormalLists(AccumulationGroup accGroup) { } // TODO: synchronized because it's expected to be fast, see class comment - public synchronized void integrateGroupBuilder(GroupBuilder builder) { + public synchronized SortType integrateGroupBuilder(GroupBuilder builder) { long chunkSectionLongPos = builder.sectionPos.asLong(); // if the builder is irrelevant, remove it from the normal lists // if the builder is relevant, this may also simplify it as a side effect - if (!builder.calculateRelevanceAndSimplify()) { + SortType sortType = builder.getSortTypeAndSimplify(); + if (!sortType.needsDynamicSort) { removeSection(chunkSectionLongPos); - return; + return sortType; } int normalListCount = this.normalLists.size(); @@ -163,5 +179,7 @@ public synchronized void integrateGroupBuilder(GroupBuilder builder) { if (normalListCount != this.normalLists.size()) { System.out.println(normalLists.size() + " normal lists"); } + + return sortType; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java index 98fa10bca7..93f2bf7bc3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java @@ -147,10 +147,10 @@ AccumulationGroup getGroupForNormal(NormalList normalList) { * * @return true if this group builder is relevant */ - boolean calculateRelevanceAndSimplify() { + SortType getSortTypeAndSimplify() { // special case A if (this.facePlaneCount <= 1) { - return false; + return SortType.NONE; } if (this.unalignedDistances == null) { @@ -163,7 +163,7 @@ boolean calculateRelevanceAndSimplify() { // each only have one distance, there is no way to see through one face to the // other. if (this.facePlaneCount == 2 && twoOpposingNormals) { - return false; + return SortType.NONE; } // special case C @@ -192,7 +192,7 @@ boolean calculateRelevanceAndSimplify() { } } if (passesBoundingBoxTest) { - return false; + return SortType.NONE; } } @@ -220,10 +220,10 @@ boolean calculateRelevanceAndSimplify() { // in case D1 the group will always still need sorting, just now less often. // the case where the only remaining face plane is removed is handled in A. - return true; + return SortType.STATIC_NORMAL_RELATIVE; } } - return true; + return SortType.DYNAMIC; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/SortType.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/SortType.java new file mode 100644 index 0000000000..d08329e2bd --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/SortType.java @@ -0,0 +1,37 @@ +package me.jellysquid.mods.sodium.client.render.chunk.gfni; + +/** + * What type of sorting to use for a section. Calculated by a heuristic after + * building a section. + */ +public enum SortType { + /** + * No sorting is required and the sort order doesn't matter. + */ + NONE(false, false), + + /** + * There is only one sort order. No active sorting is required, but an initial + * sort where quads of each facing are sorted according to their distances in + * regard to their normal. + * + * Currently assumes that there are no UNASSIGNED quads present. If this + * changes, remove this note and adjust StaticTranslucentData and anything that + * reads from it to handle UNASSIGNED quads. + */ + STATIC_NORMAL_RELATIVE(true, false), + + /** + * There are multiple sort orders. Sorting is required every time GFNI triggers + * this section. + */ + DYNAMIC(true, true); + + public final boolean needsIndexBuffer; + public final boolean needsDynamicSort; + + private SortType(boolean needsIndexBuffer, boolean needsDynamicSort) { + this.needsIndexBuffer = needsIndexBuffer; + this.needsDynamicSort = needsDynamicSort; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java index 99f6aaf9f6..80b39553ee 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java @@ -14,7 +14,10 @@ import me.jellysquid.mods.sodium.client.render.chunk.ChunkGraphicsState; import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildResult; +import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkMeshBuildResult; import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkMeshData; +import me.jellysquid.mods.sodium.client.render.chunk.data.TranslucentData; + import org.jetbrains.annotations.NotNull; import java.util.*; @@ -64,21 +67,26 @@ public void upload(CommandList commandList, Iterator queue) { } private void upload(CommandList commandList, RenderRegion region, List results) { - List uploads = new ArrayList<>(); + List uploads = new ArrayList<>(); for (ChunkBuildResult result : results) { - for (TerrainRenderPass pass : DefaultTerrainRenderPasses.ALL) { - var storage = region.getStorage(pass); - - if (storage != null) { - storage.updateState(result.render, null); - } - - ChunkMeshData mesh = result.getMesh(pass); - - if (mesh != null) { - uploads.add(new PendingSectionUpload(result.render, mesh, pass, - new PendingUpload(mesh.getVertexData()))); + // TODO: missing support for sort results. how are those uploaded to the gpu? + // does the data need to be stuck into a buffer? + // Where are index buffers anyways? + if (result instanceof ChunkMeshBuildResult meshBuildResult) { + for (TerrainRenderPass pass : DefaultTerrainRenderPasses.ALL) { + var storage = region.getStorage(pass); + + if (storage != null) { + storage.updateState(result.render, null); + } + + ChunkMeshData mesh = meshBuildResult.getMesh(pass); + + if (mesh != null) { + uploads.add(new PendingSectionMeshUpload(meshBuildResult.render, mesh, pass, + new PendingUpload(mesh.getVertexData()))); + } } } } @@ -101,7 +109,7 @@ private void upload(CommandList commandList, RenderRegion region, List meshes = new Reference2ReferenceOpenHashMap<>(); + SortType sortType = this.gfni.integrateGroupBuilder(context.groupBuilder); + TranslucentData translucentData = null; + Map meshes = new Reference2ReferenceOpenHashMap<>(); for (TerrainRenderPass pass : DefaultTerrainRenderPasses.ALL) { - ChunkMeshData mesh = buffers.createMesh(pass); + // consolidate all translucent geometry into UNASSIGNED so that it's rendered + // all together if GFNI's heuristic determines that it needs to be dynamically + // sorted + boolean isTranslucent = pass == DefaultTerrainRenderPasses.TRANSLUCENT; + ChunkMeshData mesh = buffers.createMesh(pass, isTranslucent && sortType.needsDynamicSort); if (mesh != null) { meshes.put(pass, mesh); renderData.addRenderPass(pass); + + if (isTranslucent) { + // calculate the primitive centers and initialize indexes for sorting. + // also does an initial sort + translucentData = TranslucentData.fromMeshData(buildContext.vertexType, mesh, sortType); + + // initial sort + if (translucentData != null) { + translucentData.sort(this.cameraPos); + } + } } } - renderData.setOcclusionData(occluder.build()); - - this.gfni.integrateGroupBuilder(context.groupBuilder); + this.render.setTranslucentData(translucentData); + renderData.addTranslucentData(translucentData); - return new ChunkBuildResult(this.render, renderData.build(), meshes, this.frame); + return new ChunkMeshBuildResult(this.render, this.frame, renderData.build(), meshes); } @Override diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkSortBuildTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkSortBuildTask.java new file mode 100644 index 0000000000..b96d5abf74 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkSortBuildTask.java @@ -0,0 +1,27 @@ +package me.jellysquid.mods.sodium.client.render.chunk.tasks; + +import org.joml.Vector3f; + +import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; +import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildContext; +import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildResult; +import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkSortBuildResult; +import me.jellysquid.mods.sodium.client.util.task.CancellationSource; + +public class ChunkSortBuildTask extends ChunkRenderBuildTask { + public ChunkSortBuildTask(RenderSection render, int frame, Vector3f cameraPos) { + super(render, frame, cameraPos); + } + + @Override + public ChunkBuildResult performBuild(ChunkBuildContext context, CancellationSource cancellationSource) { + this.render.getTranslucentData().sort(this.cameraPos); + + return new ChunkSortBuildResult(this.render, this.frame, this.render.getTranslucentData()); + } + + @Override + public void releaseResources() { + // TODO: is there anything to release? + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/vertex/format/impl/CompactChunkVertex.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/vertex/format/impl/CompactChunkVertex.java index 686ab95687..e6a189dd48 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/vertex/format/impl/CompactChunkVertex.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/vertex/format/impl/CompactChunkVertex.java @@ -36,6 +36,10 @@ private static short encodePosition(float v) { return (short) ((MODEL_ORIGIN + v) * MODEL_SCALE_INV); } + public static float decodePositionSum(short v, int members) { + return (v * MODEL_SCALE) - MODEL_ORIGIN * members; + } + @Override public float getTextureScale() { return TEXTURE_SCALE; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/VertexSorters.java b/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/VertexSorters.java index 2798529b66..7dc28a7232 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/VertexSorters.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/VertexSorters.java @@ -1,6 +1,9 @@ package me.jellysquid.mods.sodium.client.util.sorting; import com.mojang.blaze3d.systems.VertexSorter; + +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; + import org.joml.Vector3f; public class VertexSorters { @@ -8,6 +11,25 @@ public static VertexSorter sortByDistance(Vector3f origin) { return new SortByDistance(origin); } + public static VertexSorter sortByAxis(ModelQuadFacing facing) { + switch (facing) { + case DOWN: + return new SortByAxis(1, -1.0F); + case UP: + return new SortByAxis(1, 1.0F); + case NORTH: + return new SortByAxis(2, -1.0F); + case SOUTH: + return new SortByAxis(2, 1.0F); + case WEST: + return new SortByAxis(0, -1.0F); + case EAST: + return new SortByAxis(0, 1.0F); + default: + throw new IllegalArgumentException("Invalid facing: " + facing); + } + } + private static class SortByDistance extends AbstractVertexSorter { private final Vector3f origin; @@ -21,6 +43,21 @@ protected float getKey(Vector3f position) { } } + private static class SortByAxis extends AbstractVertexSorter { + private final int axis; + private final float sign; + + private SortByAxis(int axis, float sign) { + this.axis = axis; + this.sign = sign; + } + + @Override + protected float getKey(Vector3f position) { + return sign * position.get(this.axis); + } + } + private static abstract class AbstractVertexSorter implements VertexSorter { private static final int RADIX_SORT_THRESHOLD = 64; From 6effdec6a09202e2058ced6457a98c01017eed97 Mon Sep 17 00:00:00 2001 From: douira Date: Thu, 27 Jul 2023 04:55:59 +0200 Subject: [PATCH 008/256] do quad face gathering during vertex writing --- .../chunk/compile/pipeline/BlockRenderer.java | 10 ++++ .../chunk/data/DynamicTranslucentData.java | 28 ++++++++--- .../render/chunk/data/IndexedPrimitives.java | 49 ++----------------- .../chunk/data/StaticTranslucentData.java | 13 ++--- .../render/chunk/data/TranslucentData.java | 10 ++-- .../render/chunk/gfni/GroupBuilder.java | 14 ++++++ .../chunk/tasks/ChunkRenderRebuildTask.java | 3 +- 7 files changed, 63 insertions(+), 64 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java index 4903f120e1..0b0c38cc0b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java @@ -144,6 +144,10 @@ private void writeGeometry(BlockRenderContext ctx, // if translucent, add this face to the GFNI group builder boolean isTranslucent = material == DefaultMaterials.TRANSLUCENT; + float xSum = 0.0F; + float ySum = 0.0F; + float zSum = 0.0F; + for (int dstIndex = 0; dstIndex < 4; dstIndex++) { int srcIndex = orientation.getVertexIndex(dstIndex); @@ -164,6 +168,10 @@ private void writeGeometry(BlockRenderContext ctx, } else { ctx.groupBuilder.updateAlignedBounds(out.x, out.y, out.z); } + + xSum += out.x; + ySum += out.y; + zSum += out.z; } out.color = ColorABGR.withAlpha(colors != null ? colors[srcIndex] : 0xFFFFFFFF, light.br[srcIndex]); @@ -174,6 +182,8 @@ private void writeGeometry(BlockRenderContext ctx, out.light = light.lm[srcIndex]; } + ctx.groupBuilder.appendQuadCenter(normalFace, xSum, ySum, zSum); + var vertexBuffer = builder.getVertexBuffer(normalFace); vertexBuffer.push(vertices, material); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/DynamicTranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/DynamicTranslucentData.java index fa1f9099bd..207633cb4b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/DynamicTranslucentData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/DynamicTranslucentData.java @@ -1,19 +1,35 @@ package me.jellysquid.mods.sodium.client.render.chunk.data; +import java.util.Map; + import org.joml.Vector3f; +import it.unimi.dsi.fastutil.objects.ReferenceArrayList; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; -import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexType; import me.jellysquid.mods.sodium.client.util.sorting.VertexSorters; public class DynamicTranslucentData implements TranslucentData { private IndexedPrimitives data; - public DynamicTranslucentData(ChunkVertexType vertexType, ChunkMeshData meshData) { - var buffer = meshData.getVertexData().getDirectBuffer(); - int primitiveCount = meshData.getVertexCount() / 4; // TODO: is it quads or triangles? - var vertexRange = meshData.getPart(ModelQuadFacing.UNASSIGNED); - this.data = new IndexedPrimitives(vertexType, buffer, vertexRange, primitiveCount); + public DynamicTranslucentData(Map> centers) { + var length = 0; + for (var facing : ModelQuadFacing.DIRECTIONS) { + var centersForFacing = centers.get(facing); + if (centersForFacing != null) { + length += centersForFacing.size(); + } + } + var centersArray = new Vector3f[length]; + var index = 0; + for (var facing : ModelQuadFacing.DIRECTIONS) { + var centersForFacing = centers.get(facing); + if (centersForFacing != null) { + for (var center : centersForFacing) { + centersArray[index++] = center; + } + } + } + this.data = new IndexedPrimitives(centersArray); } @Override diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/IndexedPrimitives.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/IndexedPrimitives.java index 799091d435..5233dfcd54 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/IndexedPrimitives.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/IndexedPrimitives.java @@ -1,56 +1,15 @@ package me.jellysquid.mods.sodium.client.render.chunk.data; -import java.nio.ByteBuffer; - import org.joml.Vector3f; -import me.jellysquid.mods.sodium.client.gl.util.VertexRange; -import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexType; -import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.impl.CompactChunkVertex; - public class IndexedPrimitives { public final Vector3f[] centers; public int[] indexes; - public IndexedPrimitives( - ChunkVertexType vertexType, - ByteBuffer buffer, - VertexRange vertexRange, - int primitiveCount) { - this.centers = new Vector3f[primitiveCount]; - this.indexes = new int[primitiveCount]; - if (!(vertexType instanceof CompactChunkVertex)) { - throw new UnsupportedOperationException("Unknown vertex type: " + vertexType); - } - int vertexStride = vertexType.getVertexFormat().getStride(); - int primitiveStride = vertexStride * 4; // TODO: is it quads or triangles? - for (int i = 0; i < primitiveCount; i ++) { - // calculate the primitive center - int offset = i * primitiveStride + vertexRange.vertexStart(); - short x = buffer.getShort(offset + 0); - short y = buffer.getShort(offset + 2); - short z = buffer.getShort(offset + 4); - - offset += vertexStride; - x += buffer.getShort(offset + 0); - y += buffer.getShort(offset + 2); - z += buffer.getShort(offset + 4); - - offset += vertexStride; - x += buffer.getShort(offset + 0); - y += buffer.getShort(offset + 2); - z += buffer.getShort(offset + 4); - - offset += vertexStride; - x += buffer.getShort(offset + 0); - y += buffer.getShort(offset + 2); - z += buffer.getShort(offset + 4); - - float xCenter = CompactChunkVertex.decodePositionSum(x, 4); - float yCenter = CompactChunkVertex.decodePositionSum(y, 4); - float zCenter = CompactChunkVertex.decodePositionSum(z, 4); - - this.centers[i] = new Vector3f(xCenter, yCenter, zCenter); + public IndexedPrimitives(Vector3f[] centers) { + this.centers = centers; + this.indexes = new int[centers.length]; + for (int i = 0; i < centers.length; i++) { this.indexes[i] = i; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/StaticTranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/StaticTranslucentData.java index 9380fa3701..8b30b5b675 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/StaticTranslucentData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/StaticTranslucentData.java @@ -7,8 +7,8 @@ import com.mojang.blaze3d.systems.VertexSorter; +import it.unimi.dsi.fastutil.objects.ReferenceArrayList; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; -import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexType; import me.jellysquid.mods.sodium.client.util.sorting.VertexSorters; public class StaticTranslucentData implements TranslucentData { @@ -22,14 +22,11 @@ public class StaticTranslucentData implements TranslucentData { private final Map data = new EnumMap<>(ModelQuadFacing.class); - public StaticTranslucentData(ChunkVertexType vertexType, ChunkMeshData meshData) { - var buffer = meshData.getVertexData().getDirectBuffer(); - int primitiveCount = meshData.getVertexCount() / 4; // TODO: is it quads or triangles? - + public StaticTranslucentData(Map> centers) { for (ModelQuadFacing facing : ModelQuadFacing.DIRECTIONS) { - var vertexRange = meshData.getPart(facing); - if (vertexRange != null) { - this.data.put(facing, new IndexedPrimitives(vertexType, buffer, vertexRange, primitiveCount)); + var centersForFacing = centers.get(facing); + if (centersForFacing != null) { + this.data.put(facing, new IndexedPrimitives((Vector3f[]) centersForFacing.toArray())); } } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/TranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/TranslucentData.java index 53239442e0..017cdaba47 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/TranslucentData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/TranslucentData.java @@ -1,10 +1,12 @@ package me.jellysquid.mods.sodium.client.render.chunk.data; +import java.util.Map; + import org.joml.Vector3f; +import it.unimi.dsi.fastutil.objects.ReferenceArrayList; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.render.chunk.gfni.SortType; -import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexType; /** * TODO: figure out if the encoded vertex data should be decoded or taken from @@ -13,14 +15,14 @@ * later decides that it's not necessary. */ public interface TranslucentData { - public static TranslucentData fromMeshData(ChunkVertexType vertexType, ChunkMeshData meshData, SortType sortType) { + public static TranslucentData fromMeshData(SortType sortType, Map> centers) { switch (sortType) { case NONE: return null; case STATIC_NORMAL_RELATIVE: - return new StaticTranslucentData(vertexType, meshData); + return new StaticTranslucentData(centers); case DYNAMIC: - return new DynamicTranslucentData(vertexType, meshData); + return new DynamicTranslucentData(centers); default: throw new UnsupportedOperationException("Unknown sort type: " + sortType); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java index 93f2bf7bc3..9e1352516e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java @@ -1,9 +1,13 @@ package me.jellysquid.mods.sodium.client.render.chunk.gfni; +import java.util.EnumMap; +import java.util.Map; + import org.joml.Vector3f; import org.joml.Vector3fc; import it.unimi.dsi.fastutil.ints.Int2ReferenceLinkedOpenHashMap; +import it.unimi.dsi.fastutil.objects.ReferenceArrayList; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import net.minecraft.util.math.ChunkSectionPos; @@ -24,11 +28,21 @@ public class GroupBuilder { private int alignedNormalBitmap = 0; private Vector3f minBounds = new Vector3f(16, 16, 16); private Vector3f maxBounds = new Vector3f(0, 0, 0); + public final Map> quadCenters = new EnumMap<>(ModelQuadFacing.class); public GroupBuilder(ChunkSectionPos sectionPos) { this.sectionPos = sectionPos; } + public void appendQuadCenter(ModelQuadFacing facing, float xSum, float ySum, float zSum) { + var list = this.quadCenters.get(facing); + if (list == null) { + list = new ReferenceArrayList<>(); + this.quadCenters.put(facing, list); + } + list.add(new Vector3f(xSum / 4, ySum / 4, zSum / 4)); + } + public void addAlignedFace(ModelQuadFacing facing, float vertexX, float vertexY, float vertexZ) { if (facing == ModelQuadFacing.UNASSIGNED) { throw new IllegalArgumentException("Cannot add an unaligned face with addAlignedFace()"); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java index d60c57b9ca..1e43338bdc 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java @@ -145,7 +145,8 @@ public ChunkBuildResult performBuild(ChunkBuildContext buildContext, Cancellatio if (isTranslucent) { // calculate the primitive centers and initialize indexes for sorting. // also does an initial sort - translucentData = TranslucentData.fromMeshData(buildContext.vertexType, mesh, sortType); + translucentData = TranslucentData.fromMeshData( + sortType, context.groupBuilder.quadCenters); // initial sort if (translucentData != null) { From 5959fb7ecb0665cb80be753e19b96f55bfe62018 Mon Sep 17 00:00:00 2001 From: douira Date: Thu, 27 Jul 2023 05:01:25 +0200 Subject: [PATCH 009/256] also calculate quad centers in fluid renderer --- .../render/chunk/compile/pipeline/FluidRenderer.java | 10 ++++++++++ .../sodium/client/render/chunk/gfni/GroupBuilder.java | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java index 679e2ba1c1..6d36ca0bff 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java @@ -398,6 +398,10 @@ private void writeQuad(ChunkModelBuilder builder, GroupBuilder groupBuilder, Mat // if translucent, add this face to the GFNI group builder boolean isTranslucent = material == DefaultMaterials.TRANSLUCENT; + float xSum = 0.0F; + float ySum = 0.0F; + float zSum = 0.0F; + for (int i = 0; i < 4; i++) { var out = vertices[flip ? 3 - i : i]; out.x = offset.getX() + quad.getX(i); @@ -418,6 +422,10 @@ private void writeQuad(ChunkModelBuilder builder, GroupBuilder groupBuilder, Mat } else { groupBuilder.updateAlignedBounds(out.x, out.y, out.z); } + + xSum += out.x; + ySum += out.y; + zSum += out.z; } out.color = this.quadColors[i]; @@ -432,6 +440,8 @@ private void writeQuad(ChunkModelBuilder builder, GroupBuilder groupBuilder, Mat builder.addSprite(sprite); } + groupBuilder.appendQuadCenter(facing, xSum, ySum, zSum); + var vertexBuffer = builder.getVertexBuffer(facing); vertexBuffer.push(vertices, material); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java index 9e1352516e..bc675987aa 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java @@ -40,7 +40,7 @@ public void appendQuadCenter(ModelQuadFacing facing, float xSum, float ySum, flo list = new ReferenceArrayList<>(); this.quadCenters.put(facing, list); } - list.add(new Vector3f(xSum / 4, ySum / 4, zSum / 4)); + list.add(new Vector3f(xSum * 0.25f, ySum * 0.25f, zSum * 0.25f)); } public void addAlignedFace(ModelQuadFacing facing, float vertexX, float vertexY, float vertexZ) { From 9411041c7024d4abb41268885d602c27b6d4091e Mon Sep 17 00:00:00 2001 From: douira Date: Thu, 27 Jul 2023 15:14:37 +0200 Subject: [PATCH 010/256] remove unused method that was introduced in a previous commit --- .../render/chunk/vertex/format/impl/CompactChunkVertex.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/vertex/format/impl/CompactChunkVertex.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/vertex/format/impl/CompactChunkVertex.java index e6a189dd48..686ab95687 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/vertex/format/impl/CompactChunkVertex.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/vertex/format/impl/CompactChunkVertex.java @@ -36,10 +36,6 @@ private static short encodePosition(float v) { return (short) ((MODEL_ORIGIN + v) * MODEL_SCALE_INV); } - public static float decodePositionSum(short v, int members) { - return (v * MODEL_SCALE) - MODEL_ORIGIN * members; - } - @Override public float getTextureScale() { return TEXTURE_SCALE; From 23748a8e125426a64060ffb727c7562b08f2aba7 Mon Sep 17 00:00:00 2001 From: douira Date: Thu, 3 Aug 2023 01:58:27 +0200 Subject: [PATCH 011/256] gfni javadoc --- .../render/chunk/RenderSectionManager.java | 2 +- .../render/chunk/gfni/AccumulationGroup.java | 4 +- .../sodium/client/render/chunk/gfni/GFNI.java | 47 +++++++++++++++++-- .../client/render/chunk/gfni/Group.java | 2 +- .../client/render/chunk/gfni/NormalList.java | 6 +-- 5 files changed, 49 insertions(+), 12 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index 6e62afe945..9c95b1c0f3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -533,7 +533,7 @@ public ChunkBuilderSortingTask createSortTask(RenderSection render) { public void processGFNIMovement( double lastCameraX, double lastCameraY, double lastCameraZ, double cameraX, double cameraY, double cameraZ) { - this.gfni.findTriggeredSections(this::scheduleSort, + this.gfni.triggerSections(this::scheduleSort, lastCameraX, lastCameraY, lastCameraZ, cameraX, cameraY, cameraZ); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AccumulationGroup.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AccumulationGroup.java index 97a2a1ce16..80021bc52a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AccumulationGroup.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AccumulationGroup.java @@ -8,7 +8,7 @@ import it.unimi.dsi.fastutil.doubles.DoubleOpenHashSet; import net.minecraft.util.math.ChunkSectionPos; -public class AccumulationGroup { +class AccumulationGroup { final DoubleOpenHashSet relativeDistances = new DoubleOpenHashSet(16); final Vector3fc normal; final int groupBuilderKey; @@ -18,7 +18,7 @@ public class AccumulationGroup { private double relMinDistance = Double.POSITIVE_INFINITY; private double relMaxDistance = Double.NEGATIVE_INFINITY; - public AccumulationGroup(ChunkSectionPos sectionPos, Vector3fc normal, int groupBuilderKey) { + AccumulationGroup(ChunkSectionPos sectionPos, Vector3fc normal, int groupBuilderKey) { this.sectionPos = sectionPos; this.normal = normal; this.groupBuilderKey = groupBuilderKey; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java index a421adf692..cc1ff2a50d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java @@ -18,7 +18,7 @@ * TODO: synchronization is used for integrating group builders submitted from * chunk build threads. It is assumed that integrating a group builder is fast * and thus synchronization is not a big problem. However, if it is, it might be - * better to put the group builder in the ChunkBuildResult and have the main + * better to put the group builder in the ChunkSortOutput and have the main * thread integrate it. The distadvantage is that the main thread would be busy * with group integration while actually the chunk build thread could be doing * it itself. If fine grained synchronization is needed, threads could also work @@ -38,8 +38,6 @@ * TODO: * - update GFNI document about how this implementation works with the * interval tree and update the diagram. - * - filter the triggered sections by visibility in the frame (using the graph - * search result) * - sort the triggered sections by camera distance and possibly also use number * of translucent faces as a heuristic for importance * - baked models could possibly precompute normals and then just calculate @@ -51,6 +49,14 @@ * visible, if there are idle threads. */ public class GFNI { + /** + * The quantization factor with which the normals are quantized such that there + * are fewer possible unique normals. The factor describes the number of steps + * in each direction per dimension that the components of the normals can have. + * It determines the density of the grid on the surface of a unit cube centered + * at the origin onto which the normals are projected. The normals are snapped + * to the nearest grid point. + */ public static final int QUANTIZATION_FACTOR = 4; /** @@ -58,13 +64,29 @@ public class GFNI { */ private Object2ReferenceOpenHashMap normalLists = new Object2ReferenceOpenHashMap<>(50); + /** + * To avoid generating a collection of the triggered sections, this callback is + * used to process the triggered sections directly as they are queried from the + * normal lists' interval trees. + */ private Consumer triggerSectionCallback; // TODO: both of these are for debugging ObjectLinkedOpenHashSet triggeredSections = new ObjectLinkedOpenHashSet<>(50); ObjectOpenHashSet triggeredNormals = new ObjectOpenHashSet<>(50); - public void findTriggeredSections( + /** + * Triggers the sections that the given camera movement crosses face planes of. + * + * @param triggerSectionCallback called for each section that is triggered + * @param lastCameraX the camera x position before the movement + * @param lastCameraY the camera y position before the movement + * @param lastCameraZ the camera z position before the movement + * @param cameraX the camera x position after the movement + * @param cameraY the camera y position after the movement + * @param cameraZ the camera z position after the movement + */ + public void triggerSections( Consumer triggerSectionCallback, double lastCameraX, double lastCameraY, double lastCameraZ, double cameraX, double cameraY, double cameraZ) { @@ -105,6 +127,11 @@ private void removeSectionFromList(NormalList normalList, long chunkSectionLongP } } + /** + * Removes a section from GFNI. This removes all its face planes. + * + * @param chunkSectionLongPos the section to remove + */ public void removeSection(long chunkSectionLongPos) { int normalListCount = this.normalLists.size(); @@ -128,7 +155,17 @@ private void addSectionInNewNormalLists(AccumulationGroup accGroup) { } } - // TODO: synchronized because it's expected to be fast, see class comment + /** + * Integrates the data from a group builder into GFNI. The group builder + * contains the translucent face planes of a single section. This method may + * also remove the section if it has become irrelevant. + * + * TODO: marked as synchronized because it's expected to be fast, see class + * comment + * + * @param builder the group builder to integrate + * @return the sort type that the group builder's relevance heuristic determined + */ public synchronized SortType integrateGroupBuilder(GroupBuilder builder) { long chunkSectionLongPos = builder.sectionPos.asLong(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java index 11646ba22c..a58d4ce689 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java @@ -12,7 +12,7 @@ * group keeps a tree of its face plane distances to determine if it needs to be * triggered. */ -public class Group { +class Group { /** * The section this group is for */ diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java index 2dc616671c..3cfbfa2f1b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java @@ -20,7 +20,7 @@ /** * A normal list contains all the face planes that have the same normal. */ -public class NormalList { +class NormalList { /** * Size threshold after which group sets in {@link #groupsByInterval} are * replaced with hash sets to improve update performance. @@ -79,11 +79,11 @@ public class NormalList { this.groupBuilderKey = groupBuilderKey; } - public Vector3fc getNormal() { + Vector3fc getNormal() { return normalf; } - public int getGroupBuilderKey() { + int getGroupBuilderKey() { return groupBuilderKey; } From c95ce850a4f6d4c34735e776e5597842254f5356 Mon Sep 17 00:00:00 2001 From: douira Date: Thu, 3 Aug 2023 03:14:30 +0200 Subject: [PATCH 012/256] fix modelquadfacing.DIRECTIONS being too big, fix various exceptions and typos, WIP since sort results are not properly used yet --- .../client/model/quad/properties/ModelQuadFacing.java | 2 +- .../mods/sodium/client/render/chunk/ChunkUpdateType.java | 2 +- .../sodium/client/render/chunk/RenderSectionManager.java | 9 +++++++-- .../client/render/chunk/compile/BuilderTaskOutput.java | 2 ++ .../client/render/chunk/compile/ChunkBuildOutput.java | 7 +++++++ .../client/render/chunk/compile/ChunkSortOutput.java | 5 +++++ .../client/render/chunk/data/DynamicTranslucentData.java | 4 ++-- .../client/render/chunk/data/StaticTranslucentData.java | 3 ++- .../sodium/client/render/chunk/gfni/GroupBuilder.java | 2 +- 9 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java index 7897082df6..1a81374202 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java @@ -14,7 +14,7 @@ public enum ModelQuadFacing { public static final ModelQuadFacing[] VALUES = ModelQuadFacing.values(); public static final int COUNT = VALUES.length; - public static final int DIRECTIONS = VALUES.length; + public static final int DIRECTIONS = VALUES.length - 1; public static final int NONE = 0; public static final int ALL = (1 << COUNT) - 1; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkUpdateType.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkUpdateType.java index 3aa0bea06d..a705d4a935 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkUpdateType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkUpdateType.java @@ -7,6 +7,6 @@ public enum ChunkUpdateType { IMPORTANT_REBUILD; public static boolean canPromote(ChunkUpdateType prev, ChunkUpdateType next) { - return prev == null || (prev == REBUILD && next == IMPORTANT_REBUILD); + return prev == null || prev == TRANSLUCENT_SORT || (prev == REBUILD && next == IMPORTANT_REBUILD); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index 9c95b1c0f3..a1ef8bd6b0 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -431,6 +431,7 @@ private void processChunkBuildResults(ArrayList results) { } private void updateSectionInfo(RenderSection render, BuiltSectionInfo info) { + // TODO: make this work with translucent data and figure out a nice way to use BuilderTaskOutput render.setInfo(info); if (info == null || ArrayUtils.isEmpty(info.globalBlockEntities)) { @@ -493,9 +494,9 @@ private void submitRebuildTasks(ChunkUpdateType type, boolean asynchronous) { int frame = this.currentFrame; ChunkBuilderTask task; if (type == ChunkUpdateType.TRANSLUCENT_SORT) { - task = this.createRebuildTask(section, frame); - } else { task = this.createSortTask(section); + } else { + task = this.createRebuildTask(section, frame); } if (task != null) { @@ -527,6 +528,10 @@ private void submitRebuildTasks(ChunkUpdateType type, boolean asynchronous) { } public ChunkBuilderSortingTask createSortTask(RenderSection render) { + if (render.getTranslucentData() == null) { + return null; + } + return new ChunkBuilderSortingTask(render, this.currentFrame, this.cameraPos); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/BuilderTaskOutput.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/BuilderTaskOutput.java index 7ad53d4c95..a1f417ed61 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/BuilderTaskOutput.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/BuilderTaskOutput.java @@ -13,4 +13,6 @@ public BuilderTaskOutput(RenderSection render, int buildTime) { public void delete() { } + + public abstract void setDataOn(RenderSection render); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java index 101d36a4dd..7ecf640c95 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java @@ -35,4 +35,11 @@ public void delete() { .free(); } } + + @Override + public void setDataOn(RenderSection render) { + super.setDataOn(render); + + render.setInfo(this.info); + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java index e9c053c2c7..65647f087d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java @@ -11,4 +11,9 @@ public ChunkSortOutput(RenderSection render, int buildTime, TranslucentData tran this.translucentData = translucentData; } + + @Override + public void setDataOn(RenderSection render) { + render.setTranslucentData(translucentData);; + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/DynamicTranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/DynamicTranslucentData.java index 14c33d7d51..f1e01fa611 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/DynamicTranslucentData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/DynamicTranslucentData.java @@ -11,7 +11,7 @@ public class DynamicTranslucentData implements TranslucentData { public DynamicTranslucentData(ReferenceArrayList[] centers) { var length = 0; - for (int i = 0; i < ModelQuadFacing.DIRECTIONS; i++) { + for (int i = 0; i < ModelQuadFacing.COUNT; i++) { var centersForFacing = centers[i]; if (centersForFacing != null) { length += centersForFacing.size(); @@ -19,7 +19,7 @@ public DynamicTranslucentData(ReferenceArrayList[] centers) { } var centersArray = new Vector3f[length]; int index = 0; - for (int i = 0; i < ModelQuadFacing.DIRECTIONS; i++) { + for (int i = 0; i < ModelQuadFacing.COUNT; i++) { var centersForFacing = centers[i]; if (centersForFacing != null) { for (var center : centersForFacing) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/StaticTranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/StaticTranslucentData.java index 4cab15aa3c..e109201f33 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/StaticTranslucentData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/StaticTranslucentData.java @@ -18,12 +18,13 @@ public class StaticTranslucentData implements TranslucentData { } private final IndexedPrimitives[] data = new IndexedPrimitives[ModelQuadFacing.DIRECTIONS]; + private static final Vector3f[] EMPTY_CENTERS = new Vector3f[0]; public StaticTranslucentData(ReferenceArrayList[] centers) { for (int i = 0; i < ModelQuadFacing.DIRECTIONS; i++) { var centersForFacing = centers[i]; if (centersForFacing != null) { - this.data[i] = new IndexedPrimitives((Vector3f[]) centersForFacing.toArray()); + this.data[i] = new IndexedPrimitives(centersForFacing.toArray(EMPTY_CENTERS)); } } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java index 5eefb2a423..373658c46a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java @@ -27,7 +27,7 @@ public class GroupBuilder { private Vector3f maxBounds = new Vector3f(0, 0, 0); @SuppressWarnings("unchecked") - public final ReferenceArrayList[] quadCenters = new ReferenceArrayList[ModelQuadFacing.DIRECTIONS]; + public final ReferenceArrayList[] quadCenters = new ReferenceArrayList[ModelQuadFacing.COUNT]; public GroupBuilder(ChunkSectionPos sectionPos) { this.sectionPos = sectionPos; From d37489fa062e5f5ad25be86722ae6136cf9dbd79 Mon Sep 17 00:00:00 2001 From: douira Date: Wed, 9 Aug 2023 00:12:11 +0200 Subject: [PATCH 013/256] add special cases and update javadoc --- .../sodium/client/render/chunk/gfni/GFNI.java | 3 +- .../render/chunk/gfni/GroupBuilder.java | 70 ++++++++----------- 2 files changed, 32 insertions(+), 41 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java index cc1ff2a50d..7c818fba5d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java @@ -170,8 +170,7 @@ public synchronized SortType integrateGroupBuilder(GroupBuilder builder) { long chunkSectionLongPos = builder.sectionPos.asLong(); // if the builder is irrelevant, remove it from the normal lists - // if the builder is relevant, this may also simplify it as a side effect - SortType sortType = builder.getSortTypeAndSimplify(); + SortType sortType = builder.getSortType(); if (!sortType.needsDynamicSort) { removeSection(chunkSectionLongPos); return sortType; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java index 373658c46a..3b6342a119 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java @@ -121,7 +121,12 @@ AccumulationGroup getGroupForNormal(NormalList normalList) { } /** - * Checks if this group builder is relevant for translucency sort triggering. + * Checks if this group builder is relevant for translucency sort triggering. It + * determines a sort type, which is either no sorting, a static sort or a + * dynamic sort (section in GFNI only in this case). + * + * See the section on special cases for an explanation of the special sorting + * cases: https://hackmd.io/@douira100/sodium-sl-gfni#Special-Sorting-Cases * * A: If there are no or only one normal, this builder can be considered * practically empty. @@ -132,7 +137,7 @@ AccumulationGroup getGroupForNormal(NormalList normalList) { * * C: If the translucent faces are on the surface of the convex hull of all * translucent faces in the section and face outwards, then there is no way to - * see one through the other. Since convex nulls are hard, a simpler case only + * see one through another. Since convex hulls are hard, a simpler case only * uses the axis aligned normals: Under the condition that only aligned normals * are used in the section, tracking the bounding box of the translucent * geometry (the vertices) in the section and then checking if the normal @@ -140,27 +145,18 @@ AccumulationGroup getGroupForNormal(NormalList normalList) { * sections containing a single convex translucent cuboid (of which not all * faces need to exist). * - * D1: If there are up to two normals with each up to two distances, then only - * the larger distance of each normal needs to be triggered on. - * - * TODO: However, for this to work, the initial sort needs to happen fully above - * or below both of the distances. Otherwise there can be cases where it's - * wrong. - * - * D2: More generally, if there are only two normals which are opposites of + * D: If there are only two normals which are opposites of * each other, then a special fixed sort order is always a correct sort order. * This ordering sorts the two sets of face planes by their ascending * normal-relative distance. The ordering between the two normals is irrelevant - * as they can't be seen through each other anyways. This case in includes case - * D1 and makes it unnecessary. Sections in D2 don't need to be triggered on at - * all. (not yet implemented since there is no sorting backend yet) + * as they can't be seen through each other anyways. * * More heuristics can be performed here to conservatively determine if this * section could possibly have more than one translucent sort order. * - * @return true if this group builder is relevant + * @return the required sort type to ensure this section always looks correct */ - SortType getSortTypeAndSimplify() { + SortType getSortType() { // special case A if (this.facePlaneCount <= 1) { return SortType.NONE; @@ -209,31 +205,27 @@ SortType getSortTypeAndSimplify() { } } - // special case D1 - if (this.facePlaneCount <= 2 || this.facePlaneCount <= 4 && twoOpposingNormals) { - // remove the lesser distance of each normal, even if it only has one - for (AccumulationGroup accGroup : this.axisAlignedDistances) { - if (accGroup == null) { - continue; - } - - var distanceIterator = accGroup.relativeDistances.iterator(); - var lesserDistance = distanceIterator.nextDouble(); - if (distanceIterator.hasNext()) { - lesserDistance = Math.min(lesserDistance, distanceIterator.nextDouble()); - } - accGroup.relativeDistances.remove(lesserDistance); - this.facePlaneCount--; - - if (accGroup.relativeDistances.isEmpty()) { - this.axisAlignedDistances[accGroup.groupBuilderKey] = null; - this.alignedNormalBitmap ^= 1 << accGroup.groupBuilderKey; - } - } - - // in case D1 the group will always still need sorting, just now less often. - // the case where the only remaining face plane is removed is handled in A. + // special case D + // there are up to two normals that are opposing, this means no dynamic sorting + // is necessary. Without static sorting, the geometry to trigger on could be + // reduced but this isn't done here as we assume static sorting is possible. + if (twoOpposingNormals || Integer.bitCount(this.alignedNormalBitmap) == 1) { + return SortType.STATIC_NORMAL_RELATIVE; + } + } else if (this.alignedNormalBitmap == 0) { + if (this.unalignedDistances.size() == 1) { + // special case D but for one unaligned normal return SortType.STATIC_NORMAL_RELATIVE; + } else if (this.unalignedDistances.size() == 2) { + // special case D but for two opposing unaligned normals + var iterator = this.unalignedDistances.values().iterator(); + var normalA = iterator.next().normal; + var normalB = iterator.next().normal; + if (normalA.x() == -normalB.x() + && normalA.y() == -normalB.y() + && normalA.z() == -normalB.z()) { + return SortType.STATIC_NORMAL_RELATIVE; + } } } From 6308738b9749045f2040760d9acc53b994b19ccf Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 12 Aug 2023 03:52:20 +0200 Subject: [PATCH 014/256] update todo notes --- .../jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java index 7c818fba5d..83ac76efa3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java @@ -36,8 +36,6 @@ * blocks above the water source blocks. * * TODO: - * - update GFNI document about how this implementation works with the - * interval tree and update the diagram. * - sort the triggered sections by camera distance and possibly also use number * of translucent faces as a heuristic for importance * - baked models could possibly precompute normals and then just calculate From 554f537ca8dcc250a3ad4a0e3cab225d5fd135fb Mon Sep 17 00:00:00 2001 From: douira Date: Wed, 16 Aug 2023 03:45:49 +0200 Subject: [PATCH 015/256] missing changes --- .../render/chunk/compile/executor/ChunkJobCollector.java | 8 ++++---- .../chunk/compile/tasks/ChunkBuilderMeshingTask.java | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJobCollector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJobCollector.java index f1a396df92..ebeba8a5d0 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJobCollector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJobCollector.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.render.chunk.compile.executor; -import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildOutput; +import me.jellysquid.mods.sodium.client.render.chunk.compile.BuilderTaskOutput; import java.util.ArrayList; import java.util.List; @@ -9,17 +9,17 @@ public class ChunkJobCollector { private final Semaphore semaphore = new Semaphore(0); - private final Consumer> collector; + private final Consumer> collector; private final List submitted = new ArrayList<>(); private final int budget; - public ChunkJobCollector(int budget, Consumer> collector) { + public ChunkJobCollector(int budget, Consumer> collector) { this.budget = budget; this.collector = collector; } - public void onJobFinished(ChunkJobResult result) { + public void onJobFinished(ChunkJobResult result) { this.semaphore.release(1); this.collector.accept(result); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java index b870a6a657..0942fd97ed 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java @@ -77,7 +77,7 @@ public ChunkBuildOutput execute(ChunkBuildContext buildContext, CancellationToke BlockPos.Mutable blockPos = new BlockPos.Mutable(minX, minY, minZ); BlockPos.Mutable modelOffset = new BlockPos.Mutable(); - GroupBuilder groupBuilder = new GroupBuilder(render.getChunkPos()); + GroupBuilder groupBuilder = new GroupBuilder(render.getPosition()); BlockRenderContext context = new BlockRenderContext(slice, groupBuilder); try { From 874a92c7418c4ee89b09828a297cdc4454cd2d1d Mon Sep 17 00:00:00 2001 From: douira Date: Wed, 16 Aug 2023 04:18:04 +0200 Subject: [PATCH 016/256] update outdated documentation --- .../mods/sodium/client/render/chunk/gfni/GFNI.java | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java index 83ac76efa3..aff84f48fe 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java @@ -26,15 +26,6 @@ * lists are created (and possibly deleted) on demand, this would require a more * complex synchronization scheme. * - * Maximum add/update and remove durations are 0.4ms and 0.06ms respectively in - * a 32rd world with around 230 normal lists. - * - * It triggers 600 sections for normal (0, 1, 0) at distance - * 62.88788890838623 in a 32rd world because of flooded caves that make the - * ocean surface heuristic not work. The distance being triggered on is the - * overworld water surface height. Flooded caves have water surfaces below solid - * blocks above the water source blocks. - * * TODO: * - sort the triggered sections by camera distance and possibly also use number * of translucent faces as a heuristic for importance @@ -45,6 +36,8 @@ * may result in many sections suddenly needing sorting when the camera moves. * Maybe it's better to schedule them to be sorted gradually even if not * visible, if there are idle threads. + * + * @author douira */ public class GFNI { /** From eee8f228be4b5b09fce25f60ba0072686a6dc51b Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 4 Sep 2023 02:30:15 +0200 Subject: [PATCH 017/256] unbreak everything by removing the sort task submission --- .../client/render/chunk/RenderSectionManager.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index c48dad8288..59f59baa58 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -284,7 +284,8 @@ public void updateChunks(boolean updateImmediately) { this.submitRebuildTasks(blockingRebuilds, ChunkUpdateType.IMPORTANT_REBUILD); this.submitRebuildTasks(updateImmediately ? blockingRebuilds : deferredRebuilds, ChunkUpdateType.REBUILD); this.submitRebuildTasks(updateImmediately ? blockingRebuilds : deferredRebuilds, ChunkUpdateType.INITIAL_BUILD); - this.submitRebuildTasks(updateImmediately ? blockingRebuilds : deferredRebuilds, ChunkUpdateType.TRANSLUCENT_SORT); + // TODO: re-enable once sort tasks are figured out + // this.submitRebuildTasks(updateImmediately ? blockingRebuilds : deferredRebuilds, ChunkUpdateType.TRANSLUCENT_SORT); blockingRebuilds.awaitCompletion(this.builder); } @@ -473,12 +474,13 @@ public int getVisibleChunkCount() { public void scheduleSort(ChunkSectionPos pos) { // TODO: Does this need to invalidate the section cache? + // TODO: re-enable once sort tasks are figured out - RenderSection section = this.sectionByPosition.get(pos.asLong()); + // RenderSection section = this.sectionByPosition.get(pos.asLong()); - if (section != null && ChunkUpdateType.canPromote(section.getPendingUpdate(), ChunkUpdateType.TRANSLUCENT_SORT)) { - section.setPendingUpdate(ChunkUpdateType.TRANSLUCENT_SORT); - } + // if (section != null && ChunkUpdateType.canPromote(section.getPendingUpdate(), ChunkUpdateType.TRANSLUCENT_SORT)) { + // section.setPendingUpdate(ChunkUpdateType.TRANSLUCENT_SORT); + // } } public void scheduleRebuild(int x, int y, int z, boolean important) { From 92d00c24f83b39336ae3ed3883824869242a9bc5 Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 4 Sep 2023 04:40:11 +0200 Subject: [PATCH 018/256] comment out initial sort until it's figured out --- .../tasks/ChunkBuilderMeshingTask.java | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java index 0942fd97ed..f2adb34d1e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java @@ -156,17 +156,18 @@ public ChunkBuildOutput execute(ChunkBuildContext buildContext, CancellationToke meshes.put(pass, mesh); renderData.addRenderPass(pass); - if (isTranslucent) { - // calculate the primitive centers and initialize indexes for sorting. - // also does an initial sort - translucentData = TranslucentData.fromMeshData( - sortType, context.groupBuilder.quadCenters); - - // initial sort - if (translucentData != null) { - translucentData.sort(this.cameraPos); - } - } + // TODO: re-enable + // if (isTranslucent) { + // // calculate the primitive centers and initialize indexes for sorting. + // // also does an initial sort + // translucentData = TranslucentData.fromMeshData( + // sortType, context.groupBuilder.quadCenters); + + // // initial sort + // if (translucentData != null) { + // translucentData.sort(this.cameraPos); + // } + // } } } From 4f12c8db1638a4055bdb64aec33a0d3b7ec70fc6 Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 4 Sep 2023 19:23:11 +0200 Subject: [PATCH 019/256] implementation of translucency visibility graph sorting --- .../chunk/compile/pipeline/BlockRenderer.java | 26 +- .../chunk/compile/pipeline/FluidRenderer.java | 32 +- .../tasks/ChunkBuilderMeshingTask.java | 5 +- .../chunk/data/StaticTranslucentData.java | 11 +- .../render/chunk/data/TranslucentData.java | 5 +- .../render/chunk/gfni/AccumulationGroup.java | 2 +- .../sodium/client/render/chunk/gfni/GFNI.java | 19 +- .../render/chunk/gfni/GroupBuilder.java | 436 +++++++++++++++--- .../client/render/chunk/gfni/SortType.java | 31 +- 9 files changed, 440 insertions(+), 127 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java index 81a153cd8f..420f48c659 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java @@ -150,10 +150,6 @@ private void writeGeometry(BlockRenderContext ctx, // if translucent, add this face to the GFNI group builder boolean isTranslucent = material == DefaultMaterials.TRANSLUCENT; - float xSum = 0.0F; - float ySum = 0.0F; - float zSum = 0.0F; - for (int dstIndex = 0; dstIndex < 4; dstIndex++) { int srcIndex = orientation.getVertexIndex(dstIndex); @@ -162,24 +158,6 @@ private void writeGeometry(BlockRenderContext ctx, out.y = ctx.origin().y() + quad.getY(srcIndex) + (float) offset.getY(); out.z = ctx.origin().z() + quad.getZ(srcIndex) + (float) offset.getZ(); - if (isTranslucent) { - if (normalFace == ModelQuadFacing.UNASSIGNED) { - if (dstIndex == 0) { - ctx.groupBuilder.addUnalignedFace( - quad.getGFNINormX(), quad.getGFNINormY(), quad.getGFNINormZ(), - out.x, out.y, out.z); - } - } else if (dstIndex == 0) { - ctx.groupBuilder.addAlignedFace(normalFace, out.x, out.y, out.z); - } else { - ctx.groupBuilder.updateAlignedBounds(out.x, out.y, out.z); - } - - xSum += out.x; - ySum += out.y; - zSum += out.z; - } - out.color = ColorABGR.withAlpha(colors != null ? colors[srcIndex] : 0xFFFFFFFF, light.br[srcIndex]); out.u = quad.getTexU(srcIndex); @@ -188,7 +166,9 @@ private void writeGeometry(BlockRenderContext ctx, out.light = light.lm[srcIndex]; } - ctx.groupBuilder.appendQuadCenter(normalFace, xSum, ySum, zSum); + if (isTranslucent) { + ctx.groupBuilder.appendQuad(quad, vertices, normalFace); + } var vertexBuffer = builder.getVertexBuffer(normalFace); vertexBuffer.push(vertices, material); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java index 9d53124415..50df5686c0 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java @@ -407,36 +407,12 @@ private void writeQuad(ChunkModelBuilder builder, GroupBuilder groupBuilder, Mat // if translucent, add this face to the GFNI group builder boolean isTranslucent = material == DefaultMaterials.TRANSLUCENT; - float xSum = 0.0F; - float ySum = 0.0F; - float zSum = 0.0F; - for (int i = 0; i < 4; i++) { var out = vertices[flip ? 3 - i : i]; out.x = offset.getX() + quad.getX(i); out.y = offset.getY() + quad.getY(i); out.z = offset.getZ() + quad.getZ(i); - if (isTranslucent) { - if (facing == ModelQuadFacing.UNASSIGNED) { - if (i == 0) { - // calculate the current GFNI normal but not the unit normal - quad.calculateNormals(false); - groupBuilder.addUnalignedFace( - quad.getGFNINormX(), quad.getGFNINormY(), quad.getGFNINormZ(), - out.x, out.y, out.z); - } - } else if (i == 0) { - groupBuilder.addAlignedFace(facing, out.x, out.y, out.z); - } else { - groupBuilder.updateAlignedBounds(out.x, out.y, out.z); - } - - xSum += out.x; - ySum += out.y; - zSum += out.z; - } - out.color = this.quadColors[i]; out.u = quad.getTexU(i); out.v = quad.getTexV(i); @@ -449,7 +425,13 @@ private void writeQuad(ChunkModelBuilder builder, GroupBuilder groupBuilder, Mat builder.addSprite(sprite); } - groupBuilder.appendQuadCenter(facing, xSum, ySum, zSum); + if (isTranslucent) { + if (facing == ModelQuadFacing.UNASSIGNED) { + // calculate the current GFNI normal but not the unit normal + quad.calculateNormals(false); + } + groupBuilder.appendQuad(quad, vertices, facing); + } var vertexBuffer = builder.getVertexBuffer(facing); vertexBuffer.push(vertices, material); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java index f2adb34d1e..e764a74316 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java @@ -149,8 +149,9 @@ public ChunkBuildOutput execute(ChunkBuildContext buildContext, CancellationToke // consolidate all translucent geometry into UNASSIGNED so that it's rendered // all together if GFNI's heuristic determines that it needs to be dynamically // sorted - boolean isTranslucent = pass == DefaultTerrainRenderPasses.TRANSLUCENT; - BuiltSectionMeshParts mesh = buffers.createMesh(pass, isTranslucent && sortType.needsDynamicSort); + // boolean isTranslucent = pass == DefaultTerrainRenderPasses.TRANSLUCENT; + // BuiltSectionMeshParts mesh = buffers.createMesh(pass, isTranslucent && sortType.needsDirectionMixing); + BuiltSectionMeshParts mesh = buffers.createMesh(pass, false); if (mesh != null) { meshes.put(pass, mesh); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/StaticTranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/StaticTranslucentData.java index e109201f33..9e9d485efa 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/StaticTranslucentData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/StaticTranslucentData.java @@ -6,17 +6,10 @@ import it.unimi.dsi.fastutil.objects.ReferenceArrayList; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import me.jellysquid.mods.sodium.client.render.chunk.gfni.GFNI; import me.jellysquid.mods.sodium.client.util.sorting.VertexSorters; public class StaticTranslucentData implements TranslucentData { - private static final VertexSorter[] SORTERS = new VertexSorter[ModelQuadFacing.DIRECTIONS]; - - static { - for (int i = 0; i < ModelQuadFacing.DIRECTIONS; i++) { - SORTERS[i] = VertexSorters.sortByAxis(ModelQuadFacing.VALUES[i]); - } - } - private final IndexedPrimitives[] data = new IndexedPrimitives[ModelQuadFacing.DIRECTIONS]; private static final Vector3f[] EMPTY_CENTERS = new Vector3f[0]; @@ -55,7 +48,7 @@ public void sort(Vector3f cameraPos) { for (int i = 0; i < ModelQuadFacing.DIRECTIONS; i++) { var dataForFacing = this.data[i]; if (dataForFacing != null) { - dataForFacing.indexes = SORTERS[i].sort(dataForFacing.centers); + dataForFacing.indexes = GFNI.SORTERS[i].sort(dataForFacing.centers); } } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/TranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/TranslucentData.java index 6fe7bbceb5..85e75d1305 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/TranslucentData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/TranslucentData.java @@ -14,15 +14,16 @@ */ public interface TranslucentData { public static TranslucentData fromMeshData(SortType sortType, ReferenceArrayList[] centers) { + // TODO: handle new sort types switch (sortType) { case NONE: return null; case STATIC_NORMAL_RELATIVE: return new StaticTranslucentData(centers); - case DYNAMIC: + case DYNAMIC_ALL: return new DynamicTranslucentData(centers); default: - throw new UnsupportedOperationException("Unknown sort type: " + sortType); + throw new UnsupportedOperationException("Unhandled sort type: " + sortType); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AccumulationGroup.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AccumulationGroup.java index 80021bc52a..76eec1e571 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AccumulationGroup.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AccumulationGroup.java @@ -24,7 +24,7 @@ class AccumulationGroup { this.groupBuilderKey = groupBuilderKey; } - boolean add(float vertexX, float vertexY, float vertexZ) { + boolean addPlaneMember(float vertexX, float vertexY, float vertexZ) { double distance = this.normal.dot(vertexX, vertexY, vertexZ); // add the distance to the set and update the min/max distances if necessary diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java index aff84f48fe..d7174d739b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java @@ -4,9 +4,13 @@ import org.joml.Vector3fc; +import com.mojang.blaze3d.systems.VertexSorter; + import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import me.jellysquid.mods.sodium.client.util.sorting.VertexSorters; import net.minecraft.util.math.ChunkSectionPos; /** @@ -62,6 +66,18 @@ public class GFNI { */ private Consumer triggerSectionCallback; + /** + * The vertex sorter for each direction. + * TODO: is there a better place to put this + */ + public static final VertexSorter[] SORTERS = new VertexSorter[ModelQuadFacing.DIRECTIONS]; + + static { + for (int i = 0; i < ModelQuadFacing.DIRECTIONS; i++) { + SORTERS[i] = VertexSorters.sortByAxis(ModelQuadFacing.VALUES[i]); + } + } + // TODO: both of these are for debugging ObjectLinkedOpenHashSet triggeredSections = new ObjectLinkedOpenHashSet<>(50); ObjectOpenHashSet triggeredNormals = new ObjectOpenHashSet<>(50); @@ -161,8 +177,9 @@ public synchronized SortType integrateGroupBuilder(GroupBuilder builder) { long chunkSectionLongPos = builder.sectionPos.asLong(); // if the builder is irrelevant, remove it from the normal lists + // TODO: only do the heuristic and topo sort if the hashes are different? SortType sortType = builder.getSortType(); - if (!sortType.needsDynamicSort) { + if (!sortType.needsPlaneTrigger) { removeSection(chunkSectionLongPos); return sortType; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java index 3b6342a119..1c06ae45ac 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java @@ -1,16 +1,47 @@ package me.jellysquid.mods.sodium.client.render.chunk.gfni; +import java.util.BitSet; + import org.joml.Vector3f; import org.joml.Vector3fc; import it.unimi.dsi.fastutil.ints.Int2ReferenceLinkedOpenHashMap; import it.unimi.dsi.fastutil.objects.ReferenceArrayList; +import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexEncoder; +import me.jellysquid.mods.sodium.client.util.sorting.MergeSort; import net.minecraft.util.math.ChunkSectionPos; +/** + * The group builder collects the data from the renderers and builds data + * structures for either dynamic triggering or static sorting. It determines the + * best sort type for the section and performs translucency visibility graph + * sorting with a topological sort algorithm if necessary. + * + * TODO: can use a bunch more optimizations, this is a prototype. + * TODO list: + * - use continuous arrays for the quad centers and quad storage + * - use more accurate normals for unaligned topo sort? do we do topo sort on + * unaligned faces at all? + * - bail early during rendering if we decide not to topo sort, then we don't + * need to gather all of the data + * - do normal-relative sorting here too? or keep it in StaticTranslucentData? + * - detail how the graph construction and the topo sort works in the GFNI doc + * - make the resulting static index buffer actually available to the renderer + */ public class GroupBuilder { + // TODO: debugging + private static int topoSortHits = 0; + private static int cyclicGraphHits = 0; + private static int unalignedDynamicHits = 0; + public static final Vector3fc[] ALIGNED_NORMALS = new Vector3fc[ModelQuadFacing.DIRECTIONS]; + private static final int OPPOSING_X = 1 << ModelQuadFacing.POS_X.ordinal() | 1 << ModelQuadFacing.NEG_X.ordinal(); + private static final int OPPOSING_Y = 1 << ModelQuadFacing.POS_Y.ordinal() | 1 << ModelQuadFacing.NEG_Y.ordinal(); + private static final int OPPOSING_Z = 1 << ModelQuadFacing.POS_Z.ordinal() | 1 << ModelQuadFacing.NEG_Z.ordinal(); + static { for (int i = 0; i < ModelQuadFacing.DIRECTIONS; i++) { ALIGNED_NORMALS[i] = new Vector3f(ModelQuadFacing.VALUES[i].toDirection().getUnitVector()); @@ -26,81 +57,132 @@ public class GroupBuilder { private Vector3f minBounds = new Vector3f(16, 16, 16); private Vector3f maxBounds = new Vector3f(0, 0, 0); - @SuppressWarnings("unchecked") - public final ReferenceArrayList[] quadCenters = new ReferenceArrayList[ModelQuadFacing.COUNT]; + private int unalignedQuadCount = 0; + + /** + * List of translucent quads being rendered. + */ + public final ReferenceArrayList quads = new ReferenceArrayList<>(); + + /** + * Indexes of the quads that is non-null if the sort is topological. Static + * normal-relative sorting is handled differently since the indexes aren't mixed + * between normals. + */ + public int[] topoSortResult; public GroupBuilder(ChunkSectionPos sectionPos) { this.sectionPos = sectionPos; } - public void appendQuadCenter(ModelQuadFacing facing, float xSum, float ySum, float zSum) { - var list = this.quadCenters[facing.ordinal()]; - if (list == null) { - list = new ReferenceArrayList<>(); - this.quadCenters[facing.ordinal()] = list; - } - list.add(new Vector3f(xSum * 0.25f, ySum * 0.25f, zSum * 0.25f)); - } + record Quad(Vector3f[] vertices, ModelQuadFacing facing, Vector3fc normal, Vector3f center, float[] extents) { + private static float[] calculateExtents(Vector3f[] vertices, ModelQuadFacing facing) { + // initialize extents to positive or negative infinity + // POS_X, POS_Y, POS_Z, NEG_X, NEG_Y, NEG_Z + float[] extents = new float[] { + Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY, + Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY }; - public void addAlignedFace(ModelQuadFacing facing, float vertexX, float vertexY, float vertexZ) { - if (facing == ModelQuadFacing.UNASSIGNED) { - throw new IllegalArgumentException("Cannot add an unaligned face with addAlignedFace()"); + // TODO: given the facing, in two directions actually only one vertex needs to + // be used as the quad is assumed to be planar + for (int vertIndex = 0; vertIndex < 4; vertIndex++) { + Vector3f vertex = vertices[vertIndex]; + extents[0] = Math.max(extents[0], vertex.x); + extents[1] = Math.max(extents[1], vertex.y); + extents[2] = Math.max(extents[2], vertex.z); + extents[3] = Math.min(extents[3], vertex.x); + extents[4] = Math.min(extents[4], vertex.y); + extents[5] = Math.min(extents[5], vertex.z); + } + + return extents; } - if (this.axisAlignedDistances == null) { - this.axisAlignedDistances = new AccumulationGroup[ModelQuadFacing.DIRECTIONS]; + Quad(Vector3f[] vertices, ModelQuadFacing facing, Vector3fc normal, Vector3f center) { + this(vertices, facing, normal, center, calculateExtents(vertices, facing)); } + } - int index = facing.ordinal(); - AccumulationGroup distances = this.axisAlignedDistances[index]; + public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] vertices, ModelQuadFacing facing) { + float xSum = 0; + float ySum = 0; + float zSum = 0; - if (distances == null) { - distances = new AccumulationGroup(sectionPos, ALIGNED_NORMALS[index], index); - this.axisAlignedDistances[index] = distances; - this.alignedNormalBitmap |= 1 << index; - } + var vertexArray = new Vector3f[4]; + for (int i = 0; i < 4; i++) { + var x = vertices[i].x; + var y = vertices[i].y; + var z = vertices[i].z; - addVertex(distances, vertexX, vertexY, vertexZ); - } + if (facing != ModelQuadFacing.UNASSIGNED && this.unalignedDistances == null) { + minBounds.x = Math.min(minBounds.x, x); + minBounds.y = Math.min(minBounds.y, y); + minBounds.z = Math.min(minBounds.z, z); - public void updateAlignedBounds(float vertexX, float vertexY, float vertexZ) { - if (this.unalignedDistances == null) { - minBounds.x = Math.min(minBounds.x, vertexX); - minBounds.y = Math.min(minBounds.y, vertexY); - minBounds.z = Math.min(minBounds.z, vertexZ); + maxBounds.x = Math.max(maxBounds.x, x); + maxBounds.y = Math.max(maxBounds.y, y); + maxBounds.z = Math.max(maxBounds.z, z); + } - maxBounds.x = Math.max(maxBounds.x, vertexX); - maxBounds.y = Math.max(maxBounds.y, vertexY); - maxBounds.z = Math.max(maxBounds.z, vertexZ); - } - } + xSum += x; + ySum += y; + zSum += z; - public void addUnalignedFace(int normalX, int normalY, int normalZ, - float vertexX, float vertexY, float vertexZ) { - if (this.unalignedDistances == null) { - this.unalignedDistances = new Int2ReferenceLinkedOpenHashMap<>(4); + vertexArray[i] = new Vector3f(x, y, z); } - // the key for the hash map is the normal packed into an int - // the lowest byte is 0xFF to prevent collisions with axis-aligned normals - // (assuming quantization with 32, which is 5 bits per component) - int normalKey = 0xFF | (normalX & 0xFF << 8) | (normalY & 0xFF << 15) | (normalZ & 0xFF << 22); - AccumulationGroup distances = this.unalignedDistances.get(normalKey); + Vector3f firstVertex = vertexArray[0]; + float vertexX = firstVertex.x; + float vertexY = firstVertex.y; + float vertexZ = firstVertex.z; - if (distances == null) { - // actually normalize the vector to ensure it's a unit vector - // for the rest of the process which requires that - Vector3f normal = new Vector3f(normalX, normalY, normalZ); - normal.normalize(); - distances = new AccumulationGroup(sectionPos, normal, normalKey); - this.unalignedDistances.put(normalKey, distances); - } + AccumulationGroup accGroup; + if (facing == ModelQuadFacing.UNASSIGNED) { + int normalX = quadView.getGFNINormX(); + int normalY = quadView.getGFNINormY(); + int normalZ = quadView.getGFNINormZ(); - addVertex(distances, vertexX, vertexY, vertexZ); - } + if (this.unalignedDistances == null) { + this.unalignedDistances = new Int2ReferenceLinkedOpenHashMap<>(4); + } + + // the key for the hash map is the normal packed into an int + // the lowest byte is 0xFF to prevent collisions with axis-aligned normals + // (assuming quantization with 32, which is 5 bits per component) + int normalKey = 0xFF | (normalX & 0xFF << 8) | (normalY & 0xFF << 15) | (normalZ & 0xFF << 22); + accGroup = this.unalignedDistances.get(normalKey); - private void addVertex(AccumulationGroup accGroup, float vertexX, float vertexY, float vertexZ) { - if (accGroup.add(vertexX, vertexY, vertexZ)) { + if (accGroup == null) { + // actually normalize the vector to ensure it's a unit vector + // for the rest of the process which requires that + Vector3f normal = new Vector3f(normalX, normalY, normalZ); + normal.normalize(); + accGroup = new AccumulationGroup(sectionPos, normal, normalKey); + this.unalignedDistances.put(normalKey, accGroup); + } + this.quads.add(new Quad(vertexArray, facing, + accGroup.normal, + new Vector3f(xSum * 0.25f, ySum * 0.25f, zSum * 0.25f))); + this.unalignedQuadCount++; + } else { + if (this.axisAlignedDistances == null) { + this.axisAlignedDistances = new AccumulationGroup[ModelQuadFacing.DIRECTIONS]; + } + + int quadDirection = facing.ordinal(); + accGroup = this.axisAlignedDistances[quadDirection]; + + if (accGroup == null) { + accGroup = new AccumulationGroup(sectionPos, ALIGNED_NORMALS[quadDirection], quadDirection); + this.axisAlignedDistances[quadDirection] = accGroup; + this.alignedNormalBitmap |= 1 << quadDirection; + } + + this.quads.add(new Quad(vertexArray, facing, accGroup.normal, + new Vector3f(xSum * 0.25f, ySum * 0.25f, zSum * 0.25f))); + } + + if (accGroup.addPlaneMember(vertexX, vertexY, vertexZ)) { this.facePlaneCount++; } } @@ -151,21 +233,31 @@ AccumulationGroup getGroupForNormal(NormalList normalList) { * normal-relative distance. The ordering between the two normals is irrelevant * as they can't be seen through each other anyways. * + * E: If there are only three axis-aligned normals or only two normals if there + * is at least one unaligned normal, a static topological sort of the + * see-through graph is enough. The sort is performed on the see-through graph + * consisting of quads as nodes and edges between two quads if the one can be + * seen through the other. The see-through condition is not checked transitively + * which avoids needing to do complex projections of quads onto each other. A + * static sort exists if this graph is acyclic. In the aforementioned cases, the + * graph is known to be acyclic. It can also be acyclic if there are more + * normals, but this would require a search of the graph for cycles. + * * More heuristics can be performed here to conservatively determine if this * section could possibly have more than one translucent sort order. * * @return the required sort type to ensure this section always looks correct */ - SortType getSortType() { + private SortType sortTypeHeuristic() { // special case A if (this.facePlaneCount <= 1) { return SortType.NONE; } if (this.unalignedDistances == null) { - boolean twoOpposingNormals = this.alignedNormalBitmap == 0b11 - || this.alignedNormalBitmap == 0b1100 - || this.alignedNormalBitmap == 0b110000; + boolean twoOpposingNormals = this.alignedNormalBitmap == OPPOSING_X + || this.alignedNormalBitmap == OPPOSING_Y + || this.alignedNormalBitmap == OPPOSING_Z; // special case B // if there are just two normals, they are exact opposites of eachother and they @@ -212,6 +304,11 @@ SortType getSortType() { if (twoOpposingNormals || Integer.bitCount(this.alignedNormalBitmap) == 1) { return SortType.STATIC_NORMAL_RELATIVE; } + + // special case E + if (Integer.bitCount(this.alignedNormalBitmap) <= 3) { + return SortType.STATIC_TOPO_ACYCLIC; + } } else if (this.alignedNormalBitmap == 0) { if (this.unalignedDistances.size() == 1) { // special case D but for one unaligned normal @@ -229,6 +326,225 @@ SortType getSortType() { } } - return SortType.DYNAMIC; + // special case E + if (Integer.bitCount(this.alignedNormalBitmap) + + (this.unalignedDistances == null ? 0 : this.unalignedDistances.size()) <= 2) { + return SortType.STATIC_TOPO_ACYCLIC; + } + + // heuristically determine if a topo sort should be attempted, if the attempt + // fails the sort type is downgraded to DYNAMIC_ALL. If there are no cycles, + // it's upgraded to acyclic. + if (this.unalignedQuadCount <= 2 && this.quads.size() <= 100) { + return SortType.DYNAMIC_TOPO_CYCLIC; + } + + return SortType.DYNAMIC_ALL; + } + + SortType getSortType() { + var sortType = sortTypeHeuristic(); + + // downgrade to cyclic or dynamic if the sorting fails, upgrade from cyclic to + // acyclic if there is no cycle. + if (sortType == SortType.STATIC_TOPO_ACYCLIC + || sortType == SortType.DYNAMIC_TOPO_CYCLIC + || sortType == SortType.DYNAMIC_ALL) { + // TODO: implement topo sort with unaligned quads + if (this.unalignedQuadCount > 0) { + unalignedDynamicHits++; + sortType = SortType.DYNAMIC_ALL; + } else { + // it can only perform topo sort on acyclic graphs since it has no cycle + // breaking, but it will detect cycles and bail to DYNAMIC_ALL + // DYNAMIC_TOPO_CYCLIC if there is a cycle + sortType = topoSortAlignedAcyclic(); + + // TODO: cyclic topo sort with cycle breaking + if (sortType == SortType.DYNAMIC_TOPO_CYCLIC) { + sortType = SortType.DYNAMIC_ALL; + } + } + + System.out.println("topo sort hits: " + topoSortHits + ", cyclic graph hits: " + cyclicGraphHits + + ", unaligned dynamic hits: " + unalignedDynamicHits); + } + + return sortType; + } + + private static boolean orthogonalQuadVisible(Quad quad, Quad otherQuad) { + var otherQuadDirection = otherQuad.facing.ordinal(); + + // this only works because the quads are planar and the extent in the direction + // of the quad's normal is the same as in the opposite direction + return quad.extents[otherQuadDirection] > otherQuad.extents[otherQuadDirection]; + } + + private static final int OUTGOING_EDGES = ModelQuadFacing.DIRECTIONS; + + private static void makeEdge(int[][] graph, BitSet leafQuads, int fromQuadIndex, int toQuadIndex, int direction) { + graph[toQuadIndex][direction] = fromQuadIndex; + + // increment outgoing edges and clear from the no outgoing edges set if it had + // no outgoing edges beforehand + if (graph[fromQuadIndex][OUTGOING_EDGES]++ == 0) { + leafQuads.clear(fromQuadIndex); + } + } + + /** + * This scanning topo sort algorithm assumes that a number of invariants about + * the quads hold: + * - quads are planar and actually have the normal of their facing + * - quads don't intersect + * - quads aren't shaped weirdly + * + * If it manages to find a topological sort, it populates + * {@link #topoSortResult} and returns {@link SortType#STATIC_TOPO_ACYCLIC}. If + * it fails to find a topo sort it returns {@link SortType#DYNAMIC_TOPO_CYCLIC}. + * + * @return the sort type after the topo sort + */ + private SortType topoSortAlignedAcyclic() { + var totalQuadCount = this.quads.size(); + + /** + * The translucent quad visibility graph is stored as an array for each quad. + * Each quad's array stores the indexes of the quads that can see this quad + * through them. The edges are stored backwards to avoid using dynamically + * sized-lists for outgoing edges. + * + * The last entry stores the number of *outgoing* edges. + */ + int[][] graph = new int[totalQuadCount][ModelQuadFacing.DIRECTIONS + 1]; + + // the set of quads that have no outgoing edges + BitSet leafQuads = new BitSet(totalQuadCount); + + for (int i = 0; i < totalQuadCount; i++) { + for (int j = 0; j < ModelQuadFacing.DIRECTIONS; j++) { + graph[i][j] = -1; + } + leafQuads.set(i); + } + + // the stash of quads that have not yet been visible to the scanned quads + BitSet stashedOrthoQuads = new BitSet(totalQuadCount); + + // keep around the allocation of the keys array + float[] keys = new float[totalQuadCount]; + + // to build the graph, perform scans for each direction + for (int direction = 0; direction < ModelQuadFacing.DIRECTIONS; direction++) { + ModelQuadFacing facing = ModelQuadFacing.VALUES[direction]; + ModelQuadFacing oppositeFacing = facing.getOpposite(); + int oppositeDirection = oppositeFacing.ordinal(); + + // generate keys for this direction + for (int i = 0; i < totalQuadCount; i++) { + // get the extent in the opposite direction of the scan because quads that are + // visible from a scanning quad should be before it + keys[i] = this.quads.get(i).extents[oppositeDirection]; + } + + int[] sortedQuads = MergeSort.mergeSort(keys); + + // the index of the last quad facing in scan direction (scanning quad) in the + // sorted quad array + int lastScanQuadPos = -1; + + // perform a scan by going through the sorted quads and making edges between the + // scanning quads and the quads that precede them in the sort order + stashedOrthoQuads.clear(); + for (int quadIndexPos = 0; quadIndexPos < totalQuadCount; quadIndexPos++) { + int quadIndex = sortedQuads[quadIndexPos]; + Quad quad = this.quads.get(quadIndex); + if (quad.facing != facing) { + continue; + } + + // connect to the last scan quad if it exists + if (lastScanQuadPos != -1) { + makeEdge(graph, leafQuads, sortedQuads[lastScanQuadPos], quadIndex, direction); + } + + // check if any of the stashed quads are now visible + for (int stashedQuadIndex = stashedOrthoQuads + .nextSetBit(0); stashedQuadIndex != -1; stashedQuadIndex = stashedOrthoQuads + .nextSetBit(stashedQuadIndex + 1)) { + Quad stashedOrthoQuad = this.quads.get(stashedQuadIndex); + + // if it's visible through the current quad, unstash and connect + if (orthogonalQuadVisible(quad, stashedOrthoQuad)) { + stashedOrthoQuads.clear(stashedQuadIndex); + makeEdge(graph, leafQuads, quadIndex, stashedQuadIndex, direction); + } + } + + // check the quads facing in other directions than the scan facing. + // initially increment to skip the last scan quad. + for (++lastScanQuadPos; lastScanQuadPos < quadIndexPos; lastScanQuadPos++) { + int otherQuadIndex = sortedQuads[lastScanQuadPos]; + Quad otherQuad = this.quads.get(otherQuadIndex); + + // discard quads that face in the opposite direction, they are never visible + if (otherQuad.facing == oppositeFacing) { + continue; + } + + // if it's visible through the current quad, add an edge. + // the quad has a direction that is orthogonal to the scan direction, since + // opposite quads were just ruled out and same facing quads are handled by the + // scan. + if (orthogonalQuadVisible(quad, otherQuad)) { + makeEdge(graph, leafQuads, quadIndex, otherQuadIndex, direction); + } else { + // otherwise stash it to check if it's visible by later quads in the scan + stashedOrthoQuads.set(otherQuadIndex); + } + } + + // lastScanQuad is now at quadIndexPos + } + } + + // the topological sort result of the graph. The order is reversed comapred to + // how topo sort is usually defined, in that the first index points to the quad + // that should be rendered first since it has no outgoing edges (and thus no + // other quads are visible through it). + topoSortResult = new int[totalQuadCount]; + + // iterate through the set of quads with no outgoing edges until there are none + // left. + for (int topoSortPos = 0; topoSortPos < totalQuadCount; topoSortPos++) { + int nextLeafQuadIndex = leafQuads.nextSetBit(0); + + // if there are no leaf quads but not yet all quads have been processed, + // there must be a cycle! + if (nextLeafQuadIndex == -1) { + // since this method may be called if it's known that there are no cycles, when + // they are found it's downgraded to DYNAMIC_TOPO_CYCLIC + cyclicGraphHits++; + return SortType.DYNAMIC_TOPO_CYCLIC; + } + + leafQuads.clear(nextLeafQuadIndex); + + // add it to the topo sort result + topoSortResult[topoSortPos] = nextLeafQuadIndex; + + // remove the edges to this quad and mark them as leaves if that was the last + // outgoing edge they had + for (int direction = 0; direction < ModelQuadFacing.DIRECTIONS; direction++) { + int otherQuadIndex = graph[nextLeafQuadIndex][direction]; + if (otherQuadIndex != -1 && --graph[otherQuadIndex][OUTGOING_EDGES] == 0) { + leafQuads.set(otherQuadIndex); + } + } + } + + topoSortHits++; + return SortType.STATIC_TOPO_ACYCLIC; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/SortType.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/SortType.java index d08329e2bd..12de4613b1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/SortType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/SortType.java @@ -8,7 +8,7 @@ public enum SortType { /** * No sorting is required and the sort order doesn't matter. */ - NONE(false, false), + NONE(false, false, false, false), /** * There is only one sort order. No active sorting is required, but an initial @@ -19,19 +19,42 @@ public enum SortType { * changes, remove this note and adjust StaticTranslucentData and anything that * reads from it to handle UNASSIGNED quads. */ - STATIC_NORMAL_RELATIVE(true, false), + STATIC_NORMAL_RELATIVE(true, false, false, false), + + /** + * There is only one sort order and not active sorting is required, but + * determining the static sort order involves doing a toplogical sort of the + * quads. + */ + STATIC_TOPO_ACYCLIC(true, true, false, false), + + /** + * There is more than one sort order but instead of sorting one each plane + * trigger, a small number of sort orders is precomputed by breaking any cycles + * in the graph. They are swapped out when the cycle-breaking planes are + * triggered in GFNI. + */ + DYNAMIC_TOPO_CYCLIC(true, true, true, false), /** * There are multiple sort orders. Sorting is required every time GFNI triggers * this section. */ - DYNAMIC(true, true); + DYNAMIC_ALL(true, true, true, true); public final boolean needsIndexBuffer; + public final boolean needsDirectionMixing; + public final boolean needsPlaneTrigger; public final boolean needsDynamicSort; - private SortType(boolean needsIndexBuffer, boolean needsDynamicSort) { + private SortType( + boolean needsIndexBuffer, + boolean needsDirectionMixing, + boolean needsPlaneTrigger, + boolean needsDynamicSort) { this.needsIndexBuffer = needsIndexBuffer; + this.needsDirectionMixing = needsDirectionMixing; + this.needsPlaneTrigger = needsPlaneTrigger; this.needsDynamicSort = needsDynamicSort; } } From 64084ccc938ab75e8bb7fd9654ea431ff23fea61 Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 4 Sep 2023 20:23:37 +0200 Subject: [PATCH 020/256] use more efficient bitset init --- .../mods/sodium/client/render/chunk/gfni/GroupBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java index 1c06ae45ac..a26ab8d5ef 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java @@ -421,12 +421,12 @@ private SortType topoSortAlignedAcyclic() { // the set of quads that have no outgoing edges BitSet leafQuads = new BitSet(totalQuadCount); + leafQuads.set(0, totalQuadCount); for (int i = 0; i < totalQuadCount; i++) { for (int j = 0; j < ModelQuadFacing.DIRECTIONS; j++) { graph[i][j] = -1; } - leafQuads.set(i); } // the stash of quads that have not yet been visible to the scanned quads From 22b285bbac0268a283dd56d871c257a64fd92bfd Mon Sep 17 00:00:00 2001 From: douira Date: Thu, 7 Sep 2023 03:33:07 +0200 Subject: [PATCH 021/256] fix scan direction of negative directions --- .../mods/sodium/client/render/chunk/gfni/GroupBuilder.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java index a26ab8d5ef..47adf64e10 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java @@ -440,12 +440,17 @@ private SortType topoSortAlignedAcyclic() { ModelQuadFacing facing = ModelQuadFacing.VALUES[direction]; ModelQuadFacing oppositeFacing = facing.getOpposite(); int oppositeDirection = oppositeFacing.ordinal(); + int sign = switch (facing) { + case POS_X, POS_Y, POS_Z -> 1; + case NEG_X, NEG_Y, NEG_Z -> -1; + default -> throw new IllegalStateException("Unexpected value: " + facing); + }; // generate keys for this direction for (int i = 0; i < totalQuadCount; i++) { // get the extent in the opposite direction of the scan because quads that are // visible from a scanning quad should be before it - keys[i] = this.quads.get(i).extents[oppositeDirection]; + keys[i] = quad.extents[oppositeDirection] * sign; } int[] sortedQuads = MergeSort.mergeSort(keys); From 00f2e0e182a320c217a29afc7cddcc95772e342b Mon Sep 17 00:00:00 2001 From: douira Date: Thu, 7 Sep 2023 03:33:58 +0200 Subject: [PATCH 022/256] fix missing reference --- .../mods/sodium/client/render/chunk/gfni/GroupBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java index 47adf64e10..7e73d4d675 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java @@ -450,7 +450,7 @@ private SortType topoSortAlignedAcyclic() { for (int i = 0; i < totalQuadCount; i++) { // get the extent in the opposite direction of the scan because quads that are // visible from a scanning quad should be before it - keys[i] = quad.extents[oppositeDirection] * sign; + keys[i] = quads.get(i).extents[oppositeDirection] * sign; } int[] sortedQuads = MergeSort.mergeSort(keys); From 50dfd1089de8593f8e06abe0c100cbf713dfd37b Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 8 Sep 2023 02:41:43 +0200 Subject: [PATCH 023/256] fix graph construction, things were switched around --- .../model/quad/properties/ModelQuadFacing.java | 8 ++++++++ .../client/render/chunk/gfni/GroupBuilder.java | 18 ++++++++++-------- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java index 1a81374202..61c1dbf06d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java @@ -42,6 +42,14 @@ public ModelQuadFacing getOpposite() { }; } + public int getSign() { + return switch (this) { + case POS_Y, POS_X, POS_Z -> 1; + case NEG_Y, NEG_X, NEG_Z -> -1; + default -> 0; + }; + } + public Direction toDirection() { return switch (this) { case POS_Y -> Direction.UP; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java index 7e73d4d675..cd3cce9e24 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java @@ -375,12 +375,17 @@ SortType getSortType() { private static boolean orthogonalQuadVisible(Quad quad, Quad otherQuad) { var otherQuadDirection = otherQuad.facing.ordinal(); + var sign = otherQuad.facing.getSign(); // this only works because the quads are planar and the extent in the direction // of the quad's normal is the same as in the opposite direction - return quad.extents[otherQuadDirection] > otherQuad.extents[otherQuadDirection]; + return sign * quad.extents[otherQuadDirection] > sign * otherQuad.extents[otherQuadDirection]; } + /** + * The index in each node's array in the graph where the number of outgoing + * edges is stored. + */ private static final int OUTGOING_EDGES = ModelQuadFacing.DIRECTIONS; private static void makeEdge(int[][] graph, BitSet leafQuads, int fromQuadIndex, int toQuadIndex, int direction) { @@ -440,17 +445,14 @@ private SortType topoSortAlignedAcyclic() { ModelQuadFacing facing = ModelQuadFacing.VALUES[direction]; ModelQuadFacing oppositeFacing = facing.getOpposite(); int oppositeDirection = oppositeFacing.ordinal(); - int sign = switch (facing) { - case POS_X, POS_Y, POS_Z -> 1; - case NEG_X, NEG_Y, NEG_Z -> -1; - default -> throw new IllegalStateException("Unexpected value: " + facing); - }; + int sign = facing.getSign(); // generate keys for this direction for (int i = 0; i < totalQuadCount; i++) { // get the extent in the opposite direction of the scan because quads that are // visible from a scanning quad should be before it - keys[i] = quads.get(i).extents[oppositeDirection] * sign; + Quad quad = this.quads.get(i); + keys[i] = quad.extents[oppositeDirection] * sign * -1; } int[] sortedQuads = MergeSort.mergeSort(keys); @@ -471,7 +473,7 @@ private SortType topoSortAlignedAcyclic() { // connect to the last scan quad if it exists if (lastScanQuadPos != -1) { - makeEdge(graph, leafQuads, sortedQuads[lastScanQuadPos], quadIndex, direction); + makeEdge(graph, leafQuads, quadIndex, sortedQuads[lastScanQuadPos], direction); } // check if any of the stashed quads are now visible From 4b41f2b53e4dc4d6b8be4f28b9c54e66ff070760 Mon Sep 17 00:00:00 2001 From: douira Date: Sun, 10 Sep 2023 02:28:13 +0200 Subject: [PATCH 024/256] use statically-sized bit array instead of bitset --- .../render/chunk/gfni/GroupBuilder.java | 17 +- .../client/util/collections/BitArray.java | 257 ++++++++++++++++++ 2 files changed, 265 insertions(+), 9 deletions(-) create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/util/collections/BitArray.java diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java index cd3cce9e24..ce463ea2d0 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java @@ -1,7 +1,5 @@ package me.jellysquid.mods.sodium.client.render.chunk.gfni; -import java.util.BitSet; - import org.joml.Vector3f; import org.joml.Vector3fc; @@ -10,6 +8,7 @@ import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexEncoder; +import me.jellysquid.mods.sodium.client.util.collections.BitArray; import me.jellysquid.mods.sodium.client.util.sorting.MergeSort; import net.minecraft.util.math.ChunkSectionPos; @@ -388,13 +387,13 @@ private static boolean orthogonalQuadVisible(Quad quad, Quad otherQuad) { */ private static final int OUTGOING_EDGES = ModelQuadFacing.DIRECTIONS; - private static void makeEdge(int[][] graph, BitSet leafQuads, int fromQuadIndex, int toQuadIndex, int direction) { + private static void makeEdge(int[][] graph, BitArray leafQuads, int fromQuadIndex, int toQuadIndex, int direction) { graph[toQuadIndex][direction] = fromQuadIndex; // increment outgoing edges and clear from the no outgoing edges set if it had // no outgoing edges beforehand if (graph[fromQuadIndex][OUTGOING_EDGES]++ == 0) { - leafQuads.clear(fromQuadIndex); + leafQuads.unset(fromQuadIndex); } } @@ -425,7 +424,7 @@ private SortType topoSortAlignedAcyclic() { int[][] graph = new int[totalQuadCount][ModelQuadFacing.DIRECTIONS + 1]; // the set of quads that have no outgoing edges - BitSet leafQuads = new BitSet(totalQuadCount); + BitArray leafQuads = new BitArray(totalQuadCount); leafQuads.set(0, totalQuadCount); for (int i = 0; i < totalQuadCount; i++) { @@ -435,7 +434,7 @@ private SortType topoSortAlignedAcyclic() { } // the stash of quads that have not yet been visible to the scanned quads - BitSet stashedOrthoQuads = new BitSet(totalQuadCount); + BitArray stashedOrthoQuads = new BitArray(totalQuadCount); // keep around the allocation of the keys array float[] keys = new float[totalQuadCount]; @@ -463,7 +462,7 @@ private SortType topoSortAlignedAcyclic() { // perform a scan by going through the sorted quads and making edges between the // scanning quads and the quads that precede them in the sort order - stashedOrthoQuads.clear(); + stashedOrthoQuads.unset(); for (int quadIndexPos = 0; quadIndexPos < totalQuadCount; quadIndexPos++) { int quadIndex = sortedQuads[quadIndexPos]; Quad quad = this.quads.get(quadIndex); @@ -484,7 +483,7 @@ private SortType topoSortAlignedAcyclic() { // if it's visible through the current quad, unstash and connect if (orthogonalQuadVisible(quad, stashedOrthoQuad)) { - stashedOrthoQuads.clear(stashedQuadIndex); + stashedOrthoQuads.unset(stashedQuadIndex); makeEdge(graph, leafQuads, quadIndex, stashedQuadIndex, direction); } } @@ -536,7 +535,7 @@ private SortType topoSortAlignedAcyclic() { return SortType.DYNAMIC_TOPO_CYCLIC; } - leafQuads.clear(nextLeafQuadIndex); + leafQuads.unset(nextLeafQuadIndex); // add it to the topo sort result topoSortResult[topoSortPos] = nextLeafQuadIndex; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/collections/BitArray.java b/src/main/java/me/jellysquid/mods/sodium/client/util/collections/BitArray.java new file mode 100644 index 0000000000..85d3f80a0c --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/collections/BitArray.java @@ -0,0 +1,257 @@ +package me.jellysquid.mods.sodium.client.util.collections; + +import java.util.Arrays; + +public class BitArray { + private static final int ADDRESS_BITS_PER_WORD = 6; + private static final int BITS_PER_WORD = 1 << ADDRESS_BITS_PER_WORD; + private static final int BIT_INDEX_MASK = BITS_PER_WORD - 1; + private static final long WORD_MASK = 0xFFFFFFFFFFFFFFFFL; + + private final long[] words; + private final int count; + + /** + * Returns {@param num} aligned to the next multiple of {@param alignment}. + * + * Taken from https://github.com/CaffeineMC/sodium-fabric/blob/1.19.x/next/components/gfx-utils/src/main/java/net/caffeinemc/gfx/util/misc/MathUtil.java + * + * @param num The number that will be rounded if needed + * @param alignment The multiple that the output will be rounded to (must be a + * power-of-two) + * @return The aligned position, either equal to or greater than {@param num} + */ + private static int align(int num, int alignment) { + int additive = alignment - 1; + int mask = ~additive; + return (num + additive) & mask; + } + + public BitArray(int count) { + this.words = new long[(align(count, BITS_PER_WORD) >> ADDRESS_BITS_PER_WORD)]; + this.count = count; + } + + public boolean get(int index) { + return (this.words[wordIndex(index)] & 1L << bitIndex(index)) != 0; + } + + public void set(int index) { + this.words[wordIndex(index)] |= 1L << bitIndex(index); + } + + public void unset(int index) { + this.words[wordIndex(index)] &= ~(1L << bitIndex(index)); + } + + public void put(int index, boolean value) { + int wordIndex = wordIndex(index); + int bitIndex = bitIndex(index); + long intValue = value ? 1 : 0; + this.words[wordIndex] = (this.words[wordIndex] & ~(1L << bitIndex)) | (intValue << bitIndex); + } + + /** + * Sets the bits from startIdx (inclusive) to endIdx (exclusive) to 1 + */ + public void set(int startIdx, int endIdx) { + int startWordIndex = wordIndex(startIdx); + int endWordIndex = wordIndex(endIdx - 1); + + long firstWordMask = WORD_MASK << startIdx; + long lastWordMask = WORD_MASK >>> -endIdx; + if (startWordIndex == endWordIndex) { + this.words[startWordIndex] |= (firstWordMask & lastWordMask); + } else { + this.words[startWordIndex] |= firstWordMask; + + for (int i = startWordIndex + 1; i < endWordIndex; i++) { + this.words[i] = 0xFFFFFFFFFFFFFFFFL; + } + + this.words[endWordIndex] |= lastWordMask; + } + } + + /** + * Sets the bits from startIdx (inclusive) to endIdx (exclusive) to 0 + */ + public void unset(int startIdx, int endIdx) { + int startWordIndex = wordIndex(startIdx); + int endWordIndex = wordIndex(endIdx - 1); + + long firstWordMask = ~(WORD_MASK << startIdx); + long lastWordMask = ~(WORD_MASK >>> -endIdx); + if (startWordIndex == endWordIndex) { + this.words[startWordIndex] &= (firstWordMask & lastWordMask); + } else { + this.words[startWordIndex] &= firstWordMask; + + for (int i = startWordIndex + 1; i < endWordIndex; i++) { + this.words[i] = 0x0000000000000000L; + } + + this.words[endWordIndex] &= lastWordMask; + } + } + + // FIXME + /* public boolean checkUnset(int startIdx, int endIdx) { + int startWordIndex = wordIndex(startIdx); + int endWordIndex = wordIndex(endIdx - 1); + + long firstWordMask = ~(WORD_MASK << startIdx); + long lastWordMask = ~(WORD_MASK >>> -endIdx); + if (startWordIndex == endWordIndex) { + return (this.words[startWordIndex] & firstWordMask & lastWordMask) == 0x0000000000000000L; + } else { + if ((this.words[startWordIndex] & firstWordMask) != 0x0000000000000000L) { + return false; + } + + for (int i = startWordIndex + 1; i < endWordIndex; i++) { + if (this.words[i] != 0x0000000000000000L) { + return false; + } + } + + return (this.words[endWordIndex] & lastWordMask) == 0x0000000000000000L; + } + }*/ + + public void copy(BitArray src, int startIdx, int endIdx) { + int startWordIndex = wordIndex(startIdx); + int endWordIndex = wordIndex(endIdx - 1); + + long firstWordMask = WORD_MASK << startIdx; + long lastWordMask = WORD_MASK >>> -endIdx; + if (startWordIndex == endWordIndex) { + long combinedMask = firstWordMask & lastWordMask; + long invCombinedMask = ~combinedMask; + this.words[startWordIndex] = (this.words[startWordIndex] & invCombinedMask) + | (src.words[startWordIndex] & combinedMask); + } else { + long invFirstWordMask = ~firstWordMask; + long invLastWordMask = ~lastWordMask; + + this.words[startWordIndex] = (this.words[startWordIndex] & invFirstWordMask) + | (src.words[startWordIndex] & firstWordMask); + + int length = endWordIndex - (startWordIndex + 1); + if (length > 0) { + System.arraycopy( + src.words, + startWordIndex + 1, + this.words, + startWordIndex + 1, + length); + } + + this.words[endWordIndex] = (this.words[endWordIndex] & invLastWordMask) + | (src.words[endWordIndex] & lastWordMask); + } + } + + public void copy(BitArray src, int index) { + int wordIndex = wordIndex(index); + long invBitMask = 1L << bitIndex(index); + long bitMask = ~invBitMask; + this.words[wordIndex] = (this.words[wordIndex] & bitMask) | (src.words[wordIndex] & invBitMask); + } + + public void and(BitArray src, int startIdx, int endIdx) { + int startWordIndex = wordIndex(startIdx); + int endWordIndex = wordIndex(endIdx - 1); + + long firstWordMask = WORD_MASK << startIdx; + long lastWordMask = WORD_MASK >>> -endIdx; + if (startWordIndex == endWordIndex) { + long combinedMask = firstWordMask & lastWordMask; + long invCombinedMask = ~combinedMask; + this.words[startWordIndex] &= (src.words[startWordIndex] | invCombinedMask); + } else { + long invFirstWordMask = ~firstWordMask; + long invLastWordMask = ~lastWordMask; + + this.words[startWordIndex] &= (src.words[startWordIndex] | invFirstWordMask); + + for (int i = startWordIndex + 1; i < endWordIndex; i++) { + this.words[i] &= src.words[i]; + } + + this.words[endWordIndex] &= (src.words[endWordIndex] | invLastWordMask); + } + } + + private static int wordIndex(int index) { + return index >> ADDRESS_BITS_PER_WORD; + } + + private static int bitIndex(int index) { + return index & BIT_INDEX_MASK; + } + + public void fill(boolean value) { + Arrays.fill(this.words, value ? 0xFFFFFFFFFFFFFFFFL : 0x0000000000000000L); + } + + public void unset() { + this.fill(false); + } + + public void set() { + this.fill(true); + } + + public int count() { + int sum = 0; + + for (long word : this.words) { + sum += Long.bitCount(word); + } + + return sum; + } + + public int capacity() { + return this.count; + } + + public boolean getAndSet(int index) { + int wordIndex = wordIndex(index); + long bit = 1L << bitIndex(index); + + long word = this.words[wordIndex]; + this.words[wordIndex] = word | bit; + + return (word & bit) != 0; + } + + public boolean getAndUnset(int index) { + var wordIndex = wordIndex(index); + var bit = 1L << bitIndex(index); + + var word = this.words[wordIndex]; + this.words[wordIndex] = word & ~bit; + + return (word & bit) != 0; + } + + public int nextSetBit(int fromIndex) { + int u = wordIndex(fromIndex); + + long word = this.words[u] & (WORD_MASK << fromIndex); + + while (true) { + if (word != 0) { + return (u * BITS_PER_WORD) + Long.numberOfTrailingZeros(word); + } + + if (++u == this.words.length) { + return -1; + } + + word = this.words[u]; + } + } +} From c2f3a3c77bb244f2e68089e70332f8249e1d2fed Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 11 Sep 2023 03:22:53 +0200 Subject: [PATCH 025/256] refactor build task translucent data results --- .../client/gl/buffer/IndexedVertexData.java | 2 + .../client/render/chunk/RenderSection.java | 2 +- .../render/chunk/RenderSectionManager.java | 4 +- .../chunk/compile/ChunkBuildOutput.java | 2 +- .../render/chunk/compile/ChunkSortOutput.java | 8 +- .../tasks/ChunkBuilderMeshingTask.java | 34 +-- .../chunk/data/DynamicTranslucentData.java | 58 ----- .../chunk/data/StaticTranslucentData.java | 55 ----- .../render/chunk/data/TranslucentData.java | 37 --- .../client/render/chunk/gfni/DynamicData.java | 72 ++++++ .../chunk/gfni/DynamicTopoCyclicData.java | 28 +++ .../sodium/client/render/chunk/gfni/GFNI.java | 41 ++-- .../render/chunk/gfni/GroupBuilder.java | 221 +++++++++++------- .../client/render/chunk/gfni/NoneData.java | 14 ++ .../chunk/gfni/StaticNormalRelativeData.java | 21 ++ .../chunk/gfni/StaticTopoAcyclicData.java | 21 ++ .../render/chunk/gfni/TranslucentData.java | 44 ++++ .../chunk/region/RenderRegionManager.java | 2 +- 18 files changed, 380 insertions(+), 286 deletions(-) delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/DynamicTranslucentData.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/StaticTranslucentData.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/TranslucentData.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicTopoCyclicData.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NoneData.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/IndexedVertexData.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/IndexedVertexData.java index f4860996ed..e70b82c64f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/IndexedVertexData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/IndexedVertexData.java @@ -5,6 +5,8 @@ /** * Helper type for tagging the vertex format alongside the raw buffer data. + * + * TODO: this file is unused? */ public record IndexedVertexData(GlVertexFormat vertexFormat, NativeBuffer vertexBuffer, diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java index 52d761c14d..09f74799ea 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.render.chunk; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionInfo; -import me.jellysquid.mods.sodium.client.render.chunk.data.TranslucentData; +import me.jellysquid.mods.sodium.client.render.chunk.gfni.TranslucentData; import me.jellysquid.mods.sodium.client.render.chunk.occlusion.GraphDirection; import me.jellysquid.mods.sodium.client.render.chunk.occlusion.GraphDirectionSet; import me.jellysquid.mods.sodium.client.render.chunk.occlusion.VisibilityEncoding; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index 59f59baa58..a5dfd74c60 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -313,6 +313,8 @@ private void processChunkBuildResults(ArrayList results) { for (var result : filtered) { this.updateSectionInfo(result.render, result.info); + result.render.setTranslucentData(result.translucentData); + this.gfni.integrateTranslucentData(result.translucentData); var job = result.render.getBuildCancellationToken(); @@ -409,7 +411,7 @@ private void submitRebuildTasks(ChunkJobCollector collector, ChunkUpdateType typ return null; } - return new ChunkBuilderMeshingTask(render, frame, this.cameraPos, context, this.gfni); + return new ChunkBuilderMeshingTask(render, frame, this.cameraPos, context); } public ChunkBuilderSortingTask createSortTask(RenderSection render, int frame) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java index 7ecf640c95..e5ad82a27b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java @@ -3,7 +3,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; -import me.jellysquid.mods.sodium.client.render.chunk.data.TranslucentData; +import me.jellysquid.mods.sodium.client.render.chunk.gfni.TranslucentData; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionInfo; import java.util.Map; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java index 65647f087d..f1f6030736 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java @@ -1,8 +1,12 @@ package me.jellysquid.mods.sodium.client.render.chunk.compile; import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; -import me.jellysquid.mods.sodium.client.render.chunk.data.TranslucentData; +import me.jellysquid.mods.sodium.client.render.chunk.gfni.TranslucentData; +/** + * TODO: translucent data can also be for non-dynamic sort types, so this might + * not make a lot of sense as it is. + */ public class ChunkSortOutput extends BuilderTaskOutput { public final TranslucentData translucentData; @@ -14,6 +18,6 @@ public ChunkSortOutput(RenderSection render, int buildTime, TranslucentData tran @Override public void setDataOn(RenderSection render) { - render.setTranslucentData(translucentData);; + render.setTranslucentData(translucentData); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java index e764a74316..9b770d91f4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java @@ -9,10 +9,9 @@ import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.BlockRenderContext; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionInfo; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; -import me.jellysquid.mods.sodium.client.render.chunk.data.TranslucentData; -import me.jellysquid.mods.sodium.client.render.chunk.gfni.GFNI; import me.jellysquid.mods.sodium.client.render.chunk.gfni.GroupBuilder; import me.jellysquid.mods.sodium.client.render.chunk.gfni.SortType; +import me.jellysquid.mods.sodium.client.render.chunk.gfni.TranslucentData; import me.jellysquid.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses; import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; import me.jellysquid.mods.sodium.client.util.task.CancellationToken; @@ -44,12 +43,10 @@ */ public class ChunkBuilderMeshingTask extends ChunkBuilderTask { private final ChunkRenderContext renderContext; - private final GFNI gfni; - public ChunkBuilderMeshingTask(RenderSection render, int buildTime, Vector3f cameraPos, ChunkRenderContext renderContext, GFNI gfni) { + public ChunkBuilderMeshingTask(RenderSection render, int buildTime, Vector3f cameraPos, ChunkRenderContext renderContext) { super(render, buildTime, cameraPos); this.renderContext = renderContext; - this.gfni = gfni; } @Override @@ -140,38 +137,25 @@ public ChunkBuildOutput execute(ChunkBuildContext buildContext, CancellationToke throw fillCrashInfo(CrashReport.create(ex, "Encountered exception while building chunk meshes"), slice, blockPos); } - SortType sortType = this.gfni.integrateGroupBuilder(context.groupBuilder); - TranslucentData translucentData = null; + SortType sortType = groupBuilder.estimateSortType(); Map meshes = new Reference2ReferenceOpenHashMap<>(); for (TerrainRenderPass pass : DefaultTerrainRenderPasses.ALL) { // consolidate all translucent geometry into UNASSIGNED so that it's rendered - // all together if GFNI's heuristic determines that it needs to be dynamically - // sorted - // boolean isTranslucent = pass == DefaultTerrainRenderPasses.TRANSLUCENT; - // BuiltSectionMeshParts mesh = buffers.createMesh(pass, isTranslucent && sortType.needsDirectionMixing); - BuiltSectionMeshParts mesh = buffers.createMesh(pass, false); + // all together if it needs to share an index buffer between the directions + boolean isTranslucent = pass == DefaultTerrainRenderPasses.TRANSLUCENT; + BuiltSectionMeshParts mesh = buffers.createMesh(pass, isTranslucent && sortType.needsDirectionMixing); if (mesh != null) { meshes.put(pass, mesh); renderData.addRenderPass(pass); - - // TODO: re-enable - // if (isTranslucent) { - // // calculate the primitive centers and initialize indexes for sorting. - // // also does an initial sort - // translucentData = TranslucentData.fromMeshData( - // sortType, context.groupBuilder.quadCenters); - - // // initial sort - // if (translucentData != null) { - // translucentData.sort(this.cameraPos); - // } - // } } } + TranslucentData translucentData = groupBuilder.getTranslucentData( + meshes.get(DefaultTerrainRenderPasses.TRANSLUCENT), cameraPos); + renderData.setOcclusionData(occluder.build()); return new ChunkBuildOutput(this.render, this.buildTime, translucentData, renderData.build(), meshes); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/DynamicTranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/DynamicTranslucentData.java deleted file mode 100644 index f1e01fa611..0000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/DynamicTranslucentData.java +++ /dev/null @@ -1,58 +0,0 @@ -package me.jellysquid.mods.sodium.client.render.chunk.data; - -import org.joml.Vector3f; - -import it.unimi.dsi.fastutil.objects.ReferenceArrayList; -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; -import me.jellysquid.mods.sodium.client.util.sorting.VertexSorters; - -public class DynamicTranslucentData implements TranslucentData { - private IndexedPrimitives data; - - public DynamicTranslucentData(ReferenceArrayList[] centers) { - var length = 0; - for (int i = 0; i < ModelQuadFacing.COUNT; i++) { - var centersForFacing = centers[i]; - if (centersForFacing != null) { - length += centersForFacing.size(); - } - } - var centersArray = new Vector3f[length]; - int index = 0; - for (int i = 0; i < ModelQuadFacing.COUNT; i++) { - var centersForFacing = centers[i]; - if (centersForFacing != null) { - for (var center : centersForFacing) { - centersArray[index++] = center; - } - } - } - this.data = new IndexedPrimitives(centersArray); - } - - @Override - public Vector3f[] getCenters(ModelQuadFacing facing) { - if (facing != ModelQuadFacing.UNASSIGNED) { - throw new UnsupportedOperationException("Cannot get centers for facing other than UNASSIGNED"); - } - return this.data.centers; - } - - @Override - public int[] getIndexes(ModelQuadFacing facing) { - if (facing != ModelQuadFacing.UNASSIGNED) { - throw new UnsupportedOperationException("Cannot get indexes for facing other than UNASSIGNED"); - } - return this.data.indexes; - } - - @Override - public boolean isDynamic() { - return true; - } - - @Override - public void sort(Vector3f cameraPos) { - this.data.indexes = VertexSorters.sortByDistance(cameraPos).sort(this.data.centers); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/StaticTranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/StaticTranslucentData.java deleted file mode 100644 index 9e9d485efa..0000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/StaticTranslucentData.java +++ /dev/null @@ -1,55 +0,0 @@ -package me.jellysquid.mods.sodium.client.render.chunk.data; - -import org.joml.Vector3f; - -import com.mojang.blaze3d.systems.VertexSorter; - -import it.unimi.dsi.fastutil.objects.ReferenceArrayList; -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; -import me.jellysquid.mods.sodium.client.render.chunk.gfni.GFNI; -import me.jellysquid.mods.sodium.client.util.sorting.VertexSorters; - -public class StaticTranslucentData implements TranslucentData { - private final IndexedPrimitives[] data = new IndexedPrimitives[ModelQuadFacing.DIRECTIONS]; - private static final Vector3f[] EMPTY_CENTERS = new Vector3f[0]; - - public StaticTranslucentData(ReferenceArrayList[] centers) { - for (int i = 0; i < ModelQuadFacing.DIRECTIONS; i++) { - var centersForFacing = centers[i]; - if (centersForFacing != null) { - this.data[i] = new IndexedPrimitives(centersForFacing.toArray(EMPTY_CENTERS)); - } - } - } - - @Override - public Vector3f[] getCenters(ModelQuadFacing facing) { - if (facing == ModelQuadFacing.UNASSIGNED) { - throw new UnsupportedOperationException("Cannot get centers for UNASSIGNED facing"); - } - return this.data[facing.ordinal()].centers; - } - - @Override - public int[] getIndexes(ModelQuadFacing facing) { - if (facing == ModelQuadFacing.UNASSIGNED) { - throw new UnsupportedOperationException("Cannot get indexes for UNASSIGNED facing"); - } - return this.data[facing.ordinal()].indexes; - } - - @Override - public boolean isDynamic() { - return false; - } - - @Override - public void sort(Vector3f cameraPos) { - for (int i = 0; i < ModelQuadFacing.DIRECTIONS; i++) { - var dataForFacing = this.data[i]; - if (dataForFacing != null) { - dataForFacing.indexes = GFNI.SORTERS[i].sort(dataForFacing.centers); - } - } - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/TranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/TranslucentData.java deleted file mode 100644 index 85e75d1305..0000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/TranslucentData.java +++ /dev/null @@ -1,37 +0,0 @@ -package me.jellysquid.mods.sodium.client.render.chunk.data; - -import org.joml.Vector3f; - -import it.unimi.dsi.fastutil.objects.ReferenceArrayList; -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; -import me.jellysquid.mods.sodium.client.render.chunk.gfni.SortType; - -/** - * TODO: figure out if the encoded vertex data should be decoded or taken from - * the BlockRenderer directly without decoding the buffers. It would be less - * decoding work, but it would also be unnecessary in some cases where GFNI - * later decides that it's not necessary. - */ -public interface TranslucentData { - public static TranslucentData fromMeshData(SortType sortType, ReferenceArrayList[] centers) { - // TODO: handle new sort types - switch (sortType) { - case NONE: - return null; - case STATIC_NORMAL_RELATIVE: - return new StaticTranslucentData(centers); - case DYNAMIC_ALL: - return new DynamicTranslucentData(centers); - default: - throw new UnsupportedOperationException("Unhandled sort type: " + sortType); - } - } - - public Vector3f[] getCenters(ModelQuadFacing facing); - - public int[] getIndexes(ModelQuadFacing facing); - - public boolean isDynamic(); - - public void sort(Vector3f cameraPos); -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java new file mode 100644 index 0000000000..b74f94a41f --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java @@ -0,0 +1,72 @@ +package me.jellysquid.mods.sodium.client.render.chunk.gfni; + +import org.joml.Vector3f; + +import it.unimi.dsi.fastutil.ints.Int2ReferenceLinkedOpenHashMap; +import me.jellysquid.mods.sodium.client.gl.util.VertexRange; +import me.jellysquid.mods.sodium.client.util.NativeBuffer; +import me.jellysquid.mods.sodium.client.util.sorting.VertexSorters; +import net.minecraft.util.math.ChunkSectionPos; + +class DynamicData extends TranslucentData { + public final Vector3f[] centers; + public final NativeBuffer buffer; + public final VertexRange range; + private AccumulationGroup[] axisAlignedDistances; + private Int2ReferenceLinkedOpenHashMap unalignedDistances; + + public DynamicData(ChunkSectionPos sectionPos, + Vector3f[] centers, NativeBuffer buffer, VertexRange range, + AccumulationGroup[] axisAlignedDistances, + Int2ReferenceLinkedOpenHashMap unalignedDistances) { + super(sectionPos); + this.centers = centers; + this.buffer = buffer; + this.range = range; + this.axisAlignedDistances = axisAlignedDistances; + this.unalignedDistances = unalignedDistances; + } + + @Override + public SortType getSortType() { + return SortType.DYNAMIC_ALL; + } + + AccumulationGroup getGroupForNormal(NormalList normalList) { + int groupBuilderKey = normalList.getGroupBuilderKey(); + if (groupBuilderKey < 0xFF) { + if (this.axisAlignedDistances == null) { + return null; + } + return this.axisAlignedDistances[groupBuilderKey]; + } else { + if (this.unalignedDistances == null) { + return null; + } + return this.unalignedDistances.get(groupBuilderKey); + } + } + + public AccumulationGroup[] getAxisAlignedDistances() { + return this.axisAlignedDistances; + } + + public Int2ReferenceLinkedOpenHashMap getUnalignedDistances() { + return this.unalignedDistances; + } + + public void clearTriggerData() { + this.axisAlignedDistances = null; + this.unalignedDistances = null; + } + + @Override + public void sort(Vector3f cameraPos) { + var intBuffer = this.buffer.getDirectBuffer().asIntBuffer(); + TranslucentData.writeVertexIndexes(intBuffer, VertexSorters.sortByDistance(cameraPos).sort(this.centers)); + + // TODO: flip the int buffer or the byte buffer? Is this even necessary? + // What does this do? + intBuffer.flip(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicTopoCyclicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicTopoCyclicData.java new file mode 100644 index 0000000000..222a874263 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicTopoCyclicData.java @@ -0,0 +1,28 @@ +package me.jellysquid.mods.sodium.client.render.chunk.gfni; + +import org.joml.Vector3fc; + +import it.unimi.dsi.fastutil.objects.ReferenceArrayList; +import me.jellysquid.mods.sodium.client.gl.util.VertexRange; +import me.jellysquid.mods.sodium.client.util.NativeBuffer; +import net.minecraft.util.math.ChunkSectionPos; + +class DynamicTopoCyclicData extends TranslucentData { + public final NativeBuffer buffer; + public final ReferenceArrayList orders; + + public static record SortOrder(VertexRange range, Vector3fc normal, double distance) { + } + + public DynamicTopoCyclicData(ChunkSectionPos sectionPos, + NativeBuffer buffer, ReferenceArrayList orders) { + super(sectionPos); + this.buffer = buffer; + this.orders = orders; + } + + @Override + public SortType getSortType() { + return SortType.DYNAMIC_TOPO_CYCLIC; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java index d7174d739b..c3a15311c2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java @@ -19,17 +19,6 @@ * * Distances are stored as doubles and normals are stored as float vectors. * - * TODO: synchronization is used for integrating group builders submitted from - * chunk build threads. It is assumed that integrating a group builder is fast - * and thus synchronization is not a big problem. However, if it is, it might be - * better to put the group builder in the ChunkSortOutput and have the main - * thread integrate it. The distadvantage is that the main thread would be busy - * with group integration while actually the chunk build thread could be doing - * it itself. If fine grained synchronization is needed, threads could also work - * on integrating individual normal lists in parallel. However, since normal - * lists are created (and possibly deleted) on demand, this would require a more - * complex synchronization scheme. - * * TODO: * - sort the triggered sections by camera distance and possibly also use number * of translucent faces as a heuristic for importance @@ -173,17 +162,25 @@ private void addSectionInNewNormalLists(AccumulationGroup accGroup) { * @param builder the group builder to integrate * @return the sort type that the group builder's relevance heuristic determined */ - public synchronized SortType integrateGroupBuilder(GroupBuilder builder) { - long chunkSectionLongPos = builder.sectionPos.asLong(); + public void integrateTranslucentData(TranslucentData translucentData) { + if (translucentData == null) { + return; // TODO: when does this even happen? + } + long chunkSectionLongPos = translucentData.sectionPos.asLong(); - // if the builder is irrelevant, remove it from the normal lists + // remove the section if the data doesn't need to trigger on face planes // TODO: only do the heuristic and topo sort if the hashes are different? - SortType sortType = builder.getSortType(); + SortType sortType = translucentData.getSortType(); if (!sortType.needsPlaneTrigger) { removeSection(chunkSectionLongPos); - return sortType; + return; } + // TODO: implement cycle breaking and multiple sort orders + if (!(translucentData instanceof DynamicData)) { + throw new RuntimeException("TranslucentData other than DynamicData passed to GFNI"); + } + var dynamicData = (DynamicData) translucentData; int normalListCount = this.normalLists.size(); // go through all normal lists and check against the normals that the group @@ -191,7 +188,7 @@ public synchronized SortType integrateGroupBuilder(GroupBuilder builder) { // builder doesn't, the group is removed. otherwise, the group is updated. for (var normalList : this.normalLists.values()) { // check if the group builder includes data for this normal. - var accGroup = builder.getGroupForNormal(normalList); + var accGroup = dynamicData.getGroupForNormal(normalList); if (normalList.hasSection(chunkSectionLongPos)) { if (accGroup == null) { removeSectionFromList(normalList, chunkSectionLongPos); @@ -206,15 +203,15 @@ public synchronized SortType integrateGroupBuilder(GroupBuilder builder) { // go through the data of the group builder to check for data of new normals // for which there are no normal lists yet. This only checks for new normal // lists since new data for existing normal lists is handled above. - if (builder.axisAlignedDistances != null) { - for (var accGroup : builder.axisAlignedDistances) { + if (dynamicData.getAxisAlignedDistances() != null) { + for (var accGroup : dynamicData.getAxisAlignedDistances()) { if (accGroup != null) { addSectionInNewNormalLists(accGroup); } } } - if (builder.unalignedDistances != null) { - for (var accGroup : builder.unalignedDistances.values()) { + if (dynamicData.getUnalignedDistances() != null) { + for (var accGroup : dynamicData.getUnalignedDistances().values()) { addSectionInNewNormalLists(accGroup); } } @@ -223,7 +220,5 @@ public synchronized SortType integrateGroupBuilder(GroupBuilder builder) { if (normalListCount != this.normalLists.size()) { System.out.println(normalLists.size() + " normal lists"); } - - return sortType; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java index ce463ea2d0..25e220ccc6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java @@ -1,13 +1,18 @@ package me.jellysquid.mods.sodium.client.render.chunk.gfni; +import java.nio.IntBuffer; + import org.joml.Vector3f; import org.joml.Vector3fc; import it.unimi.dsi.fastutil.ints.Int2ReferenceLinkedOpenHashMap; import it.unimi.dsi.fastutil.objects.ReferenceArrayList; +import me.jellysquid.mods.sodium.client.gl.util.VertexRange; import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexEncoder; +import me.jellysquid.mods.sodium.client.util.NativeBuffer; import me.jellysquid.mods.sodium.client.util.collections.BitArray; import me.jellysquid.mods.sodium.client.util.sorting.MergeSort; import net.minecraft.util.math.ChunkSectionPos; @@ -63,43 +68,13 @@ public class GroupBuilder { */ public final ReferenceArrayList quads = new ReferenceArrayList<>(); - /** - * Indexes of the quads that is non-null if the sort is topological. Static - * normal-relative sorting is handled differently since the indexes aren't mixed - * between normals. - */ - public int[] topoSortResult; + public SortType sortType; public GroupBuilder(ChunkSectionPos sectionPos) { this.sectionPos = sectionPos; } - record Quad(Vector3f[] vertices, ModelQuadFacing facing, Vector3fc normal, Vector3f center, float[] extents) { - private static float[] calculateExtents(Vector3f[] vertices, ModelQuadFacing facing) { - // initialize extents to positive or negative infinity - // POS_X, POS_Y, POS_Z, NEG_X, NEG_Y, NEG_Z - float[] extents = new float[] { - Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY, - Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY }; - - // TODO: given the facing, in two directions actually only one vertex needs to - // be used as the quad is assumed to be planar - for (int vertIndex = 0; vertIndex < 4; vertIndex++) { - Vector3f vertex = vertices[vertIndex]; - extents[0] = Math.max(extents[0], vertex.x); - extents[1] = Math.max(extents[1], vertex.y); - extents[2] = Math.max(extents[2], vertex.z); - extents[3] = Math.min(extents[3], vertex.x); - extents[4] = Math.min(extents[4], vertex.y); - extents[5] = Math.min(extents[5], vertex.z); - } - - return extents; - } - - Quad(Vector3f[] vertices, ModelQuadFacing facing, Vector3fc normal, Vector3f center) { - this(vertices, facing, normal, center, calculateExtents(vertices, facing)); - } + record Quad(ModelQuadFacing facing, Vector3fc normal, Vector3f center, float[] extents) { } public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] vertices, ModelQuadFacing facing) { @@ -107,7 +82,12 @@ public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] verti float ySum = 0; float zSum = 0; - var vertexArray = new Vector3f[4]; + // initialize extents to positive or negative infinity + // POS_X, POS_Y, POS_Z, NEG_X, NEG_Y, NEG_Z + float[] extents = new float[] { + Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY, + Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY }; + for (int i = 0; i < 4; i++) { var x = vertices[i].x; var y = vertices[i].y; @@ -123,17 +103,19 @@ public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] verti maxBounds.z = Math.max(maxBounds.z, z); } + extents[0] = Math.max(extents[0], x); + extents[1] = Math.max(extents[1], y); + extents[2] = Math.max(extents[2], z); + extents[3] = Math.min(extents[3], x); + extents[4] = Math.min(extents[4], y); + extents[5] = Math.min(extents[5], z); + xSum += x; ySum += y; zSum += z; - - vertexArray[i] = new Vector3f(x, y, z); } - Vector3f firstVertex = vertexArray[0]; - float vertexX = firstVertex.x; - float vertexY = firstVertex.y; - float vertexZ = firstVertex.z; + var center = new Vector3f(xSum * 0.25f, ySum * 0.25f, zSum * 0.25f); AccumulationGroup accGroup; if (facing == ModelQuadFacing.UNASSIGNED) { @@ -159,9 +141,7 @@ public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] verti accGroup = new AccumulationGroup(sectionPos, normal, normalKey); this.unalignedDistances.put(normalKey, accGroup); } - this.quads.add(new Quad(vertexArray, facing, - accGroup.normal, - new Vector3f(xSum * 0.25f, ySum * 0.25f, zSum * 0.25f))); + this.quads.add(new Quad(facing, accGroup.normal, center, extents)); this.unalignedQuadCount++; } else { if (this.axisAlignedDistances == null) { @@ -177,30 +157,15 @@ public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] verti this.alignedNormalBitmap |= 1 << quadDirection; } - this.quads.add(new Quad(vertexArray, facing, accGroup.normal, - new Vector3f(xSum * 0.25f, ySum * 0.25f, zSum * 0.25f))); + this.quads.add(new Quad(facing, accGroup.normal, center, extents)); } - if (accGroup.addPlaneMember(vertexX, vertexY, vertexZ)) { + var firstVertex = vertices[0]; + if (accGroup.addPlaneMember(firstVertex.x, firstVertex.y, firstVertex.z)) { this.facePlaneCount++; } } - AccumulationGroup getGroupForNormal(NormalList normalList) { - int groupBuilderKey = normalList.getGroupBuilderKey(); - if (groupBuilderKey < 0xFF) { - if (this.axisAlignedDistances == null) { - return null; - } - return this.axisAlignedDistances[groupBuilderKey]; - } else { - if (this.unalignedDistances == null) { - return null; - } - return this.unalignedDistances.get(groupBuilderKey); - } - } - /** * Checks if this group builder is relevant for translucency sort triggering. It * determines a sort type, which is either no sorting, a static sort or a @@ -341,27 +306,118 @@ private SortType sortTypeHeuristic() { return SortType.DYNAMIC_ALL; } - SortType getSortType() { - var sortType = sortTypeHeuristic(); + public SortType estimateSortType() { + this.sortType = sortTypeHeuristic(); + return this.sortType; + } + + private StaticNormalRelativeData constructStaticNormalRelativeData(BuiltSectionMeshParts translucentMesh) { + int vertexCount = 0; + VertexRange[] ranges = translucentMesh.getVertexRanges(); + Vector3f[][] centers = new Vector3f[ModelQuadFacing.COUNT][]; + int[] centerCounters = new int[ModelQuadFacing.COUNT]; + + for (int i = 0; i < ModelQuadFacing.COUNT; i++) { + VertexRange range = ranges[i]; + if (range != null) { + vertexCount += range.vertexCount(); + centers[i] = new Vector3f[range.vertexCount() / TranslucentData.VERTICES_PER_PRIMITIVE]; + } + } + + for (Quad quad : this.quads) { + var direction = quad.facing.ordinal(); + centers[direction][centerCounters[direction]++] = quad.center; + } + + var buffer = new NativeBuffer(vertexCount * TranslucentData.BYTES_PER_INDEX); + IntBuffer bufferBuilder = buffer.getDirectBuffer().asIntBuffer(); + + for (int i = 0; i < ModelQuadFacing.COUNT; i++) { + VertexRange range = ranges[i]; + if (range != null) { + TranslucentData.writeVertexIndexes(bufferBuilder, GFNI.SORTERS[i].sort(centers[i])); + } + } + bufferBuilder.flip(); // TODO: flip the int buffer or the byte buffer? + + return new StaticNormalRelativeData(this.sectionPos, buffer, ranges); + } + + private static VertexRange getUnassignedVertexRange(BuiltSectionMeshParts translucentMesh) { + VertexRange range = translucentMesh.getVertexRanges()[ModelQuadFacing.UNASSIGNED.ordinal()]; + + if (range == null) { + throw new IllegalStateException("No unassigned data in mesh"); + } + + return range; + } + + // NOTE: requires filling the contained buffer afterwards + private StaticTopoAcyclicData constructStaticTopoAcyclicData(BuiltSectionMeshParts translucentMesh) { + VertexRange range = GroupBuilder.getUnassignedVertexRange(translucentMesh); + var buffer = new NativeBuffer(range.vertexCount() * TranslucentData.BYTES_PER_INDEX); + + return new StaticTopoAcyclicData(this.sectionPos, buffer, range); + } + + private DynamicData constructDynamicData(BuiltSectionMeshParts translucentMesh, NativeBuffer reuseBuffer, + Vector3f cameraPos) { + VertexRange range = GroupBuilder.getUnassignedVertexRange(translucentMesh); + int vertexCount = range.vertexCount(); + + if (reuseBuffer == null) { + reuseBuffer = new NativeBuffer(vertexCount * TranslucentData.BYTES_PER_INDEX); + } + + Vector3f[] centers = new Vector3f[vertexCount / TranslucentData.VERTICES_PER_PRIMITIVE]; - // downgrade to cyclic or dynamic if the sorting fails, upgrade from cyclic to - // acyclic if there is no cycle. - if (sortType == SortType.STATIC_TOPO_ACYCLIC - || sortType == SortType.DYNAMIC_TOPO_CYCLIC - || sortType == SortType.DYNAMIC_ALL) { + var dynamicData = new DynamicData(this.sectionPos, + centers, reuseBuffer, range, axisAlignedDistances, unalignedDistances); + dynamicData.sort(cameraPos); + return dynamicData; + } + + public TranslucentData getTranslucentData(BuiltSectionMeshParts translucentMesh, Vector3f cameraPos) { + if (this.sortType == SortType.NONE || translucentMesh == null) { + return new NoneData(this.sectionPos); + } + + if (this.sortType == SortType.STATIC_NORMAL_RELATIVE) { + return constructStaticNormalRelativeData(translucentMesh); + } + + // from this point on we know the estimated sort type requires direction mixing + // (no backface culling) and all vertices are in the UNASSIGNED direction. + NativeBuffer buffer = null; + if (this.sortType == SortType.STATIC_TOPO_ACYCLIC + || this.sortType == SortType.DYNAMIC_TOPO_CYCLIC + || this.sortType == SortType.DYNAMIC_ALL) { // TODO: implement topo sort with unaligned quads if (this.unalignedQuadCount > 0) { unalignedDynamicHits++; - sortType = SortType.DYNAMIC_ALL; + this.sortType = SortType.DYNAMIC_ALL; } else { // it can only perform topo sort on acyclic graphs since it has no cycle // breaking, but it will detect cycles and bail to DYNAMIC_ALL // DYNAMIC_TOPO_CYCLIC if there is a cycle - sortType = topoSortAlignedAcyclic(); - - // TODO: cyclic topo sort with cycle breaking - if (sortType == SortType.DYNAMIC_TOPO_CYCLIC) { - sortType = SortType.DYNAMIC_ALL; + var indexData = constructStaticTopoAcyclicData(translucentMesh); + buffer = indexData.buffer; + IntBuffer indexBuffer = buffer.getDirectBuffer().asIntBuffer(); + + if (topoSortAlignedAcyclic(indexBuffer)) { + topoSortHits++; + + // I don't understand what this does + // TODO: flip the int buffer or the byte buffer? + indexBuffer.flip(); + return indexData; + } else { + // TODO: cyclic topo sort with cycle breaking + cyclicGraphHits++; + + this.sortType = SortType.DYNAMIC_ALL; } } @@ -369,7 +425,11 @@ SortType getSortType() { + ", unaligned dynamic hits: " + unalignedDynamicHits); } - return sortType; + if (this.sortType == SortType.DYNAMIC_ALL) { + return constructDynamicData(translucentMesh, buffer, cameraPos); + } + + throw new IllegalStateException("Unknown sort type: " + this.sortType); } private static boolean orthogonalQuadVisible(Quad quad, Quad otherQuad) { @@ -408,9 +468,9 @@ private static void makeEdge(int[][] graph, BitArray leafQuads, int fromQuadInde * {@link #topoSortResult} and returns {@link SortType#STATIC_TOPO_ACYCLIC}. If * it fails to find a topo sort it returns {@link SortType#DYNAMIC_TOPO_CYCLIC}. * - * @return the sort type after the topo sort + * @return if the sort was successful */ - private SortType topoSortAlignedAcyclic() { + private boolean topoSortAlignedAcyclic(IntBuffer indexBuffer) { var totalQuadCount = this.quads.size(); /** @@ -519,7 +579,6 @@ private SortType topoSortAlignedAcyclic() { // how topo sort is usually defined, in that the first index points to the quad // that should be rendered first since it has no outgoing edges (and thus no // other quads are visible through it). - topoSortResult = new int[totalQuadCount]; // iterate through the set of quads with no outgoing edges until there are none // left. @@ -531,14 +590,13 @@ private SortType topoSortAlignedAcyclic() { if (nextLeafQuadIndex == -1) { // since this method may be called if it's known that there are no cycles, when // they are found it's downgraded to DYNAMIC_TOPO_CYCLIC - cyclicGraphHits++; - return SortType.DYNAMIC_TOPO_CYCLIC; + return false; } leafQuads.unset(nextLeafQuadIndex); // add it to the topo sort result - topoSortResult[topoSortPos] = nextLeafQuadIndex; + TranslucentData.putQuadVertexIndexes(indexBuffer, nextLeafQuadIndex); // remove the edges to this quad and mark them as leaves if that was the last // outgoing edge they had @@ -550,7 +608,6 @@ private SortType topoSortAlignedAcyclic() { } } - topoSortHits++; - return SortType.STATIC_TOPO_ACYCLIC; + return true; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NoneData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NoneData.java new file mode 100644 index 0000000000..2d16f18789 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NoneData.java @@ -0,0 +1,14 @@ +package me.jellysquid.mods.sodium.client.render.chunk.gfni; + +import net.minecraft.util.math.ChunkSectionPos; + +class NoneData extends TranslucentData { + public NoneData(ChunkSectionPos sectionPos) { + super(sectionPos); + } + + @Override + public SortType getSortType() { + return SortType.NONE; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java new file mode 100644 index 0000000000..0a3cf19d3f --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java @@ -0,0 +1,21 @@ +package me.jellysquid.mods.sodium.client.render.chunk.gfni; + +import me.jellysquid.mods.sodium.client.gl.util.VertexRange; +import me.jellysquid.mods.sodium.client.util.NativeBuffer; +import net.minecraft.util.math.ChunkSectionPos; + +class StaticNormalRelativeData extends TranslucentData { + public final NativeBuffer buffer; + public final VertexRange[] ranges; + + public StaticNormalRelativeData(ChunkSectionPos sectionPos, NativeBuffer buffer, VertexRange[] ranges) { + super(sectionPos); + this.buffer = buffer; + this.ranges = ranges; + } + + @Override + public SortType getSortType() { + return SortType.STATIC_NORMAL_RELATIVE; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java new file mode 100644 index 0000000000..b3f919d508 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java @@ -0,0 +1,21 @@ +package me.jellysquid.mods.sodium.client.render.chunk.gfni; + +import me.jellysquid.mods.sodium.client.gl.util.VertexRange; +import me.jellysquid.mods.sodium.client.util.NativeBuffer; +import net.minecraft.util.math.ChunkSectionPos; + +class StaticTopoAcyclicData extends TranslucentData { + public final NativeBuffer buffer; + public final VertexRange range; + + public StaticTopoAcyclicData(ChunkSectionPos sectionPos, NativeBuffer buffer, VertexRange range) { + super(sectionPos); + this.buffer = buffer; + this.range = range; + } + + @Override + public SortType getSortType() { + return SortType.STATIC_TOPO_ACYCLIC; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java new file mode 100644 index 0000000000..cf4b36862e --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java @@ -0,0 +1,44 @@ +package me.jellysquid.mods.sodium.client.render.chunk.gfni; + +import java.nio.IntBuffer; + +import org.joml.Vector3f; + +import net.minecraft.util.math.ChunkSectionPos; + +public abstract class TranslucentData { + public static final int ELEMENTS_PER_PRIMITIVE = 6; + public static final int VERTICES_PER_PRIMITIVE = 4; + public static final int BYTES_PER_INDEX = 4; + + public final ChunkSectionPos sectionPos; + + public TranslucentData(ChunkSectionPos sectionPos) { + this.sectionPos = sectionPos; + } + + public abstract SortType getSortType(); + + public void sort(Vector3f cameraPos) { + // there should be no sort calls to data that doesn't need sorting + throw new UnsupportedOperationException(); + } + + public static void putQuadVertexIndexes(IntBuffer intBuffer, int quadIndex) { + int vertexOffset = quadIndex * VERTICES_PER_PRIMITIVE; + + intBuffer.put(vertexOffset + 0); + intBuffer.put(vertexOffset + 1); + intBuffer.put(vertexOffset + 2); + + intBuffer.put(vertexOffset + 2); + intBuffer.put(vertexOffset + 3); + intBuffer.put(vertexOffset + 0); + } + + public static void writeVertexIndexes(IntBuffer intBuffer, int[] quadIndexes) { + for (int quadIndexPos = 0; quadIndexPos < quadIndexes.length; quadIndexPos++) { + putQuadVertexIndexes(intBuffer, quadIndexes[quadIndexPos]); + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java index 6ba3f4b6bd..b39da2f888 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java @@ -13,7 +13,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildOutput; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; -import me.jellysquid.mods.sodium.client.render.chunk.data.TranslucentData; +import me.jellysquid.mods.sodium.client.render.chunk.gfni.TranslucentData; import me.jellysquid.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses; import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; import org.jetbrains.annotations.NotNull; From 8864cc7d00a1eef10eddb4f185931f4463362882 Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 11 Sep 2023 13:18:37 +0200 Subject: [PATCH 026/256] remove unnecessary flips --- .../mods/sodium/client/render/chunk/gfni/DynamicData.java | 4 ---- .../mods/sodium/client/render/chunk/gfni/GroupBuilder.java | 4 ---- 2 files changed, 8 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java index b74f94a41f..d05b05c494 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java @@ -64,9 +64,5 @@ public void clearTriggerData() { public void sort(Vector3f cameraPos) { var intBuffer = this.buffer.getDirectBuffer().asIntBuffer(); TranslucentData.writeVertexIndexes(intBuffer, VertexSorters.sortByDistance(cameraPos).sort(this.centers)); - - // TODO: flip the int buffer or the byte buffer? Is this even necessary? - // What does this do? - intBuffer.flip(); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java index 25e220ccc6..411fd35c2b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java @@ -339,7 +339,6 @@ private StaticNormalRelativeData constructStaticNormalRelativeData(BuiltSectionM TranslucentData.writeVertexIndexes(bufferBuilder, GFNI.SORTERS[i].sort(centers[i])); } } - bufferBuilder.flip(); // TODO: flip the int buffer or the byte buffer? return new StaticNormalRelativeData(this.sectionPos, buffer, ranges); } @@ -409,9 +408,6 @@ public TranslucentData getTranslucentData(BuiltSectionMeshParts translucentMesh, if (topoSortAlignedAcyclic(indexBuffer)) { topoSortHits++; - // I don't understand what this does - // TODO: flip the int buffer or the byte buffer? - indexBuffer.flip(); return indexData; } else { // TODO: cyclic topo sort with cycle breaking From bd49744721c4adae547f17b0317eddda3d2801e0 Mon Sep 17 00:00:00 2001 From: douira Date: Tue, 12 Sep 2023 03:12:32 +0200 Subject: [PATCH 027/256] refactor translucent data classes to re-use code --- .../client/render/chunk/gfni/DynamicData.java | 10 +++------- .../render/chunk/gfni/DynamicTopoCyclicData.java | 6 ++---- .../client/render/chunk/gfni/GroupBuilder.java | 16 ++++++++++------ .../render/chunk/gfni/MixedDirectionData.java | 14 ++++++++++++++ .../client/render/chunk/gfni/NoneData.java | 6 +++++- .../chunk/gfni/PresentTranslucentData.java | 13 +++++++++++++ .../chunk/gfni/StaticNormalRelativeData.java | 6 ++---- .../render/chunk/gfni/StaticTopoAcyclicData.java | 9 ++------- .../render/chunk/gfni/TranslucentData.java | 11 ++++++++--- 9 files changed, 59 insertions(+), 32 deletions(-) create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/MixedDirectionData.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/PresentTranslucentData.java diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java index d05b05c494..4c81cb29f1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java @@ -8,21 +8,17 @@ import me.jellysquid.mods.sodium.client.util.sorting.VertexSorters; import net.minecraft.util.math.ChunkSectionPos; -class DynamicData extends TranslucentData { +public class DynamicData extends MixedDirectionData { public final Vector3f[] centers; - public final NativeBuffer buffer; - public final VertexRange range; private AccumulationGroup[] axisAlignedDistances; private Int2ReferenceLinkedOpenHashMap unalignedDistances; public DynamicData(ChunkSectionPos sectionPos, - Vector3f[] centers, NativeBuffer buffer, VertexRange range, + NativeBuffer buffer, VertexRange range, Vector3f[] centers, AccumulationGroup[] axisAlignedDistances, Int2ReferenceLinkedOpenHashMap unalignedDistances) { - super(sectionPos); + super(sectionPos, buffer, range); this.centers = centers; - this.buffer = buffer; - this.range = range; this.axisAlignedDistances = axisAlignedDistances; this.unalignedDistances = unalignedDistances; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicTopoCyclicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicTopoCyclicData.java index 222a874263..b969690157 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicTopoCyclicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicTopoCyclicData.java @@ -7,8 +7,7 @@ import me.jellysquid.mods.sodium.client.util.NativeBuffer; import net.minecraft.util.math.ChunkSectionPos; -class DynamicTopoCyclicData extends TranslucentData { - public final NativeBuffer buffer; +public class DynamicTopoCyclicData extends PresentTranslucentData { public final ReferenceArrayList orders; public static record SortOrder(VertexRange range, Vector3fc normal, double distance) { @@ -16,8 +15,7 @@ public static record SortOrder(VertexRange range, Vector3fc normal, double dista public DynamicTopoCyclicData(ChunkSectionPos sectionPos, NativeBuffer buffer, ReferenceArrayList orders) { - super(sectionPos); - this.buffer = buffer; + super(sectionPos, buffer); this.orders = orders; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java index 411fd35c2b..7c12aafa20 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java @@ -321,7 +321,7 @@ private StaticNormalRelativeData constructStaticNormalRelativeData(BuiltSectionM VertexRange range = ranges[i]; if (range != null) { vertexCount += range.vertexCount(); - centers[i] = new Vector3f[range.vertexCount() / TranslucentData.VERTICES_PER_PRIMITIVE]; + centers[i] = new Vector3f[range.vertexCount() / TranslucentData.VERTICES_PER_QUAD]; } } @@ -330,7 +330,7 @@ private StaticNormalRelativeData constructStaticNormalRelativeData(BuiltSectionM centers[direction][centerCounters[direction]++] = quad.center; } - var buffer = new NativeBuffer(vertexCount * TranslucentData.BYTES_PER_INDEX); + var buffer = new NativeBuffer(TranslucentData.vertexCountToIndexBytes(vertexCount)); IntBuffer bufferBuilder = buffer.getDirectBuffer().asIntBuffer(); for (int i = 0; i < ModelQuadFacing.COUNT; i++) { @@ -356,7 +356,7 @@ private static VertexRange getUnassignedVertexRange(BuiltSectionMeshParts transl // NOTE: requires filling the contained buffer afterwards private StaticTopoAcyclicData constructStaticTopoAcyclicData(BuiltSectionMeshParts translucentMesh) { VertexRange range = GroupBuilder.getUnassignedVertexRange(translucentMesh); - var buffer = new NativeBuffer(range.vertexCount() * TranslucentData.BYTES_PER_INDEX); + var buffer = new NativeBuffer(TranslucentData.vertexCountToIndexBytes(range.vertexCount())); return new StaticTopoAcyclicData(this.sectionPos, buffer, range); } @@ -367,13 +367,17 @@ private DynamicData constructDynamicData(BuiltSectionMeshParts translucentMesh, int vertexCount = range.vertexCount(); if (reuseBuffer == null) { - reuseBuffer = new NativeBuffer(vertexCount * TranslucentData.BYTES_PER_INDEX); + reuseBuffer = new NativeBuffer(TranslucentData.vertexCountToIndexBytes(vertexCount)); } - Vector3f[] centers = new Vector3f[vertexCount / TranslucentData.VERTICES_PER_PRIMITIVE]; + Vector3f[] centers = new Vector3f[vertexCount / TranslucentData.VERTICES_PER_QUAD]; + + for (int i = 0; i < this.quads.size(); i++) { + centers[i] = this.quads.get(i).center; + } var dynamicData = new DynamicData(this.sectionPos, - centers, reuseBuffer, range, axisAlignedDistances, unalignedDistances); + reuseBuffer, range, centers, axisAlignedDistances, unalignedDistances); dynamicData.sort(cameraPos); return dynamicData; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/MixedDirectionData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/MixedDirectionData.java new file mode 100644 index 0000000000..342581fd35 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/MixedDirectionData.java @@ -0,0 +1,14 @@ +package me.jellysquid.mods.sodium.client.render.chunk.gfni; + +import me.jellysquid.mods.sodium.client.gl.util.VertexRange; +import me.jellysquid.mods.sodium.client.util.NativeBuffer; +import net.minecraft.util.math.ChunkSectionPos; + +public abstract class MixedDirectionData extends PresentTranslucentData { + public final VertexRange range; + + public MixedDirectionData(ChunkSectionPos sectionPos, NativeBuffer buffer, VertexRange range) { + super(sectionPos, buffer); + this.range = range; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NoneData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NoneData.java index 2d16f18789..c14ff396e7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NoneData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NoneData.java @@ -2,7 +2,11 @@ import net.minecraft.util.math.ChunkSectionPos; -class NoneData extends TranslucentData { +/** + * None translucent data exists to signal to GFNI that if a section previously + * had triggering data, it no longer does and should be removed. + */ +public class NoneData extends TranslucentData { public NoneData(ChunkSectionPos sectionPos) { super(sectionPos); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/PresentTranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/PresentTranslucentData.java new file mode 100644 index 0000000000..cdc6ac71ec --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/PresentTranslucentData.java @@ -0,0 +1,13 @@ +package me.jellysquid.mods.sodium.client.render.chunk.gfni; + +import me.jellysquid.mods.sodium.client.util.NativeBuffer; +import net.minecraft.util.math.ChunkSectionPos; + +public abstract class PresentTranslucentData extends TranslucentData { + public final NativeBuffer buffer; + + public PresentTranslucentData(ChunkSectionPos sectionPos, NativeBuffer buffer) { + super(sectionPos); + this.buffer = buffer; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java index 0a3cf19d3f..b925a0757d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java @@ -4,13 +4,11 @@ import me.jellysquid.mods.sodium.client.util.NativeBuffer; import net.minecraft.util.math.ChunkSectionPos; -class StaticNormalRelativeData extends TranslucentData { - public final NativeBuffer buffer; +public class StaticNormalRelativeData extends PresentTranslucentData { public final VertexRange[] ranges; public StaticNormalRelativeData(ChunkSectionPos sectionPos, NativeBuffer buffer, VertexRange[] ranges) { - super(sectionPos); - this.buffer = buffer; + super(sectionPos, buffer); this.ranges = ranges; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java index b3f919d508..0c2f40168d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java @@ -4,14 +4,9 @@ import me.jellysquid.mods.sodium.client.util.NativeBuffer; import net.minecraft.util.math.ChunkSectionPos; -class StaticTopoAcyclicData extends TranslucentData { - public final NativeBuffer buffer; - public final VertexRange range; - +public class StaticTopoAcyclicData extends MixedDirectionData { public StaticTopoAcyclicData(ChunkSectionPos sectionPos, NativeBuffer buffer, VertexRange range) { - super(sectionPos); - this.buffer = buffer; - this.range = range; + super(sectionPos, buffer, range); } @Override diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java index cf4b36862e..0bd450c6aa 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java @@ -7,8 +7,8 @@ import net.minecraft.util.math.ChunkSectionPos; public abstract class TranslucentData { - public static final int ELEMENTS_PER_PRIMITIVE = 6; - public static final int VERTICES_PER_PRIMITIVE = 4; + public static final int INDICES_PER_QUAD = 6; + public static final int VERTICES_PER_QUAD = 4; public static final int BYTES_PER_INDEX = 4; public final ChunkSectionPos sectionPos; @@ -24,8 +24,13 @@ public void sort(Vector3f cameraPos) { throw new UnsupportedOperationException(); } + public static int vertexCountToIndexBytes(int vertexCount) { + // convert vertex count to quads, and then to indices, and then to bytes + return vertexCount / VERTICES_PER_QUAD * INDICES_PER_QUAD * BYTES_PER_INDEX; + } + public static void putQuadVertexIndexes(IntBuffer intBuffer, int quadIndex) { - int vertexOffset = quadIndex * VERTICES_PER_PRIMITIVE; + int vertexOffset = quadIndex * INDICES_PER_QUAD; intBuffer.put(vertexOffset + 0); intBuffer.put(vertexOffset + 1); From 3158324cae209d5a4e2ba0bd9e45c8ff328aa182 Mon Sep 17 00:00:00 2001 From: douira Date: Tue, 12 Sep 2023 03:19:15 +0200 Subject: [PATCH 028/256] rough attempt at using index buffers --- .../render/chunk/DefaultChunkRenderer.java | 49 +++++++++-- .../render/chunk/region/RenderRegion.java | 45 +++++++++- .../chunk/region/RenderRegionManager.java | 83 ++++++++++++++----- 3 files changed, 149 insertions(+), 28 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java index d0e9a70aaf..82d22717b7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java @@ -18,6 +18,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.region.RenderRegion; import me.jellysquid.mods.sodium.client.render.chunk.shader.ChunkShaderBindingPoints; import me.jellysquid.mods.sodium.client.render.chunk.shader.ChunkShaderInterface; +import me.jellysquid.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses; import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkMeshAttribute; import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexType; @@ -47,6 +48,7 @@ public void render(ChunkRenderMatrices matrices, CameraTransform camera) { super.begin(renderPass); + boolean isTranslucent = renderPass == DefaultTerrainRenderPasses.TRANSLUCENT; boolean useBlockFaceCulling = SodiumClientMod.options().performance.useBlockFaceCulling; ChunkShaderInterface shader = this.activeProgram.getInterface(); @@ -60,20 +62,26 @@ public void render(ChunkRenderMatrices matrices, var region = renderList.getRegion(); var storage = region.getStorage(renderPass); + SectionRenderDataStorage indexDataStorage = null; + if (isTranslucent) { + indexDataStorage = region.getTranslucentStorage(); + } if (storage == null) { continue; } - fillCommandBuffer(this.batch, region, storage, renderList, camera, renderPass, useBlockFaceCulling); + fillCommandBuffer(this.batch, region, storage, indexDataStorage, renderList, camera, renderPass, useBlockFaceCulling); if (this.batch.isEmpty()) { continue; } - this.sharedIndexBuffer.ensureCapacity(commandList, this.batch.getIndexBufferSize()); + if (!isTranslucent) { + this.sharedIndexBuffer.ensureCapacity(commandList, this.batch.getIndexBufferSize()); + } - var tessellation = this.prepareTessellation(commandList, region); + var tessellation = this.prepareTessellation(commandList, region, isTranslucent); setModelMatrixUniforms(shader, region, camera); executeDrawBatch(commandList, tessellation, this.batch); @@ -85,6 +93,7 @@ public void render(ChunkRenderMatrices matrices, private static void fillCommandBuffer(MultiDrawBatch batch, RenderRegion renderRegion, SectionRenderDataStorage renderDataStorage, + SectionRenderDataStorage indexDataStorage, ChunkRenderList renderList, CameraTransform camera, TerrainRenderPass pass, @@ -108,7 +117,11 @@ private static void fillCommandBuffer(MultiDrawBatch batch, int chunkY = originY + LocalSectionIndex.unpackY(sectionIndex); int chunkZ = originZ + LocalSectionIndex.unpackZ(sectionIndex); - var pMeshData = renderDataStorage.getDataPointer(sectionIndex); + long pMeshData = renderDataStorage.getDataPointer(sectionIndex); + long pIndexData = -1; + if (indexDataStorage != null) { + pIndexData = indexDataStorage.getDataPointer(sectionIndex); + } int slices; @@ -121,13 +134,14 @@ private static void fillCommandBuffer(MultiDrawBatch batch, slices &= SectionRenderDataUnsafe.getSliceMask(pMeshData); if (slices != 0) { - addDrawCommands(batch, pMeshData, slices); + addDrawCommands(batch, pMeshData, slices, pIndexData); } } } @SuppressWarnings("IntegerMultiplicationImplicitCastToLong") - private static void addDrawCommands(MultiDrawBatch batch, long pMeshData, int mask) { + private static void addDrawCommands(MultiDrawBatch batch, long pMeshData, int mask, long pIndexData) { + final var pElementPointer = batch.pElementPointer; final var pBaseVertex = batch.pBaseVertex; final var pElementCount = batch.pElementCount; @@ -136,6 +150,10 @@ private static void addDrawCommands(MultiDrawBatch batch, long pMeshData, int ma for (int facing = 0; facing < ModelQuadFacing.COUNT; facing++) { MemoryUtil.memPutInt(pBaseVertex + (size << 2), SectionRenderDataUnsafe.getVertexOffset(pMeshData, facing)); MemoryUtil.memPutInt(pElementCount + (size << 2), SectionRenderDataUnsafe.getElementCount(pMeshData, facing)); + if (pIndexData != -1) { + // TODO: I don't think this is correct + MemoryUtil.memPutAddress(pElementPointer + (size << 2), pIndexData); + } size += (mask >> facing) & 1; } @@ -206,12 +224,17 @@ private static float getCameraTranslation(int chunkBlockPos, int cameraBlockPos, return (chunkBlockPos - cameraBlockPos) - cameraPos; } - private GlTessellation prepareTessellation(CommandList commandList, RenderRegion region) { + private GlTessellation prepareTessellation(CommandList commandList, RenderRegion region, boolean translucent) { var resources = region.getResources(); var tessellation = resources.getTessellation(); if (tessellation == null) { - resources.updateTessellation(commandList, tessellation = this.createRegionTessellation(commandList, resources)); + if (translucent) { + tessellation = this.createIndexedRegionTessellation(commandList, resources); + } else { + tessellation = this.createRegionTessellation(commandList, resources); + } + resources.updateTessellation(commandList, tessellation); } return tessellation; @@ -227,6 +250,16 @@ private GlTessellation createRegionTessellation(CommandList commandList, RenderR }); } + private GlTessellation createIndexedRegionTessellation(CommandList commandList, RenderRegion.DeviceResources resources) { + return commandList.createTessellation(GlPrimitiveType.TRIANGLES, new TessellationBinding[] { + TessellationBinding.forVertexBuffer(resources.getVertexBuffer(), new GlVertexAttributeBinding[] { + new GlVertexAttributeBinding(ChunkShaderBindingPoints.ATTRIBUTE_PACKED_DATA, + this.vertexFormat.getAttribute(ChunkMeshAttribute.VERTEX_DATA)) + }), + TessellationBinding.forElementBuffer(resources.getIndexBuffer()) + }); + } + private static void executeDrawBatch(CommandList commandList, GlTessellation tessellation, MultiDrawBatch batch) { try (DrawCommandList drawCommandList = commandList.beginTessellating(tessellation)) { drawCommandList.multiDrawElementsBaseVertex(batch, GlIndexType.UNSIGNED_INT); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java index e41da2387e..51b2753ee2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java @@ -8,6 +8,7 @@ import me.jellysquid.mods.sodium.client.gl.tessellation.GlTessellation; import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; import me.jellysquid.mods.sodium.client.render.chunk.data.SectionRenderDataStorage; +import me.jellysquid.mods.sodium.client.render.chunk.gfni.TranslucentData; import me.jellysquid.mods.sodium.client.render.chunk.lists.ChunkRenderList; import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkMeshFormats; @@ -48,6 +49,7 @@ public class RenderRegion { private int sectionCount; private final Map sectionRenderData = new Reference2ReferenceOpenHashMap<>(); + private SectionRenderDataStorage translucentIndexData = null; private DeviceResources resources; public RenderRegion(int x, int y, int z, StagingBuffer stagingBuffer) { @@ -91,6 +93,9 @@ public void delete(CommandList commandList) { for (var storage : this.sectionRenderData.values()) { storage.delete(); } + if (this.translucentIndexData != null) { + this.translucentIndexData.delete(); + } this.sectionRenderData.clear(); @@ -110,6 +115,10 @@ public SectionRenderDataStorage getStorage(TerrainRenderPass pass) { return this.sectionRenderData.get(pass); } + public SectionRenderDataStorage getTranslucentStorage() { + return this.translucentIndexData; + } + public SectionRenderDataStorage createStorage(TerrainRenderPass pass) { var storage = this.sectionRenderData.get(pass); @@ -120,6 +129,14 @@ public SectionRenderDataStorage createStorage(TerrainRenderPass pass) { return storage; } + public SectionRenderDataStorage createTranslucentStorage() { + if (this.translucentIndexData == null) { + return this.translucentIndexData = new SectionRenderDataStorage(); + } + + return this.translucentIndexData; + } + public void refresh(CommandList commandList) { if (this.resources != null) { this.resources.deleteTessellations(commandList); @@ -130,6 +147,16 @@ public void refresh(CommandList commandList) { } } + public void refreshTranslucent(CommandList commandList) { + if (this.resources != null) { + this.resources.deleteTessellations(commandList); + } + + if (this.translucentIndexData != null) { + this.translucentIndexData.onBufferResized(); + } + } + public void addSection(RenderSection section) { var sectionIndex = section.getSectionIndex(); var prev = this.sections[sectionIndex]; @@ -155,6 +182,9 @@ public void removeSection(RenderSection section) { for (var storage : this.sectionRenderData.values()) { storage.removeMeshes(sectionIndex); } + if (this.translucentIndexData != null) { + this.translucentIndexData.removeMeshes(sectionIndex); + } this.sections[sectionIndex] = null; this.sectionCount--; @@ -189,11 +219,15 @@ public ChunkRenderList getRenderList() { public static class DeviceResources { private final GlBufferArena geometryArena; + private final GlBufferArena indexArena; private GlTessellation tessellation; public DeviceResources(CommandList commandList, StagingBuffer stagingBuffer) { int stride = ChunkMeshFormats.COMPACT.getVertexFormat().getStride(); this.geometryArena = new GlBufferArena(commandList, REGION_SIZE * 756, stride, stagingBuffer); + + // TODO: what size should this be intially? Should this be using the same staging buffer? + this.indexArena = new GlBufferArena(commandList, REGION_SIZE * 756, TranslucentData.BYTES_PER_INDEX, stagingBuffer); } public void updateTessellation(CommandList commandList, GlTessellation tessellation) { @@ -219,17 +253,26 @@ public GlBuffer getVertexBuffer() { return this.geometryArena.getBufferObject(); } + public GlBuffer getIndexBuffer() { + return this.indexArena.getBufferObject(); + } + public void delete(CommandList commandList) { this.deleteTessellations(commandList); this.geometryArena.delete(commandList); + this.indexArena.delete(commandList); } public GlBufferArena getGeometryArena() { return this.geometryArena; } + public GlBufferArena getIndexArena() { + return this.indexArena; + } + public boolean shouldDelete() { - return this.geometryArena.isEmpty(); + return this.geometryArena.isEmpty() && this.indexArena.isEmpty(); // TODO: correct? } } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java index b39da2f888..f16f8182b7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java @@ -10,10 +10,14 @@ import me.jellysquid.mods.sodium.client.gl.arena.staging.StagingBuffer; import me.jellysquid.mods.sodium.client.gl.device.CommandList; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; +import me.jellysquid.mods.sodium.client.gl.util.VertexRange; +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildOutput; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; -import me.jellysquid.mods.sodium.client.render.chunk.gfni.TranslucentData; +import me.jellysquid.mods.sodium.client.render.chunk.gfni.MixedDirectionData; +import me.jellysquid.mods.sodium.client.render.chunk.gfni.PresentTranslucentData; +import me.jellysquid.mods.sodium.client.render.chunk.gfni.StaticNormalRelativeData; import me.jellysquid.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses; import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; import org.jetbrains.annotations.NotNull; @@ -57,13 +61,15 @@ public void uploadMeshes(CommandList commandList, Collection r private void uploadMeshes(CommandList commandList, RenderRegion region, Collection results) { var uploads = new ArrayList(); + var indexUploads = new ArrayList(); for (ChunkBuildOutput result : results) { + int renderSectionIndex = result.render.getSectionIndex(); for (TerrainRenderPass pass : DefaultTerrainRenderPasses.ALL) { var storage = region.getStorage(pass); if (storage != null) { - storage.removeMeshes(result.render.getSectionIndex()); + storage.removeMeshes(renderSectionIndex); } BuiltSectionMeshParts mesh = result.getMesh(pass); @@ -73,30 +79,72 @@ private void uploadMeshes(CommandList commandList, RenderRegion region, Collecti new PendingUpload(mesh.getVertexData()))); } } + + var translucentStorage = region.getTranslucentStorage(); + if (translucentStorage != null) { + translucentStorage.removeMeshes(renderSectionIndex); + } + + var translucentData = result.translucentData; + if (translucentData != null && translucentData instanceof PresentTranslucentData presentTranslucentData) { + indexUploads.add(new PendingSectionIndexBufferUpload(result.render, presentTranslucentData, + new PendingUpload(presentTranslucentData.buffer))); + } } // If we have nothing to upload, abort! - if (uploads.isEmpty()) { + if (uploads.isEmpty() && indexUploads.isEmpty()) { return; } var resources = region.createResources(commandList); - var arena = resources.getGeometryArena(); - boolean bufferChanged = arena.upload(commandList, uploads.stream() - .map(upload -> upload.vertexUpload)); + if (!uploads.isEmpty()) { + var geometryArena = resources.getGeometryArena(); + boolean bufferChanged = geometryArena.upload(commandList, uploads.stream() + .map(upload -> upload.vertexUpload)); + + // If any of the buffers changed, the tessellation will need to be updated + // Once invalidated the tessellation will be re-created on the next attempted use + if (bufferChanged) { + region.refresh(commandList); + } + - // If any of the buffers changed, the tessellation will need to be updated - // Once invalidated the tessellation will be re-created on the next attempted use - if (bufferChanged) { - region.refresh(commandList); + // Collect the upload results + for (PendingSectionMeshUpload upload : uploads) { + var storage = region.createStorage(upload.pass); + storage.setMeshes(upload.section.getSectionIndex(), + upload.vertexUpload.getResult(), upload.meshData.getVertexRanges()); + } } - // Collect the upload results - for (PendingSectionMeshUpload upload : uploads) { - var storage = region.createStorage(upload.pass); - storage.setMeshes(upload.section.getSectionIndex(), - upload.vertexUpload.getResult(), upload.meshData.getVertexRanges()); + if (!indexUploads.isEmpty()) { + var indexArena = resources.getIndexArena(); + boolean bufferChanged = indexArena.upload(commandList, indexUploads.stream() + .map(upload -> upload.indexBufferUpload)); + + if (bufferChanged) { + region.refreshTranslucent(commandList); + } + + for (PendingSectionIndexBufferUpload upload : indexUploads) { + var storage = region.createTranslucentStorage(); + + // TODO: doesn't support DynamicTopoCyclicData yet because of SectionRenderDataStorage's internals + VertexRange[] vertexRanges = null; + var translucentData = upload.translucentData; + if (translucentData instanceof StaticNormalRelativeData data) { + vertexRanges = data.ranges; + } else if (translucentData instanceof MixedDirectionData data) { + vertexRanges = new VertexRange[ModelQuadFacing.COUNT]; + vertexRanges[ModelQuadFacing.UNASSIGNED.ordinal()] = data.range; + } + if (vertexRanges != null) { + storage.setMeshes(upload.section.getSectionIndex(), + upload.indexBufferUpload.getResult(), vertexRanges); + } + } } } @@ -149,10 +197,7 @@ private RenderRegion create(int x, int y, int z) { private record PendingSectionMeshUpload(RenderSection section, BuiltSectionMeshParts meshData, TerrainRenderPass pass, PendingUpload vertexUpload) { } - // TODO: Does this need to use native buffers or not? If so, then they should - // probably be used all throughout translucent data and not just here? Or should - // they only be used for uploading and not for off-thread sorting? - private record PendingSectionSortUpload(RenderSection section, TranslucentData data) { + private record PendingSectionIndexBufferUpload(RenderSection section, PresentTranslucentData translucentData, PendingUpload indexBufferUpload) { } From 712b44bddb6ddfcb5348c304408d281d3733c3bf Mon Sep 17 00:00:00 2001 From: douira Date: Tue, 12 Sep 2023 18:30:33 +0200 Subject: [PATCH 029/256] comments --- .../mods/sodium/client/render/chunk/gfni/GroupBuilder.java | 6 ++++-- .../client/render/chunk/region/RenderRegionManager.java | 1 - 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java index 7c12aafa20..1bdffc98c5 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java @@ -110,6 +110,7 @@ public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] verti extents[4] = Math.min(extents[4], y); extents[5] = Math.min(extents[5], z); + // TODO: can we also just use two vertices at opposite corners of the quad? xSum += x; ySum += y; zSum += z; @@ -117,6 +118,8 @@ public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] verti var center = new Vector3f(xSum * 0.25f, ySum * 0.25f, zSum * 0.25f); + // TODO: some of these things should probably only be computed on demand, and an + // allocation of a Quad object should be avoided AccumulationGroup accGroup; if (facing == ModelQuadFacing.UNASSIGNED) { int normalX = quadView.getGFNINormX(); @@ -334,8 +337,7 @@ private StaticNormalRelativeData constructStaticNormalRelativeData(BuiltSectionM IntBuffer bufferBuilder = buffer.getDirectBuffer().asIntBuffer(); for (int i = 0; i < ModelQuadFacing.COUNT; i++) { - VertexRange range = ranges[i]; - if (range != null) { + if (ranges[i] != null) { TranslucentData.writeVertexIndexes(bufferBuilder, GFNI.SORTERS[i].sort(centers[i])); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java index f16f8182b7..8e0410700e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java @@ -110,7 +110,6 @@ private void uploadMeshes(CommandList commandList, RenderRegion region, Collecti region.refresh(commandList); } - // Collect the upload results for (PendingSectionMeshUpload upload : uploads) { var storage = region.createStorage(upload.pass); From 609ff7915da08cfaf01d6d3d04917c4fb38648e1 Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 16 Sep 2023 03:05:49 +0200 Subject: [PATCH 030/256] temp things --- .../render/chunk/DefaultChunkRenderer.java | 23 +++--- .../tasks/ChunkBuilderMeshingTask.java | 1 + .../render/chunk/gfni/GroupBuilder.java | 80 ++++++++++--------- .../render/chunk/region/RenderRegion.java | 17 ++++ .../chunk/region/RenderRegionManager.java | 2 + 5 files changed, 77 insertions(+), 46 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java index 82d22717b7..ba98fc98cb 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java @@ -150,10 +150,10 @@ private static void addDrawCommands(MultiDrawBatch batch, long pMeshData, int ma for (int facing = 0; facing < ModelQuadFacing.COUNT; facing++) { MemoryUtil.memPutInt(pBaseVertex + (size << 2), SectionRenderDataUnsafe.getVertexOffset(pMeshData, facing)); MemoryUtil.memPutInt(pElementCount + (size << 2), SectionRenderDataUnsafe.getElementCount(pMeshData, facing)); - if (pIndexData != -1) { - // TODO: I don't think this is correct - MemoryUtil.memPutAddress(pElementPointer + (size << 2), pIndexData); - } + // if (pIndexData != -1) { + // // TODO: I don't think this is correct + // MemoryUtil.memPutAddress(pElementPointer + size * 8L, 0); + // } size += (mask >> facing) & 1; } @@ -226,15 +226,20 @@ private static float getCameraTranslation(int chunkBlockPos, int cameraBlockPos, private GlTessellation prepareTessellation(CommandList commandList, RenderRegion region, boolean translucent) { var resources = region.getResources(); - var tessellation = resources.getTessellation(); - if (tessellation == null) { - if (translucent) { + GlTessellation tessellation; + if (translucent) { + tessellation = resources.getIndexedTessellation(); + if (tessellation == null) { tessellation = this.createIndexedRegionTessellation(commandList, resources); - } else { + resources.updateIndexedTessellation(commandList, tessellation); + } + } else { + tessellation = resources.getTessellation(); + if (tessellation == null) { tessellation = this.createRegionTessellation(commandList, resources); + resources.updateTessellation(commandList, tessellation); } - resources.updateTessellation(commandList, tessellation); } return tessellation; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java index 9b770d91f4..de487a3db4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java @@ -155,6 +155,7 @@ public ChunkBuildOutput execute(ChunkBuildContext buildContext, CancellationToke TranslucentData translucentData = groupBuilder.getTranslucentData( meshes.get(DefaultTerrainRenderPasses.TRANSLUCENT), cameraPos); + System.out.println("translucentData: " + translucentData.getClass().getSimpleName()); renderData.setOcclusionData(occluder.build()); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java index 1bdffc98c5..7f4f6d91ce 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java @@ -216,6 +216,12 @@ public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] verti * @return the required sort type to ensure this section always looks correct */ private SortType sortTypeHeuristic() { + if (this.quads.isEmpty()) { + return SortType.NONE; + } + if (true) { + return SortType.DYNAMIC_ALL; + } // special case A if (this.facePlaneCount <= 1) { return SortType.NONE; @@ -389,49 +395,49 @@ public TranslucentData getTranslucentData(BuiltSectionMeshParts translucentMesh, return new NoneData(this.sectionPos); } - if (this.sortType == SortType.STATIC_NORMAL_RELATIVE) { - return constructStaticNormalRelativeData(translucentMesh); - } + // if (this.sortType == SortType.STATIC_NORMAL_RELATIVE) { + // return constructStaticNormalRelativeData(translucentMesh); + // } // from this point on we know the estimated sort type requires direction mixing // (no backface culling) and all vertices are in the UNASSIGNED direction. NativeBuffer buffer = null; - if (this.sortType == SortType.STATIC_TOPO_ACYCLIC - || this.sortType == SortType.DYNAMIC_TOPO_CYCLIC - || this.sortType == SortType.DYNAMIC_ALL) { - // TODO: implement topo sort with unaligned quads - if (this.unalignedQuadCount > 0) { - unalignedDynamicHits++; - this.sortType = SortType.DYNAMIC_ALL; - } else { - // it can only perform topo sort on acyclic graphs since it has no cycle - // breaking, but it will detect cycles and bail to DYNAMIC_ALL - // DYNAMIC_TOPO_CYCLIC if there is a cycle - var indexData = constructStaticTopoAcyclicData(translucentMesh); - buffer = indexData.buffer; - IntBuffer indexBuffer = buffer.getDirectBuffer().asIntBuffer(); - - if (topoSortAlignedAcyclic(indexBuffer)) { - topoSortHits++; - - return indexData; - } else { - // TODO: cyclic topo sort with cycle breaking - cyclicGraphHits++; - - this.sortType = SortType.DYNAMIC_ALL; - } - } - - System.out.println("topo sort hits: " + topoSortHits + ", cyclic graph hits: " + cyclicGraphHits - + ", unaligned dynamic hits: " + unalignedDynamicHits); - } - - if (this.sortType == SortType.DYNAMIC_ALL) { + // if (this.sortType == SortType.STATIC_TOPO_ACYCLIC + // || this.sortType == SortType.DYNAMIC_TOPO_CYCLIC + // || this.sortType == SortType.DYNAMIC_ALL) { + // // TODO: implement topo sort with unaligned quads + // if (this.unalignedQuadCount > 0) { + // unalignedDynamicHits++; + // this.sortType = SortType.DYNAMIC_ALL; + // } else { + // // it can only perform topo sort on acyclic graphs since it has no cycle + // // breaking, but it will detect cycles and bail to DYNAMIC_ALL + // // DYNAMIC_TOPO_CYCLIC if there is a cycle + // var indexData = constructStaticTopoAcyclicData(translucentMesh); + // buffer = indexData.buffer; + // IntBuffer indexBuffer = buffer.getDirectBuffer().asIntBuffer(); + + // if (topoSortAlignedAcyclic(indexBuffer)) { + // topoSortHits++; + + // return indexData; + // } else { + // // TODO: cyclic topo sort with cycle breaking + // cyclicGraphHits++; + + // this.sortType = SortType.DYNAMIC_ALL; + // } + // } + + // System.out.println("topo sort hits: " + topoSortHits + ", cyclic graph hits: " + cyclicGraphHits + // + ", unaligned dynamic hits: " + unalignedDynamicHits); + // } + + // if (this.sortType == SortType.DYNAMIC_ALL) { return constructDynamicData(translucentMesh, buffer, cameraPos); - } + // } - throw new IllegalStateException("Unknown sort type: " + this.sortType); + // throw new IllegalStateException("Unknown sort type: " + this.sortType); } private static boolean orthogonalQuadVisible(Quad quad, Quad otherQuad) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java index 51b2753ee2..285c870fd4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java @@ -221,6 +221,7 @@ public static class DeviceResources { private final GlBufferArena geometryArena; private final GlBufferArena indexArena; private GlTessellation tessellation; + private GlTessellation indexedTessellation; public DeviceResources(CommandList commandList, StagingBuffer stagingBuffer) { int stride = ChunkMeshFormats.COMPACT.getVertexFormat().getStride(); @@ -238,15 +239,31 @@ public void updateTessellation(CommandList commandList, GlTessellation tessellat this.tessellation = tessellation; } + public void updateIndexedTessellation(CommandList commandList, GlTessellation tessellation) { + if (this.indexedTessellation != null) { + this.indexedTessellation.delete(commandList); + } + + this.indexedTessellation = tessellation; + } + public GlTessellation getTessellation() { return this.tessellation; } + public GlTessellation getIndexedTessellation() { + return this.indexedTessellation; + } + public void deleteTessellations(CommandList commandList) { if (this.tessellation != null) { this.tessellation.delete(commandList); this.tessellation = null; } + if (this.indexedTessellation != null) { + this.indexedTessellation.delete(commandList); + this.indexedTessellation = null; + } } public GlBuffer getVertexBuffer() { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java index 8e0410700e..6829098598 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java @@ -138,6 +138,8 @@ private void uploadMeshes(CommandList commandList, RenderRegion region, Collecti } else if (translucentData instanceof MixedDirectionData data) { vertexRanges = new VertexRange[ModelQuadFacing.COUNT]; vertexRanges[ModelQuadFacing.UNASSIGNED.ordinal()] = data.range; + } else { + throw new UnsupportedOperationException("Unsupported translucent data type: " + translucentData.getClass()); } if (vertexRanges != null) { storage.setMeshes(upload.section.getSectionIndex(), From a422a08f69df434ef1891947b2ac7393d3ac1b87 Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 16 Sep 2023 03:43:32 +0200 Subject: [PATCH 031/256] fix translucent data to use correct factor --- .../mods/sodium/client/render/chunk/gfni/TranslucentData.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java index 0bd450c6aa..81329489b4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java @@ -30,7 +30,7 @@ public static int vertexCountToIndexBytes(int vertexCount) { } public static void putQuadVertexIndexes(IntBuffer intBuffer, int quadIndex) { - int vertexOffset = quadIndex * INDICES_PER_QUAD; + int vertexOffset = quadIndex * VERTICES_PER_QUAD; intBuffer.put(vertexOffset + 0); intBuffer.put(vertexOffset + 1); From eaf28dddc5c69abb9689ebec97ef44237c6d20f5 Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 16 Sep 2023 04:05:38 +0200 Subject: [PATCH 032/256] cleanup delete --- .../sodium/client/render/chunk/compile/ChunkBuildOutput.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java index e5ad82a27b..f4abc5d082 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java @@ -29,10 +29,11 @@ public BuiltSectionMeshParts getMesh(TerrainRenderPass pass) { return this.meshes.get(pass); } + @Override public void delete() { + super.delete(); for (BuiltSectionMeshParts data : this.meshes.values()) { - data.getVertexData() - .free(); + data.getVertexData().free(); } } From cba72f42d90330c4755f3168a6bdcafd103afd3f Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 16 Sep 2023 04:05:56 +0200 Subject: [PATCH 033/256] fix indexed rendering --- .../sodium/client/render/chunk/DefaultChunkRenderer.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java index ba98fc98cb..584fb1ae29 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java @@ -150,10 +150,11 @@ private static void addDrawCommands(MultiDrawBatch batch, long pMeshData, int ma for (int facing = 0; facing < ModelQuadFacing.COUNT; facing++) { MemoryUtil.memPutInt(pBaseVertex + (size << 2), SectionRenderDataUnsafe.getVertexOffset(pMeshData, facing)); MemoryUtil.memPutInt(pElementCount + (size << 2), SectionRenderDataUnsafe.getElementCount(pMeshData, facing)); - // if (pIndexData != -1) { - // // TODO: I don't think this is correct - // MemoryUtil.memPutAddress(pElementPointer + size * 8L, 0); - // } + if (pIndexData != -1) { + MemoryUtil.memPutAddress(pElementPointer + (size << 3), SectionRenderDataUnsafe.getVertexOffset(pIndexData, facing) * 4); + } else { + MemoryUtil.memPutAddress(pElementPointer + (size << 3), 0); + } size += (mask >> facing) & 1; } From 795087ec55147e24cf566d57c72630fb39d391b3 Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 16 Sep 2023 04:13:16 +0200 Subject: [PATCH 034/256] use manhattan distance for by distance vertex sorting --- .../mods/sodium/client/util/sorting/VertexSorters.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/VertexSorters.java b/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/VertexSorters.java index 36c03c029f..b4ba3e65d4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/VertexSorters.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/VertexSorters.java @@ -39,7 +39,10 @@ private SortByDistance(Vector3f origin) { @Override protected float getKey(Vector3f position) { - return this.origin.distanceSquared(position); + float distance = Math.abs(position.x - this.origin.x); + distance += Math.abs(position.y - this.origin.y); + distance += Math.abs(position.z - this.origin.z); + return distance; } } From 2b6b140fef0c3dab9502a7c3055a6b8f72c7a275 Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 16 Sep 2023 04:14:52 +0200 Subject: [PATCH 035/256] reeneable debugging disabled things --- .../render/chunk/gfni/GroupBuilder.java | 80 +++++++++---------- .../chunk/gfni/PresentTranslucentData.java | 4 + 2 files changed, 41 insertions(+), 43 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java index 7f4f6d91ce..1bdffc98c5 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java @@ -216,12 +216,6 @@ public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] verti * @return the required sort type to ensure this section always looks correct */ private SortType sortTypeHeuristic() { - if (this.quads.isEmpty()) { - return SortType.NONE; - } - if (true) { - return SortType.DYNAMIC_ALL; - } // special case A if (this.facePlaneCount <= 1) { return SortType.NONE; @@ -395,49 +389,49 @@ public TranslucentData getTranslucentData(BuiltSectionMeshParts translucentMesh, return new NoneData(this.sectionPos); } - // if (this.sortType == SortType.STATIC_NORMAL_RELATIVE) { - // return constructStaticNormalRelativeData(translucentMesh); - // } + if (this.sortType == SortType.STATIC_NORMAL_RELATIVE) { + return constructStaticNormalRelativeData(translucentMesh); + } // from this point on we know the estimated sort type requires direction mixing // (no backface culling) and all vertices are in the UNASSIGNED direction. NativeBuffer buffer = null; - // if (this.sortType == SortType.STATIC_TOPO_ACYCLIC - // || this.sortType == SortType.DYNAMIC_TOPO_CYCLIC - // || this.sortType == SortType.DYNAMIC_ALL) { - // // TODO: implement topo sort with unaligned quads - // if (this.unalignedQuadCount > 0) { - // unalignedDynamicHits++; - // this.sortType = SortType.DYNAMIC_ALL; - // } else { - // // it can only perform topo sort on acyclic graphs since it has no cycle - // // breaking, but it will detect cycles and bail to DYNAMIC_ALL - // // DYNAMIC_TOPO_CYCLIC if there is a cycle - // var indexData = constructStaticTopoAcyclicData(translucentMesh); - // buffer = indexData.buffer; - // IntBuffer indexBuffer = buffer.getDirectBuffer().asIntBuffer(); - - // if (topoSortAlignedAcyclic(indexBuffer)) { - // topoSortHits++; - - // return indexData; - // } else { - // // TODO: cyclic topo sort with cycle breaking - // cyclicGraphHits++; - - // this.sortType = SortType.DYNAMIC_ALL; - // } - // } - - // System.out.println("topo sort hits: " + topoSortHits + ", cyclic graph hits: " + cyclicGraphHits - // + ", unaligned dynamic hits: " + unalignedDynamicHits); - // } - - // if (this.sortType == SortType.DYNAMIC_ALL) { + if (this.sortType == SortType.STATIC_TOPO_ACYCLIC + || this.sortType == SortType.DYNAMIC_TOPO_CYCLIC + || this.sortType == SortType.DYNAMIC_ALL) { + // TODO: implement topo sort with unaligned quads + if (this.unalignedQuadCount > 0) { + unalignedDynamicHits++; + this.sortType = SortType.DYNAMIC_ALL; + } else { + // it can only perform topo sort on acyclic graphs since it has no cycle + // breaking, but it will detect cycles and bail to DYNAMIC_ALL + // DYNAMIC_TOPO_CYCLIC if there is a cycle + var indexData = constructStaticTopoAcyclicData(translucentMesh); + buffer = indexData.buffer; + IntBuffer indexBuffer = buffer.getDirectBuffer().asIntBuffer(); + + if (topoSortAlignedAcyclic(indexBuffer)) { + topoSortHits++; + + return indexData; + } else { + // TODO: cyclic topo sort with cycle breaking + cyclicGraphHits++; + + this.sortType = SortType.DYNAMIC_ALL; + } + } + + System.out.println("topo sort hits: " + topoSortHits + ", cyclic graph hits: " + cyclicGraphHits + + ", unaligned dynamic hits: " + unalignedDynamicHits); + } + + if (this.sortType == SortType.DYNAMIC_ALL) { return constructDynamicData(translucentMesh, buffer, cameraPos); - // } + } - // throw new IllegalStateException("Unknown sort type: " + this.sortType); + throw new IllegalStateException("Unknown sort type: " + this.sortType); } private static boolean orthogonalQuadVisible(Quad quad, Quad otherQuad) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/PresentTranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/PresentTranslucentData.java index cdc6ac71ec..069a2684f3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/PresentTranslucentData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/PresentTranslucentData.java @@ -3,6 +3,10 @@ import me.jellysquid.mods.sodium.client.util.NativeBuffer; import net.minecraft.util.math.ChunkSectionPos; +/** + * TODO: take care of deleting the native buffers when the translucent data + * stored here is replaced. + */ public abstract class PresentTranslucentData extends TranslucentData { public final NativeBuffer buffer; From e95bbd364ffa00719f38dd56f78ce1b395288c2d Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 16 Sep 2023 05:27:32 +0200 Subject: [PATCH 036/256] fix sort order by rearranging centers, use vector3fc for camera pos and offset chunk pos --- .../client/render/SodiumWorldRenderer.java | 2 +- .../render/chunk/RenderSectionManager.java | 19 +++++++------- .../tasks/ChunkBuilderMeshingTask.java | 4 +-- .../tasks/ChunkBuilderSortingTask.java | 4 +-- .../chunk/compile/tasks/ChunkBuilderTask.java | 10 +++++--- .../client/render/chunk/gfni/DynamicData.java | 8 +++--- .../render/chunk/gfni/GroupBuilder.java | 25 ++++++++++++++----- .../render/chunk/gfni/TranslucentData.java | 4 +-- 8 files changed, 48 insertions(+), 28 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index a930f3f612..39f95a0d51 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -192,7 +192,7 @@ public void setupTerrain(Camera camera, if (this.renderSectionManager.needsUpdate()) { profiler.swap("chunk_render_lists"); - this.renderSectionManager.update(camera, viewport, frame, spectator); + this.renderSectionManager.update(pos.toVector3f(), camera, viewport, frame, spectator); } if (cameraLocationChanged) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index a5dfd74c60..9087a9ffc8 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -49,7 +49,7 @@ import org.apache.commons.lang3.ArrayUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.joml.Vector3f; +import org.joml.Vector3fc; import java.util.*; import java.util.concurrent.ConcurrentLinkedDeque; @@ -75,8 +75,6 @@ public class RenderSectionManager { private final int renderDistance; - private Vector3f cameraPos = new Vector3f(); - @NotNull private SortedRenderLists renderLists; @@ -87,7 +85,8 @@ public class RenderSectionManager { private boolean needsUpdate; - private @Nullable BlockPos lastCameraPosition; + private @Nullable BlockPos cameraBlockPos; + private @Nullable Vector3fc cameraPosition; public RenderSectionManager(ClientWorld world, int renderDistance, CommandList commandList) { this.chunkRenderer = new DefaultChunkRenderer(RenderDevice.INSTANCE, ChunkMeshFormats.COMPACT); @@ -113,8 +112,9 @@ public RenderSectionManager(ClientWorld world, int renderDistance, CommandList c } } - public void update(Camera camera, Viewport viewport, int frame, boolean spectator) { - this.lastCameraPosition = camera.getBlockPos(); + public void update(Vector3fc cameraPosition, Camera camera, Viewport viewport, int frame, boolean spectator) { + this.cameraBlockPos = camera.getBlockPos(); + this.cameraPosition = cameraPosition; this.createTerrainRenderList(camera, viewport, frame, spectator); @@ -411,15 +411,16 @@ private void submitRebuildTasks(ChunkJobCollector collector, ChunkUpdateType typ return null; } - return new ChunkBuilderMeshingTask(render, frame, this.cameraPos, context); + return new ChunkBuilderMeshingTask(render, frame, this.cameraPosition, context); } public ChunkBuilderSortingTask createSortTask(RenderSection render, int frame) { if (render.getTranslucentData() == null) { + // TODO: this should never happen since sections are triggered by GFNI only if they have translucent data. However, the data may have been deleted in the mean time? or would it be removed from GFNI when that happens? return null; } - return new ChunkBuilderSortingTask(render, frame, this.cameraPos); + return new ChunkBuilderSortingTask(render, frame, this.cameraPosition); } public void processGFNIMovement( @@ -510,7 +511,7 @@ public void scheduleRebuild(int x, int y, int z, boolean important) { private static final float NEARBY_REBUILD_DISTANCE = MathHelper.square(16.0f); private boolean shouldPrioritizeRebuild(RenderSection section) { - return this.lastCameraPosition != null && section.getSquaredDistance(this.lastCameraPosition) < NEARBY_REBUILD_DISTANCE; + return this.cameraPosition != null && section.getSquaredDistance(this.cameraBlockPos) < NEARBY_REBUILD_DISTANCE; } private static boolean allowImportantRebuilds() { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java index de487a3db4..ee653ef84c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java @@ -32,7 +32,7 @@ import java.util.Map; -import org.joml.Vector3f; +import org.joml.Vector3fc; /** * Rebuilds all the meshes of a chunk for each given render pass with non-occluded blocks. The result is then uploaded @@ -44,7 +44,7 @@ public class ChunkBuilderMeshingTask extends ChunkBuilderTask { private final ChunkRenderContext renderContext; - public ChunkBuilderMeshingTask(RenderSection render, int buildTime, Vector3f cameraPos, ChunkRenderContext renderContext) { + public ChunkBuilderMeshingTask(RenderSection render, int buildTime, Vector3fc cameraPos, ChunkRenderContext renderContext) { super(render, buildTime, cameraPos); this.renderContext = renderContext; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java index 019ef2e47a..aae55cf347 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.render.chunk.compile.tasks; -import org.joml.Vector3f; +import org.joml.Vector3fc; import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildContext; @@ -8,7 +8,7 @@ import me.jellysquid.mods.sodium.client.util.task.CancellationToken; public class ChunkBuilderSortingTask extends ChunkBuilderTask { - public ChunkBuilderSortingTask(RenderSection render, int frame, Vector3f cameraPos) { + public ChunkBuilderSortingTask(RenderSection render, int frame, Vector3fc cameraPos) { super(render, frame, cameraPos); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderTask.java index 8beb18ff7d..56cdc099b2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderTask.java @@ -1,6 +1,7 @@ package me.jellysquid.mods.sodium.client.render.chunk.compile.tasks; import org.joml.Vector3f; +import org.joml.Vector3fc; import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; import me.jellysquid.mods.sodium.client.render.chunk.compile.BuilderTaskOutput; @@ -20,12 +21,15 @@ public abstract class ChunkBuilderTask { protected final RenderSection render; protected final int buildTime; - protected final Vector3f cameraPos; + protected final Vector3fc cameraPos; - public ChunkBuilderTask(RenderSection render, int time, Vector3f cameraPos) { + public ChunkBuilderTask(RenderSection render, int time, Vector3fc cameraPos) { this.render = render; this.buildTime = time; - this.cameraPos = cameraPos; + this.cameraPos = new Vector3f( + cameraPos.x() - (float) render.getOriginX(), + cameraPos.y() - (float) render.getOriginY(), + cameraPos.z() - (float) render.getOriginZ()); } /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java index 4c81cb29f1..928448fd84 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java @@ -1,6 +1,7 @@ package me.jellysquid.mods.sodium.client.render.chunk.gfni; import org.joml.Vector3f; +import org.joml.Vector3fc; import it.unimi.dsi.fastutil.ints.Int2ReferenceLinkedOpenHashMap; import me.jellysquid.mods.sodium.client.gl.util.VertexRange; @@ -14,7 +15,7 @@ public class DynamicData extends MixedDirectionData { private Int2ReferenceLinkedOpenHashMap unalignedDistances; public DynamicData(ChunkSectionPos sectionPos, - NativeBuffer buffer, VertexRange range, Vector3f[] centers, + NativeBuffer buffer, VertexRange range, Vector3f[] centers, AccumulationGroup[] axisAlignedDistances, Int2ReferenceLinkedOpenHashMap unalignedDistances) { super(sectionPos, buffer, range); @@ -57,8 +58,9 @@ public void clearTriggerData() { } @Override - public void sort(Vector3f cameraPos) { + public void sort(Vector3fc cameraPos) { var intBuffer = this.buffer.getDirectBuffer().asIntBuffer(); - TranslucentData.writeVertexIndexes(intBuffer, VertexSorters.sortByDistance(cameraPos).sort(this.centers)); + TranslucentData.writeVertexIndexes(intBuffer, + VertexSorters.sortByDistance(new Vector3f(cameraPos)).sort(this.centers)); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java index 1bdffc98c5..553849a6f7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java @@ -364,18 +364,31 @@ private StaticTopoAcyclicData constructStaticTopoAcyclicData(BuiltSectionMeshPar } private DynamicData constructDynamicData(BuiltSectionMeshParts translucentMesh, NativeBuffer reuseBuffer, - Vector3f cameraPos) { + Vector3fc cameraPos) { VertexRange range = GroupBuilder.getUnassignedVertexRange(translucentMesh); - int vertexCount = range.vertexCount(); + int[] centerCounters = new int[ModelQuadFacing.COUNT]; + + for (Quad quad : this.quads) { + centerCounters[quad.facing.ordinal()]++; + } + + // do a prefix sum to determine the offsets of where to write the centers + int quadCount = 0; + for (int i = 0; i < ModelQuadFacing.COUNT; i++) { + var newCount = centerCounters[i] + quadCount; + centerCounters[i] = quadCount; + quadCount = newCount; + } if (reuseBuffer == null) { - reuseBuffer = new NativeBuffer(TranslucentData.vertexCountToIndexBytes(vertexCount)); + reuseBuffer = new NativeBuffer(TranslucentData.vertexCountToIndexBytes(quadCount * TranslucentData.VERTICES_PER_QUAD)); } - Vector3f[] centers = new Vector3f[vertexCount / TranslucentData.VERTICES_PER_QUAD]; + Vector3f[] centers = new Vector3f[quadCount]; for (int i = 0; i < this.quads.size(); i++) { - centers[i] = this.quads.get(i).center; + Quad quad = this.quads.get(i); + centers[centerCounters[quad.facing.ordinal()]++] = quad.center; } var dynamicData = new DynamicData(this.sectionPos, @@ -384,7 +397,7 @@ private DynamicData constructDynamicData(BuiltSectionMeshParts translucentMesh, return dynamicData; } - public TranslucentData getTranslucentData(BuiltSectionMeshParts translucentMesh, Vector3f cameraPos) { + public TranslucentData getTranslucentData(BuiltSectionMeshParts translucentMesh, Vector3fc cameraPos) { if (this.sortType == SortType.NONE || translucentMesh == null) { return new NoneData(this.sectionPos); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java index 81329489b4..24353f04c6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java @@ -2,7 +2,7 @@ import java.nio.IntBuffer; -import org.joml.Vector3f; +import org.joml.Vector3fc; import net.minecraft.util.math.ChunkSectionPos; @@ -19,7 +19,7 @@ public TranslucentData(ChunkSectionPos sectionPos) { public abstract SortType getSortType(); - public void sort(Vector3f cameraPos) { + public void sort(Vector3fc cameraPos) { // there should be no sort calls to data that doesn't need sorting throw new UnsupportedOperationException(); } From 92198405f792d5cfd0b0d22dfd57c5a249871507 Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 16 Sep 2023 05:33:48 +0200 Subject: [PATCH 037/256] refactor tessellation method into two --- .../render/chunk/DefaultChunkRenderer.java | 42 +++++++++++-------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java index 584fb1ae29..aef6a4ba3b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java @@ -13,6 +13,7 @@ import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.render.chunk.data.SectionRenderDataStorage; import me.jellysquid.mods.sodium.client.render.chunk.data.SectionRenderDataUnsafe; +import me.jellysquid.mods.sodium.client.render.chunk.gfni.TranslucentData; import me.jellysquid.mods.sodium.client.render.chunk.lists.ChunkRenderListIterable; import me.jellysquid.mods.sodium.client.render.chunk.lists.ChunkRenderList; import me.jellysquid.mods.sodium.client.render.chunk.region.RenderRegion; @@ -77,12 +78,14 @@ public void render(ChunkRenderMatrices matrices, continue; } - if (!isTranslucent) { + GlTessellation tessellation; + if (isTranslucent) { + tessellation = this.prepareIndexedTessellation(commandList, region); + } else { this.sharedIndexBuffer.ensureCapacity(commandList, this.batch.getIndexBufferSize()); + tessellation = this.prepareTessellation(commandList, region); } - var tessellation = this.prepareTessellation(commandList, region, isTranslucent); - setModelMatrixUniforms(shader, region, camera); executeDrawBatch(commandList, tessellation, this.batch); } @@ -151,7 +154,7 @@ private static void addDrawCommands(MultiDrawBatch batch, long pMeshData, int ma MemoryUtil.memPutInt(pBaseVertex + (size << 2), SectionRenderDataUnsafe.getVertexOffset(pMeshData, facing)); MemoryUtil.memPutInt(pElementCount + (size << 2), SectionRenderDataUnsafe.getElementCount(pMeshData, facing)); if (pIndexData != -1) { - MemoryUtil.memPutAddress(pElementPointer + (size << 3), SectionRenderDataUnsafe.getVertexOffset(pIndexData, facing) * 4); + MemoryUtil.memPutAddress(pElementPointer + (size << 3), SectionRenderDataUnsafe.getVertexOffset(pIndexData, facing) * TranslucentData.VERTICES_PER_QUAD); } else { MemoryUtil.memPutAddress(pElementPointer + (size << 3), 0); } @@ -225,22 +228,25 @@ private static float getCameraTranslation(int chunkBlockPos, int cameraBlockPos, return (chunkBlockPos - cameraBlockPos) - cameraPos; } - private GlTessellation prepareTessellation(CommandList commandList, RenderRegion region, boolean translucent) { + private GlTessellation prepareTessellation(CommandList commandList, RenderRegion region) { var resources = region.getResources(); - GlTessellation tessellation; - if (translucent) { - tessellation = resources.getIndexedTessellation(); - if (tessellation == null) { - tessellation = this.createIndexedRegionTessellation(commandList, resources); - resources.updateIndexedTessellation(commandList, tessellation); - } - } else { - tessellation = resources.getTessellation(); - if (tessellation == null) { - tessellation = this.createRegionTessellation(commandList, resources); - resources.updateTessellation(commandList, tessellation); - } + GlTessellation tessellation = resources.getTessellation(); + if (tessellation == null) { + tessellation = this.createRegionTessellation(commandList, resources); + resources.updateTessellation(commandList, tessellation); + } + + return tessellation; + } + + private GlTessellation prepareIndexedTessellation(CommandList commandList, RenderRegion region) { + var resources = region.getResources(); + + GlTessellation tessellation = resources.getIndexedTessellation(); + if (tessellation == null) { + tessellation = this.createIndexedRegionTessellation(commandList, resources); + resources.updateIndexedTessellation(commandList, tessellation); } return tessellation; From 12fb105a92b0c956eb3e1ab91b26afbda838acbe Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 16 Sep 2023 05:35:57 +0200 Subject: [PATCH 038/256] remove spammy print --- .../render/chunk/compile/tasks/ChunkBuilderMeshingTask.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java index ee653ef84c..2c3bfe2a06 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java @@ -155,7 +155,6 @@ public ChunkBuildOutput execute(ChunkBuildContext buildContext, CancellationToke TranslucentData translucentData = groupBuilder.getTranslucentData( meshes.get(DefaultTerrainRenderPasses.TRANSLUCENT), cameraPos); - System.out.println("translucentData: " + translucentData.getClass().getSimpleName()); renderData.setOcclusionData(occluder.build()); From 42777d8a94212a3494029dca84d91317c52fcd1c Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 16 Sep 2023 14:58:23 +0200 Subject: [PATCH 039/256] add sort tasks --- .../client/render/chunk/RenderSection.java | 26 +++--- .../render/chunk/RenderSectionManager.java | 81 +++++++++---------- .../chunk/compile/BuilderTaskOutput.java | 6 +- .../chunk/compile/ChunkBuildOutput.java | 7 -- .../render/chunk/compile/ChunkSortOutput.java | 5 -- .../tasks/ChunkBuilderMeshingTask.java | 2 +- .../tasks/ChunkBuilderSortingTask.java | 2 +- .../chunk/compile/tasks/ChunkBuilderTask.java | 4 +- .../chunk/lists/VisibleChunkCollector.java | 2 +- .../chunk/region/RenderRegionManager.java | 51 +++++++----- 10 files changed, 88 insertions(+), 98 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java index 09f74799ea..4bd86ee6cc 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java @@ -54,12 +54,12 @@ public class RenderSection { // Pending Update State @Nullable - private CancellationToken buildCancellationToken = null; + private CancellationToken taskCancellationToken = null; @Nullable private ChunkUpdateType pendingUpdateType; - private int lastBuiltFrame = -1; + private int lastTaskFrame = -1; private int lastSubmittedFrame = -1; // Lifetime state @@ -127,9 +127,9 @@ public void setTranslucentData(TranslucentData translucentData) { * be used. */ public void delete() { - if (this.buildCancellationToken != null) { - this.buildCancellationToken.setCancelled(); - this.buildCancellationToken = null; + if (this.taskCancellationToken != null) { + this.taskCancellationToken.setCancelled(); + this.taskCancellationToken = null; } this.clearRenderState(); @@ -322,12 +322,12 @@ public long getVisibilityData() { return this.globalBlockEntities; } - public @Nullable CancellationToken getBuildCancellationToken() { - return this.buildCancellationToken; + public @Nullable CancellationToken getTaskCancellationToken() { + return this.taskCancellationToken; } - public void setBuildCancellationToken(@Nullable CancellationToken token) { - this.buildCancellationToken = token; + public void setTaskCancellationToken(@Nullable CancellationToken token) { + this.taskCancellationToken = token; } public @Nullable ChunkUpdateType getPendingUpdate() { @@ -338,12 +338,12 @@ public void setPendingUpdate(@Nullable ChunkUpdateType type) { this.pendingUpdateType = type; } - public int getLastBuiltFrame() { - return this.lastBuiltFrame; + public int getLastTaskFrame() { + return this.lastTaskFrame; } - public void setLastBuiltFrame(int lastBuiltFrame) { - this.lastBuiltFrame = lastBuiltFrame; + public void setLastTaskFrame(int lastSortFrame) { + this.lastTaskFrame = lastSortFrame; } public int getLastSubmittedFrame() { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index 9087a9ffc8..ab73757b5c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -13,6 +13,7 @@ import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; import me.jellysquid.mods.sodium.client.render.chunk.compile.BuilderTaskOutput; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildOutput; +import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkSortOutput; import me.jellysquid.mods.sodium.client.render.chunk.compile.executor.ChunkBuilder; import me.jellysquid.mods.sodium.client.render.chunk.compile.executor.ChunkJobResult; import me.jellysquid.mods.sodium.client.render.chunk.compile.executor.ChunkJobCollector; @@ -79,7 +80,7 @@ public class RenderSectionManager { private SortedRenderLists renderLists; @NotNull - private Map> rebuildLists; + private Map> taskLists; private int lastUpdatedFrame; @@ -105,10 +106,10 @@ public RenderSectionManager(ClientWorld world, int renderDistance, CommandList c this.renderLists = SortedRenderLists.empty(); this.occlusionCuller = new OcclusionCuller(Long2ReferenceMaps.unmodifiable(this.sectionByPosition), this.world); - this.rebuildLists = new EnumMap<>(ChunkUpdateType.class); + this.taskLists = new EnumMap<>(ChunkUpdateType.class); for (var type : ChunkUpdateType.values()) { - this.rebuildLists.put(type, new ArrayDeque<>()); + this.taskLists.put(type, new ArrayDeque<>()); } } @@ -133,7 +134,7 @@ private void createTerrainRenderList(Camera camera, Viewport viewport, int frame this.occlusionCuller.findVisible(visitor, viewport, searchDistance, useOcclusionCulling, frame); this.renderLists = visitor.createRenderLists(); - this.rebuildLists = visitor.getRebuildLists(); + this.taskLists = visitor.getRebuildLists(); } private float getSearchDistance() { @@ -165,7 +166,7 @@ private boolean shouldUseOcclusionCulling(Camera camera, boolean spectator) { private void resetRenderLists() { this.renderLists = SortedRenderLists.empty(); - for (var list : this.rebuildLists.values()) { + for (var list : this.taskLists.values()) { list.clear(); } } @@ -281,12 +282,11 @@ public void updateChunks(boolean updateImmediately) { var blockingRebuilds = new ChunkJobCollector(Integer.MAX_VALUE, this.buildResults::add); var deferredRebuilds = new ChunkJobCollector(this.builder.getSchedulingBudget(), this.buildResults::add); - this.submitRebuildTasks(blockingRebuilds, ChunkUpdateType.IMPORTANT_REBUILD); - this.submitRebuildTasks(updateImmediately ? blockingRebuilds : deferredRebuilds, ChunkUpdateType.REBUILD); - this.submitRebuildTasks(updateImmediately ? blockingRebuilds : deferredRebuilds, ChunkUpdateType.INITIAL_BUILD); - // TODO: re-enable once sort tasks are figured out - // this.submitRebuildTasks(updateImmediately ? blockingRebuilds : deferredRebuilds, ChunkUpdateType.TRANSLUCENT_SORT); - + this.submitSectionTasks(blockingRebuilds, ChunkUpdateType.IMPORTANT_REBUILD); + this.submitSectionTasks(updateImmediately ? blockingRebuilds : deferredRebuilds, ChunkUpdateType.REBUILD); + this.submitSectionTasks(updateImmediately ? blockingRebuilds : deferredRebuilds, ChunkUpdateType.INITIAL_BUILD); + this.submitSectionTasks(updateImmediately ? blockingRebuilds : deferredRebuilds, ChunkUpdateType.TRANSLUCENT_SORT); + blockingRebuilds.awaitCompletion(this.builder); } @@ -309,20 +309,24 @@ public void uploadChunks() { private void processChunkBuildResults(ArrayList results) { var filtered = filterChunkBuildResults(results); - this.regions.uploadMeshes(RenderDevice.INSTANCE.createCommandList(), filtered); + this.regions.uploadResults(RenderDevice.INSTANCE.createCommandList(), filtered); for (var result : filtered) { - this.updateSectionInfo(result.render, result.info); - result.render.setTranslucentData(result.translucentData); - this.gfni.integrateTranslucentData(result.translucentData); + if (result instanceof ChunkBuildOutput chunkBuildOutput) { + this.updateSectionInfo(result.render, chunkBuildOutput.info); + } + if (result instanceof ChunkSortOutput chunkSortOutput) { + result.render.setTranslucentData(chunkSortOutput.translucentData); + this.gfni.integrateTranslucentData(chunkSortOutput.translucentData); + } - var job = result.render.getBuildCancellationToken(); + var job = result.render.getTaskCancellationToken(); - if (job != null && result.buildTime >= result.render.getLastSubmittedFrame()) { - result.render.setBuildCancellationToken(null); + if (job != null && result.submitTime >= result.render.getLastSubmittedFrame()) { + result.render.setTaskCancellationToken(null); } - result.render.setLastBuiltFrame(result.buildTime); + result.render.setLastTaskFrame(result.submitTime); } } @@ -337,20 +341,19 @@ private void updateSectionInfo(RenderSection render, BuiltSectionInfo info) { } } - private static List filterChunkBuildResults(ArrayList outputs) { - // TODO: handle sort results in this method. the types should be split into two lists - var map = new Reference2ReferenceLinkedOpenHashMap(); + private static List filterChunkBuildResults(ArrayList outputs) { + var map = new Reference2ReferenceLinkedOpenHashMap(); for (var output : outputs) { - if (!(output instanceof ChunkBuildOutput) && output.render.isDisposed() || output.render.getLastBuiltFrame() > output.buildTime) { + if (output.render.isDisposed() || output.render.getLastTaskFrame() > output.submitTime) { continue; } var render = output.render; var previous = map.get(render); - if (previous == null || previous.buildTime < output.buildTime) { - map.put(render, (ChunkBuildOutput) output); + if (previous == null || previous.submitTime < output.submitTime) { + map.put(render, output); } } @@ -368,8 +371,8 @@ private ArrayList collectChunkBuildResults() { return results; } - private void submitRebuildTasks(ChunkJobCollector collector, ChunkUpdateType type) { - var queue = this.rebuildLists.get(type); + private void submitSectionTasks(ChunkJobCollector collector, ChunkUpdateType type) { + var queue = this.taskLists.get(type); while (!queue.isEmpty() && collector.canOffer()) { RenderSection section = queue.remove(); @@ -390,13 +393,13 @@ private void submitRebuildTasks(ChunkJobCollector collector, ChunkUpdateType typ var job = this.builder.scheduleTask(task, type.isImportant(), collector::onJobFinished); collector.addSubmittedJob(job); - section.setBuildCancellationToken(job); + section.setTaskCancellationToken(job); } else { // TODO: why does this exist and where is this data read? is null translucent data ok? var result = ChunkJobResult.successfully(new ChunkBuildOutput(section, frame, null, BuiltSectionInfo.EMPTY, Collections.emptyMap())); this.buildResults.add(result); - section.setBuildCancellationToken(null); + section.setTaskCancellationToken(null); } section.setLastSubmittedFrame(frame); @@ -415,11 +418,6 @@ private void submitRebuildTasks(ChunkJobCollector collector, ChunkUpdateType typ } public ChunkBuilderSortingTask createSortTask(RenderSection render, int frame) { - if (render.getTranslucentData() == null) { - // TODO: this should never happen since sections are triggered by GFNI only if they have translucent data. However, the data may have been deleted in the mean time? or would it be removed from GFNI when that happens? - return null; - } - return new ChunkBuilderSortingTask(render, frame, this.cameraPosition); } @@ -477,13 +475,12 @@ public int getVisibleChunkCount() { public void scheduleSort(ChunkSectionPos pos) { // TODO: Does this need to invalidate the section cache? - // TODO: re-enable once sort tasks are figured out - // RenderSection section = this.sectionByPosition.get(pos.asLong()); + RenderSection section = this.sectionByPosition.get(pos.asLong()); - // if (section != null && ChunkUpdateType.canPromote(section.getPendingUpdate(), ChunkUpdateType.TRANSLUCENT_SORT)) { - // section.setPendingUpdate(ChunkUpdateType.TRANSLUCENT_SORT); - // } + if (section != null && ChunkUpdateType.canPromote(section.getPendingUpdate(), ChunkUpdateType.TRANSLUCENT_SORT)) { + section.setPendingUpdate(ChunkUpdateType.TRANSLUCENT_SORT); + } } public void scheduleRebuild(int x, int y, int z, boolean important) { @@ -596,9 +593,9 @@ public Collection getDebugStrings() { list.add(String.format("Chunk Queues: U=%02d (P0=%03d | P1=%03d | P2=%03d)", this.buildResults.size(), - this.rebuildLists.get(ChunkUpdateType.IMPORTANT_REBUILD).size(), - this.rebuildLists.get(ChunkUpdateType.REBUILD).size(), - this.rebuildLists.get(ChunkUpdateType.INITIAL_BUILD).size()) + this.taskLists.get(ChunkUpdateType.IMPORTANT_REBUILD).size(), + this.taskLists.get(ChunkUpdateType.REBUILD).size(), + this.taskLists.get(ChunkUpdateType.INITIAL_BUILD).size()) ); return list; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/BuilderTaskOutput.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/BuilderTaskOutput.java index a1f417ed61..ecd1f8b0fe 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/BuilderTaskOutput.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/BuilderTaskOutput.java @@ -4,15 +4,13 @@ public abstract class BuilderTaskOutput { public final RenderSection render; - public final int buildTime; + public final int submitTime; public BuilderTaskOutput(RenderSection render, int buildTime) { this.render = render; - this.buildTime = buildTime; + this.submitTime = buildTime; } public void delete() { } - - public abstract void setDataOn(RenderSection render); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java index f4abc5d082..fd1b3dc15d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java @@ -36,11 +36,4 @@ public void delete() { data.getVertexData().free(); } } - - @Override - public void setDataOn(RenderSection render) { - super.setDataOn(render); - - render.setInfo(this.info); - } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java index f1f6030736..bc56f68662 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java @@ -15,9 +15,4 @@ public ChunkSortOutput(RenderSection render, int buildTime, TranslucentData tran this.translucentData = translucentData; } - - @Override - public void setDataOn(RenderSection render) { - render.setTranslucentData(translucentData); - } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java index 2c3bfe2a06..aa066f3158 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java @@ -158,7 +158,7 @@ public ChunkBuildOutput execute(ChunkBuildContext buildContext, CancellationToke renderData.setOcclusionData(occluder.build()); - return new ChunkBuildOutput(this.render, this.buildTime, translucentData, renderData.build(), meshes); + return new ChunkBuildOutput(this.render, this.submitTime, translucentData, renderData.build(), meshes); } private CrashException fillCrashInfo(CrashReport report, WorldSlice slice, BlockPos pos) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java index aae55cf347..d08b876a19 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java @@ -16,6 +16,6 @@ public ChunkBuilderSortingTask(RenderSection render, int frame, Vector3fc camera public ChunkSortOutput execute(ChunkBuildContext context, CancellationToken cancellationToken) { this.render.getTranslucentData().sort(this.cameraPos); - return new ChunkSortOutput(this.render, this.buildTime, this.render.getTranslucentData()); + return new ChunkSortOutput(this.render, this.submitTime, this.render.getTranslucentData()); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderTask.java index 56cdc099b2..e8d4c9a239 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderTask.java @@ -20,12 +20,12 @@ */ public abstract class ChunkBuilderTask { protected final RenderSection render; - protected final int buildTime; + protected final int submitTime; protected final Vector3fc cameraPos; public ChunkBuilderTask(RenderSection render, int time, Vector3fc cameraPos) { this.render = render; - this.buildTime = time; + this.submitTime = time; this.cameraPos = new Vector3f( cameraPos.x() - (float) render.getOriginX(), cameraPos.y() - (float) render.getOriginY(), diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/lists/VisibleChunkCollector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/lists/VisibleChunkCollector.java index a294766343..d46fa7abf5 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/lists/VisibleChunkCollector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/lists/VisibleChunkCollector.java @@ -34,7 +34,7 @@ public void accept(RenderSection section) { private void addToRebuildLists(RenderSection section) { ChunkUpdateType type = section.getPendingUpdate(); - if (type != null && section.getBuildCancellationToken() == null) { + if (type != null && section.getTaskCancellationToken() == null) { Queue queue = this.sortedRebuildLists.get(type); if (queue.size() < type.getMaximumQueueSize()) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java index 6829098598..28d03066fc 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java @@ -13,7 +13,9 @@ import me.jellysquid.mods.sodium.client.gl.util.VertexRange; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; +import me.jellysquid.mods.sodium.client.render.chunk.compile.BuilderTaskOutput; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildOutput; +import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkSortOutput; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; import me.jellysquid.mods.sodium.client.render.chunk.gfni.MixedDirectionData; import me.jellysquid.mods.sodium.client.render.chunk.gfni.PresentTranslucentData; @@ -53,42 +55,47 @@ public void update() { } } - public void uploadMeshes(CommandList commandList, Collection results) { + public void uploadResults(CommandList commandList, Collection results) { for (var entry : this.createMeshUploadQueues(results)) { - this.uploadMeshes(commandList, entry.getKey(), entry.getValue()); + this.uploadResults(commandList, entry.getKey(), entry.getValue()); } } - private void uploadMeshes(CommandList commandList, RenderRegion region, Collection results) { + private void uploadResults(CommandList commandList, RenderRegion region, Collection results) { var uploads = new ArrayList(); var indexUploads = new ArrayList(); - for (ChunkBuildOutput result : results) { + for (BuilderTaskOutput result : results) { int renderSectionIndex = result.render.getSectionIndex(); - for (TerrainRenderPass pass : DefaultTerrainRenderPasses.ALL) { - var storage = region.getStorage(pass); - if (storage != null) { - storage.removeMeshes(renderSectionIndex); - } + if (result instanceof ChunkBuildOutput chunkBuildOutput) { + for (TerrainRenderPass pass : DefaultTerrainRenderPasses.ALL) { + var storage = region.getStorage(pass); + + if (storage != null) { + storage.removeMeshes(renderSectionIndex); + } - BuiltSectionMeshParts mesh = result.getMesh(pass); + BuiltSectionMeshParts mesh = chunkBuildOutput.getMesh(pass); - if (mesh != null) { - uploads.add(new PendingSectionMeshUpload(result.render, mesh, pass, - new PendingUpload(mesh.getVertexData()))); + if (mesh != null) { + uploads.add(new PendingSectionMeshUpload(result.render, mesh, pass, + new PendingUpload(mesh.getVertexData()))); + } } } - var translucentStorage = region.getTranslucentStorage(); - if (translucentStorage != null) { - translucentStorage.removeMeshes(renderSectionIndex); - } + if (result instanceof ChunkSortOutput chunkSortOutput) { + var translucentStorage = region.getTranslucentStorage(); + if (translucentStorage != null) { + translucentStorage.removeMeshes(renderSectionIndex); + } - var translucentData = result.translucentData; - if (translucentData != null && translucentData instanceof PresentTranslucentData presentTranslucentData) { - indexUploads.add(new PendingSectionIndexBufferUpload(result.render, presentTranslucentData, + var translucentData = chunkSortOutput.translucentData; + if (translucentData != null && translucentData instanceof PresentTranslucentData presentTranslucentData) { + indexUploads.add(new PendingSectionIndexBufferUpload(result.render, presentTranslucentData, new PendingUpload(presentTranslucentData.buffer))); + } } } @@ -149,8 +156,8 @@ private void uploadMeshes(CommandList commandList, RenderRegion region, Collecti } } - private Reference2ReferenceMap.FastEntrySet> createMeshUploadQueues(Collection results) { - var map = new Reference2ReferenceOpenHashMap>(); + private Reference2ReferenceMap.FastEntrySet> createMeshUploadQueues(Collection results) { + var map = new Reference2ReferenceOpenHashMap>(); for (var result : results) { var queue = map.computeIfAbsent(result.render.getRegion(), k -> new ArrayList<>()); From 5c593098c9dfea05f1fb7e597567ae71a2201358 Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 16 Sep 2023 15:02:15 +0200 Subject: [PATCH 040/256] fix bit array out of bounds --- .../mods/sodium/client/util/collections/BitArray.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/collections/BitArray.java b/src/main/java/me/jellysquid/mods/sodium/client/util/collections/BitArray.java index 85d3f80a0c..6b9718a724 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/collections/BitArray.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/collections/BitArray.java @@ -240,6 +240,9 @@ public boolean getAndUnset(int index) { public int nextSetBit(int fromIndex) { int u = wordIndex(fromIndex); + if (u >= this.words.length) { + return -1; + } long word = this.words[u] & (WORD_MASK << fromIndex); while (true) { From 6d7f0368ce53e913c6a52c63c79053ef445357a0 Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 16 Sep 2023 16:56:45 +0200 Subject: [PATCH 041/256] gfni settings --- .../client/gui/SodiumGameOptionPages.java | 14 +++++- .../sodium/client/gui/SodiumGameOptions.java | 43 +++++++++++++++++++ .../render/chunk/DefaultChunkRenderer.java | 3 +- .../render/chunk/RenderSectionManager.java | 21 ++++++--- .../tasks/ChunkBuilderMeshingTask.java | 1 + .../sodium/client/render/chunk/gfni/GFNI.java | 3 -- .../render/chunk/gfni/GroupBuilder.java | 38 ++++++++++++++-- .../client/render/chunk/gfni/NoneData.java | 7 +++ .../client/render/chunk/gfni/SortType.java | 2 + .../resources/assets/sodium/lang/en_us.json | 9 +++- 10 files changed, 124 insertions(+), 17 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java index 6defffdb21..b00354d4a9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java @@ -260,8 +260,7 @@ public static OptionPage performance() { .setBinding((opts, value) -> opts.performance.alwaysDeferChunkUpdates = value, opts -> opts.performance.alwaysDeferChunkUpdates) .setFlags(OptionFlag.REQUIRES_RENDERER_UPDATE) .build()) - .build() - ); + .build()); groups.add(OptionGroup.createBuilder() .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) @@ -310,6 +309,17 @@ public static OptionPage performance() { .build()) .build()); + groups.add(OptionGroup.createBuilder() + .add(OptionImpl.createBuilder(SodiumGameOptions.SortBehavior.class, sodiumOpts) + .setName(Text.translatable("sodium.options.sort_behavior.name")) + .setTooltip(Text.translatable("sodium.options.sort_behavior.tooltip")) + .setControl(option -> new CyclingControl<>(option, SodiumGameOptions.SortBehavior.class)) + .setBinding((opts, value) -> opts.performance.sortBehavior = value, opts -> opts.performance.sortBehavior) + .setImpact(OptionImpact.MEDIUM) + .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) + .build()) + .build()); + return new OptionPage(Text.translatable("sodium.options.pages.performance"), ImmutableList.copyOf(groups)); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java index 1304b6163f..e509565d3a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java @@ -5,6 +5,7 @@ import com.google.gson.GsonBuilder; import com.google.gson.annotations.SerializedName; import me.jellysquid.mods.sodium.client.gui.options.TextProvider; +import me.jellysquid.mods.sodium.client.render.chunk.gfni.SortType; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.client.option.GraphicsMode; import net.minecraft.text.Text; @@ -15,6 +16,8 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; +import java.util.Set; +import java.util.EnumSet; public class SodiumGameOptions { private static final String DEFAULT_FILE_NAME = "sodium-options.json"; @@ -45,6 +48,46 @@ public static class PerformanceSettings { public boolean useFogOcclusion = true; public boolean useBlockFaceCulling = true; public boolean useNoErrorGLContext = true; + + public SortBehavior sortBehavior = SortBehavior.DYNAMIC_ALL; + } + + public enum SortBehavior implements TextProvider { + ONLY_TRIVIAL("options.sort_behavior.only_trivial", Set.of(SortType.NONE)), + STATIC_NORMAL_RELATIVE("options.sort_behavior.static_normal_relative", getUpTo(SortType.STATIC_NORMAL_RELATIVE)), + STATIC_TOPO_ACYCLIC("options.sort_behavior.static_topo_acyclic", getUpTo(SortType.STATIC_TOPO_ACYCLIC)), + // TODO: enable when implemented + // DYNAMIC_TOPO_CYCLIC("options.sort_behavior.dynamic_topo_cyclic", getUpTo(SortType.DYNAMIC_TOPO_CYCLIC)), + DYNAMIC_ALL("options.sort_behavior.dynamic_all", getUpTo(SortType.DYNAMIC_ALL)), + ONLY_DYNAMIC_ALL("options.sort_behavior.only_dynamic_all", Set.of(SortType.DYNAMIC_ALL)); + + private final Text name; + public final Set sortTypes; + public final boolean needsPlaneTrigger; + public final boolean needsIndexBuffer; + + SortBehavior(String name, Set sortTypes) { + this.name = Text.translatable(name); + this.sortTypes = sortTypes; + this.needsPlaneTrigger = sortTypes.stream().anyMatch(type -> type.needsPlaneTrigger); + this.needsIndexBuffer = sortTypes.stream().anyMatch(type -> type.needsIndexBuffer); + } + + @Override + public Text getLocalizedName() { + return this.name; + } + + private static final Set getUpTo(SortType sortType) { + var set = EnumSet.noneOf(SortType.class); + for (var type : SortType.values()) { + set.add(type); + if (type == sortType) { + break; + } + } + return set; + } } public static class AdvancedSettings { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java index aef6a4ba3b..83230b8926 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java @@ -49,7 +49,8 @@ public void render(ChunkRenderMatrices matrices, CameraTransform camera) { super.begin(renderPass); - boolean isTranslucent = renderPass == DefaultTerrainRenderPasses.TRANSLUCENT; + boolean isTranslucent = renderPass == DefaultTerrainRenderPasses.TRANSLUCENT + && SodiumClientMod.options().performance.sortBehavior.needsIndexBuffer; boolean useBlockFaceCulling = SodiumClientMod.options().performance.useBlockFaceCulling; ChunkShaderInterface shader = this.activeProgram.getInterface(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index ab73757b5c..405b8e0ca5 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -68,7 +68,6 @@ public class RenderSectionManager { private final ChunkRenderer chunkRenderer; private final ClientWorld world; - private final GFNI gfni; private final ReferenceSet sectionsWithGlobalEntities = new ReferenceOpenHashSet<>(); @@ -76,6 +75,8 @@ public class RenderSectionManager { private final int renderDistance; + private @Nullable GFNI gfni = null; + @NotNull private SortedRenderLists renderLists; @@ -93,7 +94,9 @@ public RenderSectionManager(ClientWorld world, int renderDistance, CommandList c this.chunkRenderer = new DefaultChunkRenderer(RenderDevice.INSTANCE, ChunkMeshFormats.COMPACT); this.world = world; - this.gfni = new GFNI(); + if (SodiumClientMod.options().performance.sortBehavior.needsPlaneTrigger) { + this.gfni = new GFNI(); + } this.builder = new ChunkBuilder(world, ChunkMeshFormats.COMPACT); @@ -218,7 +221,9 @@ public void onSectionRemoved(int x, int y, int z) { section.delete(); - this.gfni.removeSection(chunkSectionLongPos); + if (this.gfni != null) { + this.gfni.removeSection(chunkSectionLongPos); + } this.needsUpdate = true; } @@ -315,9 +320,11 @@ private void processChunkBuildResults(ArrayList results) { if (result instanceof ChunkBuildOutput chunkBuildOutput) { this.updateSectionInfo(result.render, chunkBuildOutput.info); } - if (result instanceof ChunkSortOutput chunkSortOutput) { + if (result instanceof ChunkSortOutput chunkSortOutput && chunkSortOutput.translucentData != null) { result.render.setTranslucentData(chunkSortOutput.translucentData); - this.gfni.integrateTranslucentData(chunkSortOutput.translucentData); + if (this.gfni != null) { + this.gfni.integrateTranslucentData(chunkSortOutput.translucentData); + } } var job = result.render.getTaskCancellationToken(); @@ -424,9 +431,11 @@ public ChunkBuilderSortingTask createSortTask(RenderSection render, int frame) { public void processGFNIMovement( double lastCameraX, double lastCameraY, double lastCameraZ, double cameraX, double cameraY, double cameraZ) { - this.gfni.triggerSections(this::scheduleSort, + if (this.gfni != null) { + this.gfni.triggerSections(this::scheduleSort, lastCameraX, lastCameraY, lastCameraZ, cameraX, cameraY, cameraZ); + } } public void markGraphDirty() { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java index aa066f3158..a4c5d3b513 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java @@ -155,6 +155,7 @@ public ChunkBuildOutput execute(ChunkBuildContext buildContext, CancellationToke TranslucentData translucentData = groupBuilder.getTranslucentData( meshes.get(DefaultTerrainRenderPasses.TRANSLUCENT), cameraPos); + System.out.println("translucentData: " + translucentData.getSortType()); renderData.setOcclusionData(occluder.build()); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java index c3a15311c2..1f7d0b24a4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java @@ -163,9 +163,6 @@ private void addSectionInNewNormalLists(AccumulationGroup accGroup) { * @return the sort type that the group builder's relevance heuristic determined */ public void integrateTranslucentData(TranslucentData translucentData) { - if (translucentData == null) { - return; // TODO: when does this even happen? - } long chunkSectionLongPos = translucentData.sectionPos.asLong(); // remove the section if the data doesn't need to trigger on face planes diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java index 553849a6f7..8f49a7bede 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java @@ -7,7 +7,9 @@ import it.unimi.dsi.fastutil.ints.Int2ReferenceLinkedOpenHashMap; import it.unimi.dsi.fastutil.objects.ReferenceArrayList; +import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.gl.util.VertexRange; +import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions.SortBehavior; import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; @@ -169,6 +171,17 @@ public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] verti } } + private static SortType filterSortType(SortType sortType) { + // SortBehavior sortBehavior = SodiumClientMod.options().performance.sortBehavior; + // if (!sortBehavior.sortTypes.contains(sortType)) { + // return SortType.NONE; + // } + // if (sortBehavior == SortBehavior.ONLY_DYNAMIC_ALL) { + // return SortType.DYNAMIC_ALL; + // } + return sortType; + } + /** * Checks if this group builder is relevant for translucency sort triggering. It * determines a sort type, which is either no sorting, a static sort or a @@ -216,8 +229,13 @@ public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] verti * @return the required sort type to ensure this section always looks correct */ private SortType sortTypeHeuristic() { + SortBehavior sortBehavior = SodiumClientMod.options().performance.sortBehavior; + if (sortBehavior == SortBehavior.ONLY_DYNAMIC_ALL) { + return SortType.DYNAMIC_ALL; + } + // special case A - if (this.facePlaneCount <= 1) { + if (sortBehavior == SortBehavior.ONLY_TRIVIAL || this.facePlaneCount <= 1) { return SortType.NONE; } @@ -302,7 +320,7 @@ private SortType sortTypeHeuristic() { // heuristically determine if a topo sort should be attempted, if the attempt // fails the sort type is downgraded to DYNAMIC_ALL. If there are no cycles, // it's upgraded to acyclic. - if (this.unalignedQuadCount <= 2 && this.quads.size() <= 100) { + if (this.unalignedQuadCount <= 2 && this.quads.size() <= 400) { return SortType.DYNAMIC_TOPO_CYCLIC; } @@ -310,7 +328,7 @@ private SortType sortTypeHeuristic() { } public SortType estimateSortType() { - this.sortType = sortTypeHeuristic(); + this.sortType = filterSortType(sortTypeHeuristic()); return this.sortType; } @@ -381,7 +399,8 @@ private DynamicData constructDynamicData(BuiltSectionMeshParts translucentMesh, } if (reuseBuffer == null) { - reuseBuffer = new NativeBuffer(TranslucentData.vertexCountToIndexBytes(quadCount * TranslucentData.VERTICES_PER_QUAD)); + reuseBuffer = new NativeBuffer( + TranslucentData.vertexCountToIndexBytes(quadCount * TranslucentData.VERTICES_PER_QUAD)); } Vector3f[] centers = new Vector3f[quadCount]; @@ -406,6 +425,10 @@ public TranslucentData getTranslucentData(BuiltSectionMeshParts translucentMesh, return constructStaticNormalRelativeData(translucentMesh); } + if (SodiumClientMod.options().performance.sortBehavior == SortBehavior.ONLY_DYNAMIC_ALL) { + return constructDynamicData(translucentMesh, null, cameraPos); + } + // from this point on we know the estimated sort type requires direction mixing // (no backface culling) and all vertices are in the UNASSIGNED direction. NativeBuffer buffer = null; @@ -440,6 +463,13 @@ public TranslucentData getTranslucentData(BuiltSectionMeshParts translucentMesh, + ", unaligned dynamic hits: " + unalignedDynamicHits); } + // filter the sort type with the user setting and re-evaluate + this.sortType = filterSortType(this.sortType); + + if (this.sortType == SortType.NONE) { + return new NoneData(this.sectionPos); + } + if (this.sortType == SortType.DYNAMIC_ALL) { return constructDynamicData(translucentMesh, buffer, cameraPos); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NoneData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NoneData.java index c14ff396e7..1bcdd02d16 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NoneData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NoneData.java @@ -5,6 +5,13 @@ /** * None translucent data exists to signal to GFNI that if a section previously * had triggering data, it no longer does and should be removed. + * + * With this sort type the section's translucent quads can be rendered in any + * order. However, they do need to be rendered with some index buffer, so that + * vertices are assembled into quads. Since the sort order doesn't matter, all + * sections with this sort type can share the same data in the index buffer. + * + * TODO: make shared NoneData in the SectionRenderDataStorage or sth */ public class NoneData extends TranslucentData { public NoneData(ChunkSectionPos sectionPos) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/SortType.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/SortType.java index 12de4613b1..918d91ed4d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/SortType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/SortType.java @@ -3,6 +3,8 @@ /** * What type of sorting to use for a section. Calculated by a heuristic after * building a section. + * + * TODO: maybe remove needsDynamicSort if they remain unused */ public enum SortType { /** diff --git a/src/main/resources/assets/sodium/lang/en_us.json b/src/main/resources/assets/sodium/lang/en_us.json index 13e41d62b4..1ca6f8a1d3 100644 --- a/src/main/resources/assets/sodium/lang/en_us.json +++ b/src/main/resources/assets/sodium/lang/en_us.json @@ -56,5 +56,12 @@ "sodium.options.buttons.donate": "Buy us a coffee!", "sodium.console.game_restart": "The game must be restarted to apply one or more video settings!", "sodium.console.broken_nvidia_driver": "Your NVIDIA graphics drivers are out of date!\n * This will cause severe performance issues and crashes when Sodium is installed.\n * Please update your graphics drivers to the latest version (version 536.23 or newer.)", - "sodium.console.pojav_launcher": "PojavLauncher is not supported when using Sodium.\n * You are very likely to run into extreme performance issues, graphical bugs, and crashes.\n * You will be on your own if you decide to continue -- we will not help you with any bugs or crashes!" + "sodium.console.pojav_launcher": "PojavLauncher is not supported when using Sodium.\n * You are very likely to run into extreme performance issues, graphical bugs, and crashes.\n * You will be on your own if you decide to continue -- we will not help you with any bugs or crashes!", + "sodium.options.sort_behavior.name": "Sort Behavior", + "sodium.options.sort_behavior.tooltip": "Controls when and with how much effort translucency sorting is performed. Dynamic and adaptive sorting will sort geometry as you move around. Lesser sort types perform sorting on an best-effort basis. The more sorting is performed the higher the performance impact.", + "options.sort_behavior.only_trivial": "No Sorting", + "options.sort_behavior.static_normal_relative": "Static Relative", + "options.sort_behavior.static_topo_acyclic": "Static Topological", + "options.sort_behavior.dynamic_all": "Auto", + "options.sort_behavior.only_dynamic_all": "Only Dynamic" } From 0d724d918e021c1409d82ba5bafd1b5196d4500a Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 16 Sep 2023 17:31:03 +0200 Subject: [PATCH 042/256] better sort type and GFNI statistics --- .../render/chunk/RenderSectionManager.java | 10 ++- .../sodium/client/render/chunk/gfni/GFNI.java | 80 +++++++++++++------ .../client/render/chunk/gfni/Group.java | 6 +- .../client/render/chunk/gfni/NormalList.java | 2 +- 4 files changed, 66 insertions(+), 32 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index 405b8e0ca5..dbd88ff423 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -22,6 +22,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.compile.tasks.ChunkBuilderTask; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionInfo; import me.jellysquid.mods.sodium.client.render.chunk.gfni.GFNI; +import me.jellysquid.mods.sodium.client.render.chunk.gfni.TranslucentData; import me.jellysquid.mods.sodium.client.render.chunk.lists.ChunkRenderList; import me.jellysquid.mods.sodium.client.render.chunk.lists.SortedRenderLists; import me.jellysquid.mods.sodium.client.render.chunk.lists.VisibleChunkCollector; @@ -222,7 +223,7 @@ public void onSectionRemoved(int x, int y, int z) { section.delete(); if (this.gfni != null) { - this.gfni.removeSection(chunkSectionLongPos); + this.gfni.removeSection(section.getTranslucentData(), chunkSectionLongPos); } this.needsUpdate = true; @@ -321,9 +322,10 @@ private void processChunkBuildResults(ArrayList results) { this.updateSectionInfo(result.render, chunkBuildOutput.info); } if (result instanceof ChunkSortOutput chunkSortOutput && chunkSortOutput.translucentData != null) { + TranslucentData oldData = result.render.getTranslucentData(); result.render.setTranslucentData(chunkSortOutput.translucentData); if (this.gfni != null) { - this.gfni.integrateTranslucentData(chunkSortOutput.translucentData); + this.gfni.integrateTranslucentData(oldData, chunkSortOutput.translucentData); } } @@ -607,6 +609,10 @@ public Collection getDebugStrings() { this.taskLists.get(ChunkUpdateType.INITIAL_BUILD).size()) ); + if (this.gfni != null) { + this.gfni.addDebugStrings(list); + } + return list; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java index 1f7d0b24a4..5e0797c952 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java @@ -1,14 +1,15 @@ package me.jellysquid.mods.sodium.client.render.chunk.gfni; +import java.util.List; import java.util.function.Consumer; import org.joml.Vector3fc; import com.mojang.blaze3d.systems.VertexSorter; +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; -import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet; -import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.util.sorting.VertexSorters; import net.minecraft.util.math.ChunkSectionPos; @@ -67,9 +68,26 @@ public class GFNI { } } - // TODO: both of these are for debugging - ObjectLinkedOpenHashSet triggeredSections = new ObjectLinkedOpenHashSet<>(50); - ObjectOpenHashSet triggeredNormals = new ObjectOpenHashSet<>(50); + /** + * A set of all the sections that were triggered the last time something was + * triggered. + * + * TODO: only count the sections and not their whole position + */ + private final LongOpenHashSet triggeredSections = new LongOpenHashSet(50); + private int triggeredSectionCount = 0; + + /** + * A set of all the normals that were triggered the last time something was + * triggered. + */ + private final IntOpenHashSet triggeredNormals = new IntOpenHashSet(50); + private int triggeredNormalCount = 0; + + /** + * A map of the number of times each sort type is currently in use. + */ + private final int[] sortTypeCounters = new int[SortType.values().length]; /** * Triggers the sections that the given camera movement crosses face planes of. @@ -94,21 +112,29 @@ public void triggerSections( normalList.processMovement(this, lastCameraX, lastCameraY, lastCameraZ, cameraX, cameraY, cameraZ); } + var newTriggeredSectionsCount = this.triggeredSections.size(); + var newTriggeredNormalCount = this.triggeredNormals.size(); + if (newTriggeredSectionsCount > 0) { + this.triggeredSectionCount = newTriggeredSectionsCount; + this.triggeredNormalCount = newTriggeredNormalCount; + } + // TODO: the collections for tracking sections are only used for debugging int triggerCount = this.triggeredSections.size(); if (triggerCount > 0) { System.out.println("Triggered " + triggerCount + " sections"); - for (ChunkSectionPos section : this.triggeredSections) { - System.out.println(section.getX() + " " + section.getY() + " " + section.getZ()); + for (long section : this.triggeredSections) { + ChunkSectionPos sectionPos = ChunkSectionPos.from(section); + System.out.println(sectionPos.getX() + " " + sectionPos.getY() + " " + sectionPos.getZ()); } } triggerSectionCallback = null; } - void triggerSection(ChunkSectionPos section, Vector3fc normal) { - this.triggeredSections.add(section); - this.triggeredNormals.add(normal); + void triggerSection(ChunkSectionPos section, int groupBuilderKey) { + this.triggeredSections.add(section.asLong()); + this.triggeredNormals.add(groupBuilderKey); // by simply setting a chunk update type on the section, it naturally only gets // updated once the section becomes visible. @@ -126,18 +152,16 @@ private void removeSectionFromList(NormalList normalList, long chunkSectionLongP /** * Removes a section from GFNI. This removes all its face planes. * + * @param oldTranslucentData the data of the section to remove * @param chunkSectionLongPos the section to remove */ - public void removeSection(long chunkSectionLongPos) { - int normalListCount = this.normalLists.size(); - + public void removeSection(TranslucentData oldTranslucentData, long chunkSectionLongPos) { for (var normalList : this.normalLists.values()) { removeSectionFromList(normalList, chunkSectionLongPos); } - // TODO: remove - if (normalListCount != this.normalLists.size()) { - System.out.println(normalLists.size() + " normal lists"); + if (oldTranslucentData != null) { + this.sortTypeCounters[oldTranslucentData.getSortType().ordinal()]--; } } @@ -156,20 +180,17 @@ private void addSectionInNewNormalLists(AccumulationGroup accGroup) { * contains the translucent face planes of a single section. This method may * also remove the section if it has become irrelevant. * - * TODO: marked as synchronized because it's expected to be fast, see class - * comment - * * @param builder the group builder to integrate * @return the sort type that the group builder's relevance heuristic determined */ - public void integrateTranslucentData(TranslucentData translucentData) { + public void integrateTranslucentData(TranslucentData oldTranslucentData, TranslucentData translucentData) { long chunkSectionLongPos = translucentData.sectionPos.asLong(); // remove the section if the data doesn't need to trigger on face planes // TODO: only do the heuristic and topo sort if the hashes are different? SortType sortType = translucentData.getSortType(); if (!sortType.needsPlaneTrigger) { - removeSection(chunkSectionLongPos); + removeSection(oldTranslucentData, chunkSectionLongPos); return; } @@ -178,7 +199,6 @@ public void integrateTranslucentData(TranslucentData translucentData) { throw new RuntimeException("TranslucentData other than DynamicData passed to GFNI"); } var dynamicData = (DynamicData) translucentData; - int normalListCount = this.normalLists.size(); // go through all normal lists and check against the normals that the group // builder has. if the normal list has data for the section, but the group @@ -213,9 +233,19 @@ public void integrateTranslucentData(TranslucentData translucentData) { } } - // TODO: remove - if (normalListCount != this.normalLists.size()) { - System.out.println(normalLists.size() + " normal lists"); + if (oldTranslucentData != null) { + this.sortTypeCounters[oldTranslucentData.getSortType().ordinal()]--; } + this.sortTypeCounters[sortType.ordinal()]++; + } + + public void addDebugStrings(List list) { + list.add("GFNI NL=" + this.normalLists.size() + + " TrS=" + this.triggeredSectionCount + + " TrN=" + this.triggeredNormalCount); + list.add("N=" + this.sortTypeCounters[SortType.NONE.ordinal()] + + " SNR=" + this.sortTypeCounters[SortType.STATIC_NORMAL_RELATIVE.ordinal()] + + " STA=" + this.sortTypeCounters[SortType.STATIC_TOPO_ACYCLIC.ordinal()] + + " DYN=" + this.sortTypeCounters[SortType.DYNAMIC_ALL.ordinal()]); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java index a58d4ce689..f43d90521e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java @@ -1,7 +1,5 @@ package me.jellysquid.mods.sodium.client.render.chunk.gfni; -import org.joml.Vector3fc; - import com.lodborg.intervaltree.DoubleInterval; import it.unimi.dsi.fastutil.doubles.DoubleAVLTreeSet; @@ -52,11 +50,11 @@ void replaceWith(AccumulationGroup accGroup, DoubleInterval accGroupDistances, d } } - void triggerRange(GFNI gfni, double start, double end, Vector3fc normal) { + void triggerRange(GFNI gfni, double start, double end, int groupBuilderKey) { // trigger self on the section if the query range overlaps with the group if (start < this.distances.getEnd() && end > this.distances.getStart() && !this.facePlaneDistances.subSet(start, end).isEmpty()) { - gfni.triggerSection(this.sectionPos, normal); + gfni.triggerSection(this.sectionPos, groupBuilderKey); } } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java index 3cfbfa2f1b..0ed9574f07 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java @@ -104,7 +104,7 @@ void processMovement(GFNI gfni, double lastCameraX, double lastCameraY, double l var interval = new DoubleInterval(start, end, Bounded.CLOSED); for (Interval groupInterval : groupIntervals.query(interval)) { for (Group group : groupsByInterval.get(groupInterval)) { - group.triggerRange(gfni, start, end, this.normalf); + group.triggerRange(gfni, start, end, this.groupBuilderKey); } } } From ca6594d4ea840f35b927457c7112ca3b89e0ff1c Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 16 Sep 2023 17:50:12 +0200 Subject: [PATCH 043/256] fix sort type counters --- .../tasks/ChunkBuilderMeshingTask.java | 1 - .../sodium/client/render/chunk/gfni/GFNI.java | 22 ++++++++++--------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java index a4c5d3b513..aa066f3158 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java @@ -155,7 +155,6 @@ public ChunkBuildOutput execute(ChunkBuildContext buildContext, CancellationToke TranslucentData translucentData = groupBuilder.getTranslucentData( meshes.get(DefaultTerrainRenderPasses.TRANSLUCENT), cameraPos); - System.out.println("translucentData: " + translucentData.getSortType()); renderData.setOcclusionData(occluder.build()); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java index 5e0797c952..a1cb139e2a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java @@ -149,10 +149,16 @@ private void removeSectionFromList(NormalList normalList, long chunkSectionLongP } } + private void decrementSortTypeCounter(TranslucentData oldTranslucentData) { + if (oldTranslucentData != null) { + this.sortTypeCounters[oldTranslucentData.getSortType().ordinal()]--; + } + } + /** * Removes a section from GFNI. This removes all its face planes. * - * @param oldTranslucentData the data of the section to remove + * @param oldTranslucentData the data of the section to remove * @param chunkSectionLongPos the section to remove */ public void removeSection(TranslucentData oldTranslucentData, long chunkSectionLongPos) { @@ -160,9 +166,7 @@ public void removeSection(TranslucentData oldTranslucentData, long chunkSectionL removeSectionFromList(normalList, chunkSectionLongPos); } - if (oldTranslucentData != null) { - this.sortTypeCounters[oldTranslucentData.getSortType().ordinal()]--; - } + decrementSortTypeCounter(oldTranslucentData); } private void addSectionInNewNormalLists(AccumulationGroup accGroup) { @@ -189,14 +193,17 @@ public void integrateTranslucentData(TranslucentData oldTranslucentData, Translu // remove the section if the data doesn't need to trigger on face planes // TODO: only do the heuristic and topo sort if the hashes are different? SortType sortType = translucentData.getSortType(); + this.sortTypeCounters[sortType.ordinal()]++; if (!sortType.needsPlaneTrigger) { removeSection(oldTranslucentData, chunkSectionLongPos); return; } + decrementSortTypeCounter(oldTranslucentData); + // TODO: implement cycle breaking and multiple sort orders if (!(translucentData instanceof DynamicData)) { - throw new RuntimeException("TranslucentData other than DynamicData passed to GFNI"); + throw new RuntimeException("Dynamic topo sort not implemented yet"); } var dynamicData = (DynamicData) translucentData; @@ -232,11 +239,6 @@ public void integrateTranslucentData(TranslucentData oldTranslucentData, Translu addSectionInNewNormalLists(accGroup); } } - - if (oldTranslucentData != null) { - this.sortTypeCounters[oldTranslucentData.getSortType().ordinal()]--; - } - this.sortTypeCounters[sortType.ordinal()]++; } public void addDebugStrings(List list) { From 941c97b8750db9c5507092225e4b903efd6fc3b9 Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 16 Sep 2023 19:57:03 +0200 Subject: [PATCH 044/256] refactor translucent data construction into the respective classes --- .../client/render/chunk/gfni/DynamicData.java | 40 ++++++ .../sodium/client/render/chunk/gfni/GFNI.java | 18 +-- .../render/chunk/gfni/GroupBuilder.java | 118 +++--------------- .../chunk/gfni/StaticNormalRelativeData.java | 56 +++++++++ .../chunk/gfni/StaticTopoAcyclicData.java | 9 ++ .../render/chunk/gfni/TranslucentData.java | 19 ++- 6 files changed, 140 insertions(+), 120 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java index 928448fd84..89d05fe7b7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java @@ -1,10 +1,15 @@ package me.jellysquid.mods.sodium.client.render.chunk.gfni; +import java.util.List; + import org.joml.Vector3f; import org.joml.Vector3fc; import it.unimi.dsi.fastutil.ints.Int2ReferenceLinkedOpenHashMap; import me.jellysquid.mods.sodium.client.gl.util.VertexRange; +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; +import me.jellysquid.mods.sodium.client.render.chunk.gfni.GroupBuilder.Quad; import me.jellysquid.mods.sodium.client.util.NativeBuffer; import me.jellysquid.mods.sodium.client.util.sorting.VertexSorters; import net.minecraft.util.math.ChunkSectionPos; @@ -63,4 +68,39 @@ public void sort(Vector3fc cameraPos) { TranslucentData.writeVertexIndexes(intBuffer, VertexSorters.sortByDistance(new Vector3f(cameraPos)).sort(this.centers)); } + + static DynamicData fromMesh(BuiltSectionMeshParts translucentMesh, NativeBuffer reuseBuffer, + Vector3fc cameraPos, List quads, ChunkSectionPos sectionPos, GroupBuilder groupBuilder) { + VertexRange range = TranslucentData.getUnassignedVertexRange(translucentMesh); + int[] centerCounters = new int[ModelQuadFacing.COUNT]; + + for (Quad quad : quads) { + centerCounters[quad.facing().ordinal()]++; + } + + // do a prefix sum to determine the offsets of where to write the centers + int quadCount = 0; + for (int i = 0; i < ModelQuadFacing.COUNT; i++) { + var newCount = centerCounters[i] + quadCount; + centerCounters[i] = quadCount; + quadCount = newCount; + } + + if (reuseBuffer == null) { + reuseBuffer = new NativeBuffer( + TranslucentData.vertexCountToIndexBytes(quadCount * TranslucentData.VERTICES_PER_QUAD)); + } + + Vector3f[] centers = new Vector3f[quadCount]; + + for (int i = 0; i < quads.size(); i++) { + Quad quad = quads.get(i); + centers[centerCounters[quad.facing().ordinal()]++] = quad.center(); + } + + var dynamicData = new DynamicData(sectionPos, + reuseBuffer, range, centers, groupBuilder.axisAlignedDistances, groupBuilder.unalignedDistances); + dynamicData.sort(cameraPos); + return dynamicData; + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java index a1cb139e2a..a08c34d601 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java @@ -5,13 +5,9 @@ import org.joml.Vector3fc; -import com.mojang.blaze3d.systems.VertexSorter; - import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; -import me.jellysquid.mods.sodium.client.util.sorting.VertexSorters; import net.minecraft.util.math.ChunkSectionPos; /** @@ -55,19 +51,7 @@ public class GFNI { * normal lists' interval trees. */ private Consumer triggerSectionCallback; - - /** - * The vertex sorter for each direction. - * TODO: is there a better place to put this - */ - public static final VertexSorter[] SORTERS = new VertexSorter[ModelQuadFacing.DIRECTIONS]; - - static { - for (int i = 0; i < ModelQuadFacing.DIRECTIONS; i++) { - SORTERS[i] = VertexSorters.sortByAxis(ModelQuadFacing.VALUES[i]); - } - } - + /** * A set of all the sections that were triggered the last time something was * triggered. diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java index 8f49a7bede..56c83d8d8e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java @@ -8,7 +8,6 @@ import it.unimi.dsi.fastutil.ints.Int2ReferenceLinkedOpenHashMap; import it.unimi.dsi.fastutil.objects.ReferenceArrayList; import me.jellysquid.mods.sodium.client.SodiumClientMod; -import me.jellysquid.mods.sodium.client.gl.util.VertexRange; import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions.SortBehavior; import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; @@ -42,7 +41,7 @@ public class GroupBuilder { private static int cyclicGraphHits = 0; private static int unalignedDynamicHits = 0; - public static final Vector3fc[] ALIGNED_NORMALS = new Vector3fc[ModelQuadFacing.DIRECTIONS]; + private static final Vector3fc[] ALIGNED_NORMALS = new Vector3fc[ModelQuadFacing.DIRECTIONS]; private static final int OPPOSING_X = 1 << ModelQuadFacing.POS_X.ordinal() | 1 << ModelQuadFacing.NEG_X.ordinal(); private static final int OPPOSING_Y = 1 << ModelQuadFacing.POS_Y.ordinal() | 1 << ModelQuadFacing.NEG_Y.ordinal(); @@ -57,7 +56,7 @@ public class GroupBuilder { AccumulationGroup[] axisAlignedDistances; Int2ReferenceLinkedOpenHashMap unalignedDistances; - final ChunkSectionPos sectionPos; + private final ChunkSectionPos sectionPos; private int facePlaneCount = 0; private int alignedNormalBitmap = 0; private Vector3f minBounds = new Vector3f(16, 16, 16); @@ -68,9 +67,9 @@ public class GroupBuilder { /** * List of translucent quads being rendered. */ - public final ReferenceArrayList quads = new ReferenceArrayList<>(); + private final ReferenceArrayList quads = new ReferenceArrayList<>(); - public SortType sortType; + private SortType sortType; public GroupBuilder(ChunkSectionPos sectionPos) { this.sectionPos = sectionPos; @@ -172,13 +171,13 @@ public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] verti } private static SortType filterSortType(SortType sortType) { - // SortBehavior sortBehavior = SodiumClientMod.options().performance.sortBehavior; - // if (!sortBehavior.sortTypes.contains(sortType)) { - // return SortType.NONE; - // } - // if (sortBehavior == SortBehavior.ONLY_DYNAMIC_ALL) { - // return SortType.DYNAMIC_ALL; - // } + SortBehavior sortBehavior = SodiumClientMod.options().performance.sortBehavior; + if (!sortBehavior.sortTypes.contains(sortType)) { + return SortType.NONE; + } + if (sortBehavior == SortBehavior.ONLY_DYNAMIC_ALL) { + return SortType.DYNAMIC_ALL; + } return sortType; } @@ -332,101 +331,17 @@ public SortType estimateSortType() { return this.sortType; } - private StaticNormalRelativeData constructStaticNormalRelativeData(BuiltSectionMeshParts translucentMesh) { - int vertexCount = 0; - VertexRange[] ranges = translucentMesh.getVertexRanges(); - Vector3f[][] centers = new Vector3f[ModelQuadFacing.COUNT][]; - int[] centerCounters = new int[ModelQuadFacing.COUNT]; - - for (int i = 0; i < ModelQuadFacing.COUNT; i++) { - VertexRange range = ranges[i]; - if (range != null) { - vertexCount += range.vertexCount(); - centers[i] = new Vector3f[range.vertexCount() / TranslucentData.VERTICES_PER_QUAD]; - } - } - - for (Quad quad : this.quads) { - var direction = quad.facing.ordinal(); - centers[direction][centerCounters[direction]++] = quad.center; - } - - var buffer = new NativeBuffer(TranslucentData.vertexCountToIndexBytes(vertexCount)); - IntBuffer bufferBuilder = buffer.getDirectBuffer().asIntBuffer(); - - for (int i = 0; i < ModelQuadFacing.COUNT; i++) { - if (ranges[i] != null) { - TranslucentData.writeVertexIndexes(bufferBuilder, GFNI.SORTERS[i].sort(centers[i])); - } - } - - return new StaticNormalRelativeData(this.sectionPos, buffer, ranges); - } - - private static VertexRange getUnassignedVertexRange(BuiltSectionMeshParts translucentMesh) { - VertexRange range = translucentMesh.getVertexRanges()[ModelQuadFacing.UNASSIGNED.ordinal()]; - - if (range == null) { - throw new IllegalStateException("No unassigned data in mesh"); - } - - return range; - } - - // NOTE: requires filling the contained buffer afterwards - private StaticTopoAcyclicData constructStaticTopoAcyclicData(BuiltSectionMeshParts translucentMesh) { - VertexRange range = GroupBuilder.getUnassignedVertexRange(translucentMesh); - var buffer = new NativeBuffer(TranslucentData.vertexCountToIndexBytes(range.vertexCount())); - - return new StaticTopoAcyclicData(this.sectionPos, buffer, range); - } - - private DynamicData constructDynamicData(BuiltSectionMeshParts translucentMesh, NativeBuffer reuseBuffer, - Vector3fc cameraPos) { - VertexRange range = GroupBuilder.getUnassignedVertexRange(translucentMesh); - int[] centerCounters = new int[ModelQuadFacing.COUNT]; - - for (Quad quad : this.quads) { - centerCounters[quad.facing.ordinal()]++; - } - - // do a prefix sum to determine the offsets of where to write the centers - int quadCount = 0; - for (int i = 0; i < ModelQuadFacing.COUNT; i++) { - var newCount = centerCounters[i] + quadCount; - centerCounters[i] = quadCount; - quadCount = newCount; - } - - if (reuseBuffer == null) { - reuseBuffer = new NativeBuffer( - TranslucentData.vertexCountToIndexBytes(quadCount * TranslucentData.VERTICES_PER_QUAD)); - } - - Vector3f[] centers = new Vector3f[quadCount]; - - for (int i = 0; i < this.quads.size(); i++) { - Quad quad = this.quads.get(i); - centers[centerCounters[quad.facing.ordinal()]++] = quad.center; - } - - var dynamicData = new DynamicData(this.sectionPos, - reuseBuffer, range, centers, axisAlignedDistances, unalignedDistances); - dynamicData.sort(cameraPos); - return dynamicData; - } - public TranslucentData getTranslucentData(BuiltSectionMeshParts translucentMesh, Vector3fc cameraPos) { if (this.sortType == SortType.NONE || translucentMesh == null) { return new NoneData(this.sectionPos); } if (this.sortType == SortType.STATIC_NORMAL_RELATIVE) { - return constructStaticNormalRelativeData(translucentMesh); + return StaticNormalRelativeData.fromMesh(translucentMesh, quads, sectionPos); } if (SodiumClientMod.options().performance.sortBehavior == SortBehavior.ONLY_DYNAMIC_ALL) { - return constructDynamicData(translucentMesh, null, cameraPos); + return DynamicData.fromMesh(translucentMesh, null, cameraPos, quads, sectionPos, this); } // from this point on we know the estimated sort type requires direction mixing @@ -443,7 +358,7 @@ public TranslucentData getTranslucentData(BuiltSectionMeshParts translucentMesh, // it can only perform topo sort on acyclic graphs since it has no cycle // breaking, but it will detect cycles and bail to DYNAMIC_ALL // DYNAMIC_TOPO_CYCLIC if there is a cycle - var indexData = constructStaticTopoAcyclicData(translucentMesh); + var indexData = StaticTopoAcyclicData.fromMesh(translucentMesh, sectionPos); buffer = indexData.buffer; IntBuffer indexBuffer = buffer.getDirectBuffer().asIntBuffer(); @@ -467,11 +382,14 @@ public TranslucentData getTranslucentData(BuiltSectionMeshParts translucentMesh, this.sortType = filterSortType(this.sortType); if (this.sortType == SortType.NONE) { + if (buffer != null) { + buffer.free(); + } return new NoneData(this.sectionPos); } if (this.sortType == SortType.DYNAMIC_ALL) { - return constructDynamicData(translucentMesh, buffer, cameraPos); + return DynamicData.fromMesh(translucentMesh, buffer, cameraPos, quads, sectionPos, this); } throw new IllegalStateException("Unknown sort type: " + this.sortType); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java index b925a0757d..bb04b9c58d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java @@ -1,7 +1,18 @@ package me.jellysquid.mods.sodium.client.render.chunk.gfni; +import java.nio.IntBuffer; +import java.util.List; + +import org.joml.Vector3f; + +import com.mojang.blaze3d.systems.VertexSorter; + import me.jellysquid.mods.sodium.client.gl.util.VertexRange; +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; +import me.jellysquid.mods.sodium.client.render.chunk.gfni.GroupBuilder.Quad; import me.jellysquid.mods.sodium.client.util.NativeBuffer; +import me.jellysquid.mods.sodium.client.util.sorting.VertexSorters; import net.minecraft.util.math.ChunkSectionPos; public class StaticNormalRelativeData extends PresentTranslucentData { @@ -16,4 +27,49 @@ public StaticNormalRelativeData(ChunkSectionPos sectionPos, NativeBuffer buffer, public SortType getSortType() { return SortType.STATIC_NORMAL_RELATIVE; } + + /** + * The vertex sorter for each direction. + * TODO: is there a better place to put this + */ + private static final VertexSorter[] SORTERS = new VertexSorter[ModelQuadFacing.DIRECTIONS]; + + static { + for (int i = 0; i < ModelQuadFacing.DIRECTIONS; i++) { + SORTERS[i] = VertexSorters.sortByAxis(ModelQuadFacing.VALUES[i]); + } + } + + static StaticNormalRelativeData fromMesh(BuiltSectionMeshParts translucentMesh, + List quads, ChunkSectionPos sectionPos) { + int vertexCount = 0; + VertexRange[] ranges = translucentMesh.getVertexRanges(); + Vector3f[][] centers = new Vector3f[ModelQuadFacing.COUNT][]; + int[] centerCounters = new int[ModelQuadFacing.COUNT]; + + for (int i = 0; i < ModelQuadFacing.COUNT; i++) { + VertexRange range = ranges[i]; + if (range != null) { + vertexCount += range.vertexCount(); + centers[i] = new Vector3f[range.vertexCount() / TranslucentData.VERTICES_PER_QUAD]; + } + } + + for (Quad quad : quads) { + var direction = quad.facing().ordinal(); + centers[direction][centerCounters[direction]++] = quad.center(); + } + + var buffer = new NativeBuffer(TranslucentData.vertexCountToIndexBytes(vertexCount)); + IntBuffer bufferBuilder = buffer.getDirectBuffer().asIntBuffer(); + + for (int i = 0; i < ModelQuadFacing.COUNT; i++) { + if (ranges[i] != null) { + // TODO: there's no sorter for unaligned quads in normal relative mode + TranslucentData.writeVertexIndexes(bufferBuilder, SORTERS[i].sort(centers[i])); + } + } + + return new StaticNormalRelativeData(sectionPos, buffer, ranges); + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java index 0c2f40168d..0048a00a18 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java @@ -1,6 +1,7 @@ package me.jellysquid.mods.sodium.client.render.chunk.gfni; import me.jellysquid.mods.sodium.client.gl.util.VertexRange; +import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; import me.jellysquid.mods.sodium.client.util.NativeBuffer; import net.minecraft.util.math.ChunkSectionPos; @@ -13,4 +14,12 @@ public StaticTopoAcyclicData(ChunkSectionPos sectionPos, NativeBuffer buffer, Ve public SortType getSortType() { return SortType.STATIC_TOPO_ACYCLIC; } + + // NOTE: requires filling the contained buffer with data afterwards + static StaticTopoAcyclicData fromMesh(BuiltSectionMeshParts translucentMesh, ChunkSectionPos sectionPos) { + VertexRange range = TranslucentData.getUnassignedVertexRange(translucentMesh); + var buffer = new NativeBuffer(TranslucentData.vertexCountToIndexBytes(range.vertexCount())); + + return new StaticTopoAcyclicData(sectionPos, buffer, range); + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java index 24353f04c6..f284da4dda 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java @@ -4,6 +4,9 @@ import org.joml.Vector3fc; +import me.jellysquid.mods.sodium.client.gl.util.VertexRange; +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; import net.minecraft.util.math.ChunkSectionPos; public abstract class TranslucentData { @@ -24,12 +27,12 @@ public void sort(Vector3fc cameraPos) { throw new UnsupportedOperationException(); } - public static int vertexCountToIndexBytes(int vertexCount) { + static int vertexCountToIndexBytes(int vertexCount) { // convert vertex count to quads, and then to indices, and then to bytes return vertexCount / VERTICES_PER_QUAD * INDICES_PER_QUAD * BYTES_PER_INDEX; } - public static void putQuadVertexIndexes(IntBuffer intBuffer, int quadIndex) { + static void putQuadVertexIndexes(IntBuffer intBuffer, int quadIndex) { int vertexOffset = quadIndex * VERTICES_PER_QUAD; intBuffer.put(vertexOffset + 0); @@ -41,9 +44,19 @@ public static void putQuadVertexIndexes(IntBuffer intBuffer, int quadIndex) { intBuffer.put(vertexOffset + 0); } - public static void writeVertexIndexes(IntBuffer intBuffer, int[] quadIndexes) { + static void writeVertexIndexes(IntBuffer intBuffer, int[] quadIndexes) { for (int quadIndexPos = 0; quadIndexPos < quadIndexes.length; quadIndexPos++) { putQuadVertexIndexes(intBuffer, quadIndexes[quadIndexPos]); } } + + static VertexRange getUnassignedVertexRange(BuiltSectionMeshParts translucentMesh) { + VertexRange range = translucentMesh.getVertexRanges()[ModelQuadFacing.UNASSIGNED.ordinal()]; + + if (range == null) { + throw new IllegalStateException("No unassigned data in mesh"); + } + + return range; + } } From 3e652b109415385b846ae2049b6e81600e3550c0 Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 16 Sep 2023 21:22:52 +0200 Subject: [PATCH 045/256] fix static normal sorting --- .../render/chunk/gfni/GroupBuilder.java | 4 +- .../chunk/gfni/StaticNormalRelativeData.java | 45 +++++++++++++++++-- .../client/util/sorting/VertexSorters.java | 17 +++++++ 3 files changed, 61 insertions(+), 5 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java index 56c83d8d8e..8413681c50 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java @@ -58,7 +58,7 @@ public class GroupBuilder { private final ChunkSectionPos sectionPos; private int facePlaneCount = 0; - private int alignedNormalBitmap = 0; + int alignedNormalBitmap = 0; private Vector3f minBounds = new Vector3f(16, 16, 16); private Vector3f maxBounds = new Vector3f(0, 0, 0); @@ -337,7 +337,7 @@ public TranslucentData getTranslucentData(BuiltSectionMeshParts translucentMesh, } if (this.sortType == SortType.STATIC_NORMAL_RELATIVE) { - return StaticNormalRelativeData.fromMesh(translucentMesh, quads, sectionPos); + return StaticNormalRelativeData.fromMesh(translucentMesh, quads, sectionPos, this); } if (SodiumClientMod.options().performance.sortBehavior == SortBehavior.ONLY_DYNAMIC_ALL) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java index bb04b9c58d..1a2f8de41e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java @@ -12,6 +12,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; import me.jellysquid.mods.sodium.client.render.chunk.gfni.GroupBuilder.Quad; import me.jellysquid.mods.sodium.client.util.NativeBuffer; +import me.jellysquid.mods.sodium.client.util.sorting.MergeSort; import me.jellysquid.mods.sodium.client.util.sorting.VertexSorters; import net.minecraft.util.math.ChunkSectionPos; @@ -40,7 +41,26 @@ public SortType getSortType() { } } - static StaticNormalRelativeData fromMesh(BuiltSectionMeshParts translucentMesh, + private static StaticNormalRelativeData fromDoubleUnaligned(BuiltSectionMeshParts translucentMesh, + List quads, ChunkSectionPos sectionPos, GroupBuilder groupBuilder) { + VertexRange[] ranges = translucentMesh.getVertexRanges(); + float[] keys = new float[quads.size()]; + + for (int i = 0; i < quads.size(); i++) { + Quad quad = quads.get(i); + keys[i] = quad.center().dot(quad.normal()); + } + + var buffer = new NativeBuffer(TranslucentData.vertexCountToIndexBytes( + ranges[ModelQuadFacing.UNASSIGNED.ordinal()].vertexCount())); + IntBuffer bufferBuilder = buffer.getDirectBuffer().asIntBuffer(); + + TranslucentData.writeVertexIndexes(bufferBuilder, MergeSort.mergeSort(keys)); + + return new StaticNormalRelativeData(sectionPos, buffer, ranges); + } + + private static StaticNormalRelativeData fromAligned(BuiltSectionMeshParts translucentMesh, List quads, ChunkSectionPos sectionPos) { int vertexCount = 0; VertexRange[] ranges = translucentMesh.getVertexRanges(); @@ -55,9 +75,14 @@ static StaticNormalRelativeData fromMesh(BuiltSectionMeshParts translucentMesh, } } + // in this case there can only be up to one unaligned normal + Vector3f unalignedNormal = null; for (Quad quad : quads) { var direction = quad.facing().ordinal(); centers[direction][centerCounters[direction]++] = quad.center(); + if (direction == ModelQuadFacing.UNASSIGNED.ordinal()) { + unalignedNormal = new Vector3f(quad.normal()); + } } var buffer = new NativeBuffer(TranslucentData.vertexCountToIndexBytes(vertexCount)); @@ -65,11 +90,25 @@ static StaticNormalRelativeData fromMesh(BuiltSectionMeshParts translucentMesh, for (int i = 0; i < ModelQuadFacing.COUNT; i++) { if (ranges[i] != null) { - // TODO: there's no sorter for unaligned quads in normal relative mode - TranslucentData.writeVertexIndexes(bufferBuilder, SORTERS[i].sort(centers[i])); + VertexSorter sorter; + if (i == ModelQuadFacing.UNASSIGNED.ordinal()) { + sorter = VertexSorters.sortByNormalRelative(unalignedNormal); + } else { + sorter = SORTERS[i]; + } + TranslucentData.writeVertexIndexes(bufferBuilder, sorter.sort(centers[i])); } } return new StaticNormalRelativeData(sectionPos, buffer, ranges); } + + static StaticNormalRelativeData fromMesh(BuiltSectionMeshParts translucentMesh, + List quads, ChunkSectionPos sectionPos, GroupBuilder groupBuilder) { + if (groupBuilder.alignedNormalBitmap == 0) { + return fromDoubleUnaligned(translucentMesh, quads, sectionPos, groupBuilder); + } else { + return fromAligned(translucentMesh, quads, sectionPos); + } + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/VertexSorters.java b/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/VertexSorters.java index b4ba3e65d4..a2c6e5ce99 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/VertexSorters.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/VertexSorters.java @@ -30,6 +30,10 @@ public static VertexSorter sortByAxis(ModelQuadFacing facing) { } } + public static VertexSorter sortByNormalRelative(Vector3f normal) { + return new SortNormalRelative(normal); + } + private static class SortByDistance extends AbstractVertexSorter { private final Vector3f origin; @@ -61,6 +65,19 @@ protected float getKey(Vector3f position) { } } + private static class SortNormalRelative extends AbstractVertexSorter { + private final Vector3f normal; + + private SortNormalRelative(Vector3f normal) { + this.normal = normal; + } + + @Override + protected float getKey(Vector3f position) { + return this.normal.dot(position); + } + } + private static abstract class AbstractVertexSorter implements VertexSorter { @Override public final int[] sort(Vector3f[] positions) { From 9ee5dca33080319cdfb602c90ea5e6fb68c57fd7 Mon Sep 17 00:00:00 2001 From: douira Date: Sun, 17 Sep 2023 03:08:39 +0200 Subject: [PATCH 046/256] fix memory leaks --- .../client/render/chunk/RenderSection.java | 6 +++++ .../render/chunk/RenderSectionManager.java | 8 +++++-- .../chunk/compile/BuilderTaskOutput.java | 6 ++++- .../chunk/compile/ChunkBuildOutput.java | 4 ++-- .../render/chunk/compile/ChunkSortOutput.java | 19 +++++++++++++++ .../sodium/client/render/chunk/gfni/GFNI.java | 23 +++++++++++-------- .../render/chunk/gfni/GroupBuilder.java | 4 ++-- .../chunk/gfni/PresentTranslucentData.java | 15 ++++++++---- .../render/chunk/gfni/TranslucentData.java | 3 +++ 9 files changed, 66 insertions(+), 22 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java index 4bd86ee6cc..e566b5c3ce 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java @@ -118,6 +118,9 @@ public TranslucentData getTranslucentData() { } public void setTranslucentData(TranslucentData translucentData) { + if (this.translucentData != null && this.translucentData != translucentData) { + this.translucentData.delete(); + } this.translucentData = translucentData; } @@ -131,6 +134,9 @@ public void delete() { this.taskCancellationToken.setCancelled(); this.taskCancellationToken = null; } + if (this.translucentData != null) { + this.translucentData.delete(); + } this.clearRenderState(); this.disposed = true; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index dbd88ff423..600618c931 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -306,7 +306,7 @@ public void uploadChunks() { this.processChunkBuildResults(results); for (var result : results) { - result.delete(); + result.deleteAfterUpload(); } this.needsUpdate = true; @@ -456,7 +456,11 @@ public void destroy() { this.builder.shutdown(); // stop all the workers, and cancel any tasks for (var result : this.collectChunkBuildResults()) { - result.delete(); // delete resources for any pending tasks (including those that were cancelled) + result.deleteFully(); // delete resources for any pending tasks (including those that were cancelled) + } + + for (var section : sectionByPosition.values()) { + section.delete(); } this.sectionsWithGlobalEntities.clear(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/BuilderTaskOutput.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/BuilderTaskOutput.java index ecd1f8b0fe..604fcaba90 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/BuilderTaskOutput.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/BuilderTaskOutput.java @@ -11,6 +11,10 @@ public BuilderTaskOutput(RenderSection render, int buildTime) { this.submitTime = buildTime; } - public void delete() { + public void deleteFully() { + deleteAfterUpload(); + } + + public void deleteAfterUpload() { } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java index fd1b3dc15d..5f1bdf6ac2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java @@ -30,8 +30,8 @@ public BuiltSectionMeshParts getMesh(TerrainRenderPass pass) { } @Override - public void delete() { - super.delete(); + public void deleteAfterUpload() { + super.deleteAfterUpload(); for (BuiltSectionMeshParts data : this.meshes.values()) { data.getVertexData().free(); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java index bc56f68662..84fbbc6fbc 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java @@ -15,4 +15,23 @@ public ChunkSortOutput(RenderSection render, int buildTime, TranslucentData tran this.translucentData = translucentData; } + + + @Override + public void deleteAfterUpload() { + super.deleteAfterUpload(); + + // delete translucent data if it's not persisted for dynamic sorting + if (this.translucentData != null && !translucentData.getSortType().needsPlaneTrigger) { + this.translucentData.delete(); + } + } + + @Override + public void deleteFully() { + super.deleteFully(); + if (this.translucentData != null) { + this.translucentData.delete(); + } + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java index a08c34d601..c05adf5a29 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java @@ -26,6 +26,10 @@ * may result in many sections suddenly needing sorting when the camera moves. * Maybe it's better to schedule them to be sorted gradually even if not * visible, if there are idle threads. + * - problem: when there are two parallel planes made up of many quads each, + * sorting the whole thing from one perspective means the sorting is wrong when + * we look at it from another perspective. This happens because there is no + * trigger in the plane. Sorting as if the entire thing was one quad would fix it. * * @author douira */ @@ -51,7 +55,7 @@ public class GFNI { * normal lists' interval trees. */ private Consumer triggerSectionCallback; - + /** * A set of all the sections that were triggered the last time something was * triggered. @@ -103,15 +107,14 @@ public void triggerSections( this.triggeredNormalCount = newTriggeredNormalCount; } - // TODO: the collections for tracking sections are only used for debugging - int triggerCount = this.triggeredSections.size(); - if (triggerCount > 0) { - System.out.println("Triggered " + triggerCount + " sections"); - for (long section : this.triggeredSections) { - ChunkSectionPos sectionPos = ChunkSectionPos.from(section); - System.out.println(sectionPos.getX() + " " + sectionPos.getY() + " " + sectionPos.getZ()); - } - } + // int triggerCount = this.triggeredSections.size(); + // if (triggerCount > 0) { + // System.out.println("Triggered " + triggerCount + " sections"); + // for (long section : this.triggeredSections) { + // ChunkSectionPos sectionPos = ChunkSectionPos.from(section); + // System.out.println(sectionPos.getX() + " " + sectionPos.getY() + " " + sectionPos.getZ()); + // } + // } triggerSectionCallback = null; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java index 8413681c50..aacd5dee86 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java @@ -374,8 +374,8 @@ public TranslucentData getTranslucentData(BuiltSectionMeshParts translucentMesh, } } - System.out.println("topo sort hits: " + topoSortHits + ", cyclic graph hits: " + cyclicGraphHits - + ", unaligned dynamic hits: " + unalignedDynamicHits); + // System.out.println("topo sort hits: " + topoSortHits + ", cyclic graph hits: " + cyclicGraphHits + // + ", unaligned dynamic hits: " + unalignedDynamicHits); } // filter the sort type with the user setting and re-evaluate diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/PresentTranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/PresentTranslucentData.java index 069a2684f3..433208507c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/PresentTranslucentData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/PresentTranslucentData.java @@ -3,15 +3,20 @@ import me.jellysquid.mods.sodium.client.util.NativeBuffer; import net.minecraft.util.math.ChunkSectionPos; -/** - * TODO: take care of deleting the native buffers when the translucent data - * stored here is replaced. - */ public abstract class PresentTranslucentData extends TranslucentData { - public final NativeBuffer buffer; + public NativeBuffer buffer; public PresentTranslucentData(ChunkSectionPos sectionPos, NativeBuffer buffer) { super(sectionPos); this.buffer = buffer; } + + @Override + public void delete() { + super.delete(); + if (this.buffer != null) { + this.buffer.free(); + this.buffer = null; + } + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java index f284da4dda..18042222d9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java @@ -22,6 +22,9 @@ public TranslucentData(ChunkSectionPos sectionPos) { public abstract SortType getSortType(); + public void delete() { + } + public void sort(Vector3fc cameraPos) { // there should be no sort calls to data that doesn't need sorting throw new UnsupportedOperationException(); From 5bbc2359c115e3112245add24314a6291945b624 Mon Sep 17 00:00:00 2001 From: douira Date: Sun, 17 Sep 2023 03:30:21 +0200 Subject: [PATCH 047/256] javadoc --- .../mods/sodium/client/render/chunk/gfni/GroupBuilder.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java index aacd5dee86..5f086135c2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java @@ -431,6 +431,7 @@ private static void makeEdge(int[][] graph, BitArray leafQuads, int fromQuadInde * {@link #topoSortResult} and returns {@link SortType#STATIC_TOPO_ACYCLIC}. If * it fails to find a topo sort it returns {@link SortType#DYNAMIC_TOPO_CYCLIC}. * + * @param indexBuffer the buffer to write the topo sort result to * @return if the sort was successful */ private boolean topoSortAlignedAcyclic(IntBuffer indexBuffer) { From f23dd15a0d4c56cc30ea1e87b6e8bb3e75cfb1bd Mon Sep 17 00:00:00 2001 From: douira Date: Sun, 17 Sep 2023 03:47:34 +0200 Subject: [PATCH 048/256] fix issues with sort behaviors --- .../render/chunk/RenderSectionManager.java | 26 ++++++------------- .../render/chunk/gfni/GroupBuilder.java | 14 +++++----- 2 files changed, 16 insertions(+), 24 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index 600618c931..82c91a52eb 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -76,7 +76,7 @@ public class RenderSectionManager { private final int renderDistance; - private @Nullable GFNI gfni = null; + private final GFNI gfni; @NotNull private SortedRenderLists renderLists; @@ -95,9 +95,7 @@ public RenderSectionManager(ClientWorld world, int renderDistance, CommandList c this.chunkRenderer = new DefaultChunkRenderer(RenderDevice.INSTANCE, ChunkMeshFormats.COMPACT); this.world = world; - if (SodiumClientMod.options().performance.sortBehavior.needsPlaneTrigger) { - this.gfni = new GFNI(); - } + this.gfni = new GFNI(); this.builder = new ChunkBuilder(world, ChunkMeshFormats.COMPACT); @@ -222,9 +220,7 @@ public void onSectionRemoved(int x, int y, int z) { section.delete(); - if (this.gfni != null) { - this.gfni.removeSection(section.getTranslucentData(), chunkSectionLongPos); - } + this.gfni.removeSection(section.getTranslucentData(), chunkSectionLongPos); this.needsUpdate = true; } @@ -324,9 +320,7 @@ private void processChunkBuildResults(ArrayList results) { if (result instanceof ChunkSortOutput chunkSortOutput && chunkSortOutput.translucentData != null) { TranslucentData oldData = result.render.getTranslucentData(); result.render.setTranslucentData(chunkSortOutput.translucentData); - if (this.gfni != null) { - this.gfni.integrateTranslucentData(oldData, chunkSortOutput.translucentData); - } + this.gfni.integrateTranslucentData(oldData, chunkSortOutput.translucentData); } var job = result.render.getTaskCancellationToken(); @@ -433,11 +427,9 @@ public ChunkBuilderSortingTask createSortTask(RenderSection render, int frame) { public void processGFNIMovement( double lastCameraX, double lastCameraY, double lastCameraZ, double cameraX, double cameraY, double cameraZ) { - if (this.gfni != null) { - this.gfni.triggerSections(this::scheduleSort, - lastCameraX, lastCameraY, lastCameraZ, - cameraX, cameraY, cameraZ); - } + this.gfni.triggerSections(this::scheduleSort, + lastCameraX, lastCameraY, lastCameraZ, + cameraX, cameraY, cameraZ); } public void markGraphDirty() { @@ -613,9 +605,7 @@ public Collection getDebugStrings() { this.taskLists.get(ChunkUpdateType.INITIAL_BUILD).size()) ); - if (this.gfni != null) { - this.gfni.addDebugStrings(list); - } + this.gfni.addDebugStrings(list); return list; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java index 5f086135c2..3caa96e193 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java @@ -170,9 +170,10 @@ public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] verti } } - private static SortType filterSortType(SortType sortType) { + private static SortType filterSortType(SortType sortType, boolean allowDynamicInStatic) { SortBehavior sortBehavior = SodiumClientMod.options().performance.sortBehavior; - if (!sortBehavior.sortTypes.contains(sortType)) { + if (!sortBehavior.sortTypes.contains(sortType) + && !(allowDynamicInStatic && sortBehavior == SortBehavior.STATIC_TOPO_ACYCLIC)) { return SortType.NONE; } if (sortBehavior == SortBehavior.ONLY_DYNAMIC_ALL) { @@ -327,7 +328,7 @@ private SortType sortTypeHeuristic() { } public SortType estimateSortType() { - this.sortType = filterSortType(sortTypeHeuristic()); + this.sortType = filterSortType(sortTypeHeuristic(), true); return this.sortType; } @@ -374,12 +375,13 @@ public TranslucentData getTranslucentData(BuiltSectionMeshParts translucentMesh, } } - // System.out.println("topo sort hits: " + topoSortHits + ", cyclic graph hits: " + cyclicGraphHits - // + ", unaligned dynamic hits: " + unalignedDynamicHits); + // System.out.println("topo sort hits: " + topoSortHits + ", cyclic graph hits: + // " + cyclicGraphHits + // + ", unaligned dynamic hits: " + unalignedDynamicHits); } // filter the sort type with the user setting and re-evaluate - this.sortType = filterSortType(this.sortType); + this.sortType = filterSortType(this.sortType, false); if (this.sortType == SortType.NONE) { if (buffer != null) { From 699d3c7711849a920f45b13f364985b93229abb4 Mon Sep 17 00:00:00 2001 From: douira Date: Sun, 17 Sep 2023 14:30:06 +0200 Subject: [PATCH 049/256] actually JiJ the interval tree dependency --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index b73e6e3bc6..6ec8a2c906 100644 --- a/build.gradle +++ b/build.gradle @@ -80,7 +80,7 @@ dependencies { mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" - implementation "com.lodborg:interval-tree:1.0.0" + modIncludeImplementation "com.lodborg:interval-tree:1.0.0" // Fabric API modIncludeImplementation(fabricApi.module("fabric-api-base", project.fabric_version)) From 54d4be7cbd7f17038016ab4f4eaf12a9a9ffcf67 Mon Sep 17 00:00:00 2001 From: douira Date: Tue, 19 Sep 2023 23:58:13 +0200 Subject: [PATCH 050/256] rename camera pos parameter to clarify absolute --- .../chunk/compile/tasks/ChunkBuilderSortingTask.java | 4 ++-- .../render/chunk/compile/tasks/ChunkBuilderTask.java | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java index d08b876a19..795933bac2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java @@ -8,8 +8,8 @@ import me.jellysquid.mods.sodium.client.util.task.CancellationToken; public class ChunkBuilderSortingTask extends ChunkBuilderTask { - public ChunkBuilderSortingTask(RenderSection render, int frame, Vector3fc cameraPos) { - super(render, frame, cameraPos); + public ChunkBuilderSortingTask(RenderSection render, int frame, Vector3fc absoluteCameraPos) { + super(render, frame, absoluteCameraPos); } @Override diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderTask.java index e8d4c9a239..9a0116d4ee 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderTask.java @@ -23,13 +23,13 @@ public abstract class ChunkBuilderTask { protected final int submitTime; protected final Vector3fc cameraPos; - public ChunkBuilderTask(RenderSection render, int time, Vector3fc cameraPos) { + public ChunkBuilderTask(RenderSection render, int time, Vector3fc absoluteCameraPos) { this.render = render; this.submitTime = time; this.cameraPos = new Vector3f( - cameraPos.x() - (float) render.getOriginX(), - cameraPos.y() - (float) render.getOriginY(), - cameraPos.z() - (float) render.getOriginZ()); + absoluteCameraPos.x() - (float) render.getOriginX(), + absoluteCameraPos.y() - (float) render.getOriginY(), + absoluteCameraPos.z() - (float) render.getOriginZ()); } /** From 2aa2bf136945937a8bb849a1cbf88c8c6a2e4c29 Mon Sep 17 00:00:00 2001 From: douira Date: Wed, 20 Sep 2023 01:23:16 +0200 Subject: [PATCH 051/256] fix quads being interpreted in the wrong order, add better dynamic sorting to avoid ice effect, cleanup and rename some things --- .../tasks/ChunkBuilderMeshingTask.java | 2 +- .../client/render/chunk/gfni/DynamicData.java | 120 ++++++++++++------ .../render/chunk/gfni/GroupBuilder.java | 77 +++++++---- .../render/chunk/gfni/MixedDirectionData.java | 2 +- .../chunk/gfni/PresentTranslucentData.java | 2 +- .../chunk/gfni/StaticNormalRelativeData.java | 35 ++--- .../chunk/gfni/StaticTopoAcyclicData.java | 2 +- .../render/chunk/gfni/TranslucentData.java | 2 +- 8 files changed, 157 insertions(+), 85 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java index aa066f3158..8de94ff7a1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java @@ -137,7 +137,7 @@ public ChunkBuildOutput execute(ChunkBuildContext buildContext, CancellationToke throw fillCrashInfo(CrashReport.create(ex, "Encountered exception while building chunk meshes"), slice, blockPos); } - SortType sortType = groupBuilder.estimateSortType(); + SortType sortType = groupBuilder.finishRendering(); Map meshes = new Reference2ReferenceOpenHashMap<>(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java index 89d05fe7b7..7486113a49 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java @@ -1,30 +1,35 @@ package me.jellysquid.mods.sodium.client.render.chunk.gfni; -import java.util.List; - -import org.joml.Vector3f; import org.joml.Vector3fc; import it.unimi.dsi.fastutil.ints.Int2ReferenceLinkedOpenHashMap; +import it.unimi.dsi.fastutil.ints.IntArrays; import me.jellysquid.mods.sodium.client.gl.util.VertexRange; -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; import me.jellysquid.mods.sodium.client.render.chunk.gfni.GroupBuilder.Quad; import me.jellysquid.mods.sodium.client.util.NativeBuffer; -import me.jellysquid.mods.sodium.client.util.sorting.VertexSorters; +import me.jellysquid.mods.sodium.client.util.collections.BitArray; import net.minecraft.util.math.ChunkSectionPos; +/** + * TODO: the sort algorithm uses a heuristic to avoid issues arising from + * parallel planes of many quads. (see below) This heuristic is imperfect and + * can cause some artifacts. A better approach would be a visible-only + * topological sort. That's hard though, because it needs to handle arbitrary + * amounts of (potentially unaligned) quads and run on every trigger event. + * Possibly re-use of (incrementally constructed) graph structures is necessary? + */ public class DynamicData extends MixedDirectionData { - public final Vector3f[] centers; - private AccumulationGroup[] axisAlignedDistances; - private Int2ReferenceLinkedOpenHashMap unalignedDistances; + private final Quad[] quads; + private final AccumulationGroup[] axisAlignedDistances; + private final Int2ReferenceLinkedOpenHashMap unalignedDistances; - public DynamicData(ChunkSectionPos sectionPos, - NativeBuffer buffer, VertexRange range, Vector3f[] centers, + DynamicData(ChunkSectionPos sectionPos, + NativeBuffer buffer, VertexRange range, Quad[] quads, AccumulationGroup[] axisAlignedDistances, Int2ReferenceLinkedOpenHashMap unalignedDistances) { super(sectionPos, buffer, range); - this.centers = centers; + this.quads = quads; this.axisAlignedDistances = axisAlignedDistances; this.unalignedDistances = unalignedDistances; } @@ -57,49 +62,86 @@ public Int2ReferenceLinkedOpenHashMap getUnalignedDistances() return this.unalignedDistances; } - public void clearTriggerData() { - this.axisAlignedDistances = null; - this.unalignedDistances = null; + private static float halfspace(Vector3fc planeAnchor, Vector3fc planeNormal, Vector3fc point) { + return (point.x() - planeAnchor.x()) * planeNormal.x() + + (point.y() - planeAnchor.y()) * planeNormal.y() + + (point.z() - planeAnchor.z()) * planeNormal.z(); } @Override public void sort(Vector3fc cameraPos) { + int[] indexes = new int[this.quads.length]; + BitArray visible = new BitArray(this.quads.length); + float[] centerDist = new float[this.quads.length]; + for (int i = 0; i < indexes.length; i++) { + indexes[i] = i; + Quad quad = this.quads[i]; + if (halfspace(quad.center(), quad.normal(), cameraPos) > 0) { + visible.set(i); + centerDist[i] = cameraPos.distanceSquared(this.quads[i].center()); + } + } + + IntArrays.quickSort(indexes, (a, b) -> { + // returning -1 results in the ordering a, b, returning 1 produces b, a + + boolean aVisible = visible.get(a); + boolean bVisible = visible.get(b); + + // compare only pairs where both are visible + if (aVisible && bVisible) { + var quadA = this.quads[a]; + var quadB = this.quads[b]; + var normalA = quadA.normal(); + var normalB = quadB.normal(); + + // this is a heuristic that attempts to reduce the sorting mistakes that happen + // when two parallel planes made up of many quads are seen from different + // angles. For quads with equal normals it sorts them only by their + // normal-relative distance to the camera. This eliminates some of wrong sorting + // that happens in tangent directions. + if (normalA.equals(normalB)) { + var centerA = quadA.center(); + var centerB = quadB.center(); + var cameraDistance = normalB.dot(cameraPos); + var result = Float.compare(Math.abs(cameraDistance - normalB.dot(centerB)), + Math.abs(cameraDistance - normalB.dot(centerA))); + if (result != 0) { + return result; + } + } + + return Float.compare(centerDist[b], centerDist[a]); + + } + + // put invisible quads last + if (aVisible) { + return -1; + } + if (bVisible) { + return 1; + } + + return 0; + }); + var intBuffer = this.buffer.getDirectBuffer().asIntBuffer(); - TranslucentData.writeVertexIndexes(intBuffer, - VertexSorters.sortByDistance(new Vector3f(cameraPos)).sort(this.centers)); + TranslucentData.writeVertexIndexes(intBuffer, indexes); } static DynamicData fromMesh(BuiltSectionMeshParts translucentMesh, NativeBuffer reuseBuffer, - Vector3fc cameraPos, List quads, ChunkSectionPos sectionPos, GroupBuilder groupBuilder) { + Vector3fc cameraPos, Quad[] quads, ChunkSectionPos sectionPos, GroupBuilder groupBuilder) { VertexRange range = TranslucentData.getUnassignedVertexRange(translucentMesh); - int[] centerCounters = new int[ModelQuadFacing.COUNT]; - - for (Quad quad : quads) { - centerCounters[quad.facing().ordinal()]++; - } - - // do a prefix sum to determine the offsets of where to write the centers - int quadCount = 0; - for (int i = 0; i < ModelQuadFacing.COUNT; i++) { - var newCount = centerCounters[i] + quadCount; - centerCounters[i] = quadCount; - quadCount = newCount; - } if (reuseBuffer == null) { reuseBuffer = new NativeBuffer( - TranslucentData.vertexCountToIndexBytes(quadCount * TranslucentData.VERTICES_PER_QUAD)); - } - - Vector3f[] centers = new Vector3f[quadCount]; - - for (int i = 0; i < quads.size(); i++) { - Quad quad = quads.get(i); - centers[centerCounters[quad.facing().ordinal()]++] = quad.center(); + TranslucentData.vertexCountToIndexBytes(quads.length * TranslucentData.VERTICES_PER_QUAD)); } var dynamicData = new DynamicData(sectionPos, - reuseBuffer, range, centers, groupBuilder.axisAlignedDistances, groupBuilder.unalignedDistances); + reuseBuffer, range, quads, + groupBuilder.axisAlignedDistances, groupBuilder.unalignedDistances); dynamicData.sort(cameraPos); return dynamicData; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java index 3caa96e193..8c524e34ae 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java @@ -1,6 +1,7 @@ package me.jellysquid.mods.sodium.client.render.chunk.gfni; import java.nio.IntBuffer; +import java.util.List; import org.joml.Vector3f; import org.joml.Vector3fc; @@ -64,10 +65,9 @@ public class GroupBuilder { private int unalignedQuadCount = 0; - /** - * List of translucent quads being rendered. - */ - private final ReferenceArrayList quads = new ReferenceArrayList<>(); + @SuppressWarnings("unchecked") + private ReferenceArrayList[] quadLists = new ReferenceArrayList[ModelQuadFacing.COUNT]; + private Quad[] quads; private SortType sortType; @@ -122,6 +122,12 @@ public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] verti // TODO: some of these things should probably only be computed on demand, and an // allocation of a Quad object should be avoided AccumulationGroup accGroup; + var quadList = this.quadLists[facing.ordinal()]; + if (quadList == null) { + quadList = new ReferenceArrayList<>(); + this.quadLists[facing.ordinal()] = quadList; + } + if (facing == ModelQuadFacing.UNASSIGNED) { int normalX = quadView.getGFNINormX(); int normalY = quadView.getGFNINormY(); @@ -145,7 +151,8 @@ public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] verti accGroup = new AccumulationGroup(sectionPos, normal, normalKey); this.unalignedDistances.put(normalKey, accGroup); } - this.quads.add(new Quad(facing, accGroup.normal, center, extents)); + + quadList.add(new Quad(facing, accGroup.normal, center, extents)); this.unalignedQuadCount++; } else { if (this.axisAlignedDistances == null) { @@ -161,7 +168,7 @@ public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] verti this.alignedNormalBitmap |= 1 << quadDirection; } - this.quads.add(new Quad(facing, accGroup.normal, center, extents)); + quadList.add(new Quad(facing, accGroup.normal, center, extents)); } var firstVertex = vertices[0]; @@ -320,14 +327,32 @@ private SortType sortTypeHeuristic() { // heuristically determine if a topo sort should be attempted, if the attempt // fails the sort type is downgraded to DYNAMIC_ALL. If there are no cycles, // it's upgraded to acyclic. - if (this.unalignedQuadCount <= 2 && this.quads.size() <= 400) { + if (this.unalignedQuadCount <= 2 && this.quads.length <= 400) { return SortType.DYNAMIC_TOPO_CYCLIC; } return SortType.DYNAMIC_ALL; } - public SortType estimateSortType() { + public SortType finishRendering() { + // combine the quads into one array + int totalQuadCount = 0; + for (var quadList : this.quadLists) { + if (quadList != null) { + totalQuadCount += quadList.size(); + } + } + this.quads = new Quad[totalQuadCount]; + int quadIndex = 0; + for (var quadList : this.quadLists) { + if (quadList != null) { + for (var quad : quadList) { + this.quads[quadIndex++] = quad; + } + } + } + this.quadLists = null; + this.sortType = filterSortType(sortTypeHeuristic(), true); return this.sortType; } @@ -338,11 +363,11 @@ public TranslucentData getTranslucentData(BuiltSectionMeshParts translucentMesh, } if (this.sortType == SortType.STATIC_NORMAL_RELATIVE) { - return StaticNormalRelativeData.fromMesh(translucentMesh, quads, sectionPos, this); + return StaticNormalRelativeData.fromMesh(translucentMesh, this.quads, sectionPos, this); } if (SodiumClientMod.options().performance.sortBehavior == SortBehavior.ONLY_DYNAMIC_ALL) { - return DynamicData.fromMesh(translucentMesh, null, cameraPos, quads, sectionPos, this); + return DynamicData.fromMesh(translucentMesh, null, cameraPos, this.quads, sectionPos, this); } // from this point on we know the estimated sort type requires direction mixing @@ -437,7 +462,7 @@ private static void makeEdge(int[][] graph, BitArray leafQuads, int fromQuadInde * @return if the sort was successful */ private boolean topoSortAlignedAcyclic(IntBuffer indexBuffer) { - var totalQuadCount = this.quads.size(); + /** * The translucent quad visibility graph is stored as an array for each quad. @@ -447,23 +472,23 @@ private boolean topoSortAlignedAcyclic(IntBuffer indexBuffer) { * * The last entry stores the number of *outgoing* edges. */ - int[][] graph = new int[totalQuadCount][ModelQuadFacing.DIRECTIONS + 1]; + int[][] graph = new int[this.quads.length][ModelQuadFacing.DIRECTIONS + 1]; // the set of quads that have no outgoing edges - BitArray leafQuads = new BitArray(totalQuadCount); - leafQuads.set(0, totalQuadCount); + BitArray leafQuads = new BitArray(this.quads.length); + leafQuads.set(0, this.quads.length); - for (int i = 0; i < totalQuadCount; i++) { + for (int i = 0; i < this.quads.length; i++) { for (int j = 0; j < ModelQuadFacing.DIRECTIONS; j++) { graph[i][j] = -1; } } // the stash of quads that have not yet been visible to the scanned quads - BitArray stashedOrthoQuads = new BitArray(totalQuadCount); + BitArray stashedOrthoQuads = new BitArray(this.quads.length); // keep around the allocation of the keys array - float[] keys = new float[totalQuadCount]; + float[] keys = new float[this.quads.length]; // to build the graph, perform scans for each direction for (int direction = 0; direction < ModelQuadFacing.DIRECTIONS; direction++) { @@ -473,10 +498,10 @@ private boolean topoSortAlignedAcyclic(IntBuffer indexBuffer) { int sign = facing.getSign(); // generate keys for this direction - for (int i = 0; i < totalQuadCount; i++) { + for (int i = 0; i < this.quads.length; i++) { // get the extent in the opposite direction of the scan because quads that are // visible from a scanning quad should be before it - Quad quad = this.quads.get(i); + Quad quad = this.quads[i]; keys[i] = quad.extents[oppositeDirection] * sign * -1; } @@ -489,9 +514,9 @@ private boolean topoSortAlignedAcyclic(IntBuffer indexBuffer) { // perform a scan by going through the sorted quads and making edges between the // scanning quads and the quads that precede them in the sort order stashedOrthoQuads.unset(); - for (int quadIndexPos = 0; quadIndexPos < totalQuadCount; quadIndexPos++) { + for (int quadIndexPos = 0; quadIndexPos < this.quads.length; quadIndexPos++) { int quadIndex = sortedQuads[quadIndexPos]; - Quad quad = this.quads.get(quadIndex); + Quad quad = this.quads[quadIndex]; if (quad.facing != facing) { continue; } @@ -505,7 +530,7 @@ private boolean topoSortAlignedAcyclic(IntBuffer indexBuffer) { for (int stashedQuadIndex = stashedOrthoQuads .nextSetBit(0); stashedQuadIndex != -1; stashedQuadIndex = stashedOrthoQuads .nextSetBit(stashedQuadIndex + 1)) { - Quad stashedOrthoQuad = this.quads.get(stashedQuadIndex); + Quad stashedOrthoQuad = this.quads[stashedQuadIndex]; // if it's visible through the current quad, unstash and connect if (orthogonalQuadVisible(quad, stashedOrthoQuad)) { @@ -518,7 +543,7 @@ private boolean topoSortAlignedAcyclic(IntBuffer indexBuffer) { // initially increment to skip the last scan quad. for (++lastScanQuadPos; lastScanQuadPos < quadIndexPos; lastScanQuadPos++) { int otherQuadIndex = sortedQuads[lastScanQuadPos]; - Quad otherQuad = this.quads.get(otherQuadIndex); + Quad otherQuad = this.quads[otherQuadIndex]; // discard quads that face in the opposite direction, they are never visible if (otherQuad.facing == oppositeFacing) { @@ -548,7 +573,10 @@ private boolean topoSortAlignedAcyclic(IntBuffer indexBuffer) { // iterate through the set of quads with no outgoing edges until there are none // left. - for (int topoSortPos = 0; topoSortPos < totalQuadCount; topoSortPos++) { + // TODO: debug topo sort with the arrangement of blocks I wrote the indices down + // in miro + List topoSortResult = new ReferenceArrayList<>(); + for (int topoSortPos = 0; topoSortPos < this.quads.length; topoSortPos++) { int nextLeafQuadIndex = leafQuads.nextSetBit(0); // if there are no leaf quads but not yet all quads have been processed, @@ -563,6 +591,7 @@ private boolean topoSortAlignedAcyclic(IntBuffer indexBuffer) { // add it to the topo sort result TranslucentData.putQuadVertexIndexes(indexBuffer, nextLeafQuadIndex); + topoSortResult.add(nextLeafQuadIndex); // remove the edges to this quad and mark them as leaves if that was the last // outgoing edge they had diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/MixedDirectionData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/MixedDirectionData.java index 342581fd35..7417acfad8 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/MixedDirectionData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/MixedDirectionData.java @@ -7,7 +7,7 @@ public abstract class MixedDirectionData extends PresentTranslucentData { public final VertexRange range; - public MixedDirectionData(ChunkSectionPos sectionPos, NativeBuffer buffer, VertexRange range) { + MixedDirectionData(ChunkSectionPos sectionPos, NativeBuffer buffer, VertexRange range) { super(sectionPos, buffer); this.range = range; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/PresentTranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/PresentTranslucentData.java index 433208507c..2493c60958 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/PresentTranslucentData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/PresentTranslucentData.java @@ -6,7 +6,7 @@ public abstract class PresentTranslucentData extends TranslucentData { public NativeBuffer buffer; - public PresentTranslucentData(ChunkSectionPos sectionPos, NativeBuffer buffer) { + PresentTranslucentData(ChunkSectionPos sectionPos, NativeBuffer buffer) { super(sectionPos); this.buffer = buffer; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java index 1a2f8de41e..0e06369b71 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java @@ -1,7 +1,6 @@ package me.jellysquid.mods.sodium.client.render.chunk.gfni; import java.nio.IntBuffer; -import java.util.List; import org.joml.Vector3f; @@ -42,12 +41,12 @@ public SortType getSortType() { } private static StaticNormalRelativeData fromDoubleUnaligned(BuiltSectionMeshParts translucentMesh, - List quads, ChunkSectionPos sectionPos, GroupBuilder groupBuilder) { + Quad[] quads, ChunkSectionPos sectionPos, GroupBuilder groupBuilder) { VertexRange[] ranges = translucentMesh.getVertexRanges(); - float[] keys = new float[quads.size()]; + float[] keys = new float[quads.length]; - for (int i = 0; i < quads.size(); i++) { - Quad quad = quads.get(i); + for (int i = 0; i < quads.length; i++) { + Quad quad = quads[i]; keys[i] = quad.center().dot(quad.normal()); } @@ -61,33 +60,35 @@ private static StaticNormalRelativeData fromDoubleUnaligned(BuiltSectionMeshPart } private static StaticNormalRelativeData fromAligned(BuiltSectionMeshParts translucentMesh, - List quads, ChunkSectionPos sectionPos) { - int vertexCount = 0; + Quad[] quads, ChunkSectionPos sectionPos) { VertexRange[] ranges = translucentMesh.getVertexRanges(); Vector3f[][] centers = new Vector3f[ModelQuadFacing.COUNT][]; - int[] centerCounters = new int[ModelQuadFacing.COUNT]; for (int i = 0; i < ModelQuadFacing.COUNT; i++) { VertexRange range = ranges[i]; if (range != null) { - vertexCount += range.vertexCount(); centers[i] = new Vector3f[range.vertexCount() / TranslucentData.VERTICES_PER_QUAD]; } } - // in this case there can only be up to one unaligned normal - Vector3f unalignedNormal = null; + int centerCounter = 0; for (Quad quad : quads) { - var direction = quad.facing().ordinal(); - centers[direction][centerCounters[direction]++] = quad.center(); - if (direction == ModelQuadFacing.UNASSIGNED.ordinal()) { - unalignedNormal = new Vector3f(quad.normal()); + var directionCenters = centers[quad.facing().ordinal()]; + directionCenters[centerCounter++] = quad.center(); + + if (centerCounter == directionCenters.length) { + centerCounter = 0; } } - var buffer = new NativeBuffer(TranslucentData.vertexCountToIndexBytes(vertexCount)); + var buffer = new NativeBuffer( + TranslucentData.vertexCountToIndexBytes(quads.length * TranslucentData.VERTICES_PER_QUAD)); IntBuffer bufferBuilder = buffer.getDirectBuffer().asIntBuffer(); + // in this case there can only be up to one unaligned normal. + // since the quads are sorted by facing, it will be at the end if it exists + Vector3f unalignedNormal = new Vector3f(quads[quads.length - 1].normal()); + for (int i = 0; i < ModelQuadFacing.COUNT; i++) { if (ranges[i] != null) { VertexSorter sorter; @@ -104,7 +105,7 @@ private static StaticNormalRelativeData fromAligned(BuiltSectionMeshParts transl } static StaticNormalRelativeData fromMesh(BuiltSectionMeshParts translucentMesh, - List quads, ChunkSectionPos sectionPos, GroupBuilder groupBuilder) { + Quad[] quads, ChunkSectionPos sectionPos, GroupBuilder groupBuilder) { if (groupBuilder.alignedNormalBitmap == 0) { return fromDoubleUnaligned(translucentMesh, quads, sectionPos, groupBuilder); } else { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java index 0048a00a18..5f17caf55e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java @@ -6,7 +6,7 @@ import net.minecraft.util.math.ChunkSectionPos; public class StaticTopoAcyclicData extends MixedDirectionData { - public StaticTopoAcyclicData(ChunkSectionPos sectionPos, NativeBuffer buffer, VertexRange range) { + StaticTopoAcyclicData(ChunkSectionPos sectionPos, NativeBuffer buffer, VertexRange range) { super(sectionPos, buffer, range); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java index 18042222d9..f8cfdbd5dd 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java @@ -16,7 +16,7 @@ public abstract class TranslucentData { public final ChunkSectionPos sectionPos; - public TranslucentData(ChunkSectionPos sectionPos) { + TranslucentData(ChunkSectionPos sectionPos) { this.sectionPos = sectionPos; } From 7b8f7a1cb7c2e7edb2b5e345cc7a23cd5c42a96f Mon Sep 17 00:00:00 2001 From: douira Date: Wed, 20 Sep 2023 02:16:16 +0200 Subject: [PATCH 052/256] use quad count directly when determining buffer size --- .../mods/sodium/client/render/chunk/gfni/DynamicData.java | 3 +-- .../client/render/chunk/gfni/StaticNormalRelativeData.java | 3 +-- .../mods/sodium/client/render/chunk/gfni/TranslucentData.java | 4 ++++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java index 7486113a49..b978fc13c8 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java @@ -135,8 +135,7 @@ static DynamicData fromMesh(BuiltSectionMeshParts translucentMesh, NativeBuffer VertexRange range = TranslucentData.getUnassignedVertexRange(translucentMesh); if (reuseBuffer == null) { - reuseBuffer = new NativeBuffer( - TranslucentData.vertexCountToIndexBytes(quads.length * TranslucentData.VERTICES_PER_QUAD)); + reuseBuffer = new NativeBuffer(TranslucentData.quadCountToIndexBytes(quads.length)); } var dynamicData = new DynamicData(sectionPos, diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java index 0e06369b71..2f3897646c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java @@ -81,8 +81,7 @@ private static StaticNormalRelativeData fromAligned(BuiltSectionMeshParts transl } } - var buffer = new NativeBuffer( - TranslucentData.vertexCountToIndexBytes(quads.length * TranslucentData.VERTICES_PER_QUAD)); + var buffer = new NativeBuffer(TranslucentData.quadCountToIndexBytes(quads.length)); IntBuffer bufferBuilder = buffer.getDirectBuffer().asIntBuffer(); // in this case there can only be up to one unaligned normal. diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java index f8cfdbd5dd..8917a9bdb4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java @@ -35,6 +35,10 @@ static int vertexCountToIndexBytes(int vertexCount) { return vertexCount / VERTICES_PER_QUAD * INDICES_PER_QUAD * BYTES_PER_INDEX; } + static int quadCountToIndexBytes(int quadCount) { + return quadCount * INDICES_PER_QUAD * BYTES_PER_INDEX; + } + static void putQuadVertexIndexes(IntBuffer intBuffer, int quadIndex) { int vertexOffset = quadIndex * VERTICES_PER_QUAD; From 48d2682ffb692fa7095c66f0b3d752cba90070ec Mon Sep 17 00:00:00 2001 From: douira Date: Wed, 20 Sep 2023 02:33:03 +0200 Subject: [PATCH 053/256] fix normal relative index buffer being wrong with offset of vertex start, thanks to breadloaf for helping with the bug reproduction --- .../render/chunk/gfni/StaticNormalRelativeData.java | 9 +++++++-- .../sodium/client/render/chunk/gfni/TranslucentData.java | 6 ++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java index 2f3897646c..571ca9ab36 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java @@ -89,14 +89,19 @@ private static StaticNormalRelativeData fromAligned(BuiltSectionMeshParts transl Vector3f unalignedNormal = new Vector3f(quads[quads.length - 1].normal()); for (int i = 0; i < ModelQuadFacing.COUNT; i++) { - if (ranges[i] != null) { + var range = ranges[i]; + if (range != null) { VertexSorter sorter; if (i == ModelQuadFacing.UNASSIGNED.ordinal()) { sorter = VertexSorters.sortByNormalRelative(unalignedNormal); } else { sorter = SORTERS[i]; } - TranslucentData.writeVertexIndexes(bufferBuilder, sorter.sort(centers[i])); + + // add the vertex start converted to quads to the offset to get the real quad + // index and not just the index local to the direction's set of quads + TranslucentData.writeVertexIndexesOffset(bufferBuilder, sorter.sort(centers[i]), + range.vertexStart() / TranslucentData.VERTICES_PER_QUAD); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java index 8917a9bdb4..bb65ab81c5 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java @@ -57,6 +57,12 @@ static void writeVertexIndexes(IntBuffer intBuffer, int[] quadIndexes) { } } + static void writeVertexIndexesOffset(IntBuffer intBuffer, int[] quadIndexes, int offset) { + for (int quadIndexPos = 0; quadIndexPos < quadIndexes.length; quadIndexPos++) { + putQuadVertexIndexes(intBuffer, quadIndexes[quadIndexPos] + offset); + } + } + static VertexRange getUnassignedVertexRange(BuiltSectionMeshParts translucentMesh) { VertexRange range = translucentMesh.getVertexRanges()[ModelQuadFacing.UNASSIGNED.ordinal()]; From 5885875a114c754e6ce4474426c8b3edb036bf65 Mon Sep 17 00:00:00 2001 From: douira Date: Thu, 21 Sep 2023 03:08:43 +0200 Subject: [PATCH 054/256] make translucency sorting options more user friendly --- .../sodium/client/gui/SodiumGameOptions.java | 12 +++---- .../render/chunk/DefaultChunkRenderer.java | 1 + .../chunk/gfni/DynamicTopoCyclicData.java | 5 ++- .../render/chunk/gfni/GroupBuilder.java | 34 +++++++------------ .../client/render/chunk/gfni/SortType.java | 2 +- .../resources/assets/sodium/lang/en_us.json | 9 ++--- 6 files changed, 25 insertions(+), 38 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java index e509565d3a..ca520449b2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java @@ -49,17 +49,13 @@ public static class PerformanceSettings { public boolean useBlockFaceCulling = true; public boolean useNoErrorGLContext = true; - public SortBehavior sortBehavior = SortBehavior.DYNAMIC_ALL; + public SortBehavior sortBehavior = SortBehavior.DYNAMIC; } public enum SortBehavior implements TextProvider { - ONLY_TRIVIAL("options.sort_behavior.only_trivial", Set.of(SortType.NONE)), - STATIC_NORMAL_RELATIVE("options.sort_behavior.static_normal_relative", getUpTo(SortType.STATIC_NORMAL_RELATIVE)), - STATIC_TOPO_ACYCLIC("options.sort_behavior.static_topo_acyclic", getUpTo(SortType.STATIC_TOPO_ACYCLIC)), - // TODO: enable when implemented - // DYNAMIC_TOPO_CYCLIC("options.sort_behavior.dynamic_topo_cyclic", getUpTo(SortType.DYNAMIC_TOPO_CYCLIC)), - DYNAMIC_ALL("options.sort_behavior.dynamic_all", getUpTo(SortType.DYNAMIC_ALL)), - ONLY_DYNAMIC_ALL("options.sort_behavior.only_dynamic_all", Set.of(SortType.DYNAMIC_ALL)); + NONE("options.off", Set.of(SortType.NONE)), + STATIC("options.clouds.fast", getUpTo(SortType.STATIC_TOPO_ACYCLIC)), + DYNAMIC("options.clouds.fancy", getUpTo(SortType.DYNAMIC_ALL)); private final Text name; public final Set sortTypes; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java index 83230b8926..1c736a7e59 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java @@ -49,6 +49,7 @@ public void render(ChunkRenderMatrices matrices, CameraTransform camera) { super.begin(renderPass); + // TODO: also disable this if there is only NONE-type sorting or no translucent geometry in the region boolean isTranslucent = renderPass == DefaultTerrainRenderPasses.TRANSLUCENT && SodiumClientMod.options().performance.sortBehavior.needsIndexBuffer; boolean useBlockFaceCulling = SodiumClientMod.options().performance.useBlockFaceCulling; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicTopoCyclicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicTopoCyclicData.java index b969690157..a0acd7e2c6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicTopoCyclicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicTopoCyclicData.java @@ -7,6 +7,9 @@ import me.jellysquid.mods.sodium.client.util.NativeBuffer; import net.minecraft.util.math.ChunkSectionPos; +/** + * TODO: implement + */ public class DynamicTopoCyclicData extends PresentTranslucentData { public final ReferenceArrayList orders; @@ -21,6 +24,6 @@ public DynamicTopoCyclicData(ChunkSectionPos sectionPos, @Override public SortType getSortType() { - return SortType.DYNAMIC_TOPO_CYCLIC; + throw new UnsupportedOperationException(); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java index 8c524e34ae..f179249bb5 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java @@ -177,15 +177,22 @@ public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] verti } } + /** + * Filters the given sort type to fit within the selected sorting mode. If it + * doesn't match, then it's set to the NONE sort type. + * + * @param sortType the sort type to filter + * @param allowDynamicInStatic if true, then the DYNAMIC_ALL is allowed even if + * the sort behavior is STATIC. This is to allow a + * topo sort to be attempted even if the heuristic + * can't determine that it's acyclic. + */ private static SortType filterSortType(SortType sortType, boolean allowDynamicInStatic) { SortBehavior sortBehavior = SodiumClientMod.options().performance.sortBehavior; if (!sortBehavior.sortTypes.contains(sortType) - && !(allowDynamicInStatic && sortBehavior == SortBehavior.STATIC_TOPO_ACYCLIC)) { + && !(allowDynamicInStatic && sortBehavior == SortBehavior.STATIC)) { return SortType.NONE; } - if (sortBehavior == SortBehavior.ONLY_DYNAMIC_ALL) { - return SortType.DYNAMIC_ALL; - } return sortType; } @@ -237,12 +244,9 @@ private static SortType filterSortType(SortType sortType, boolean allowDynamicIn */ private SortType sortTypeHeuristic() { SortBehavior sortBehavior = SodiumClientMod.options().performance.sortBehavior; - if (sortBehavior == SortBehavior.ONLY_DYNAMIC_ALL) { - return SortType.DYNAMIC_ALL; - } // special case A - if (sortBehavior == SortBehavior.ONLY_TRIVIAL || this.facePlaneCount <= 1) { + if (sortBehavior == SortBehavior.NONE || this.facePlaneCount <= 1) { return SortType.NONE; } @@ -324,13 +328,6 @@ private SortType sortTypeHeuristic() { return SortType.STATIC_TOPO_ACYCLIC; } - // heuristically determine if a topo sort should be attempted, if the attempt - // fails the sort type is downgraded to DYNAMIC_ALL. If there are no cycles, - // it's upgraded to acyclic. - if (this.unalignedQuadCount <= 2 && this.quads.length <= 400) { - return SortType.DYNAMIC_TOPO_CYCLIC; - } - return SortType.DYNAMIC_ALL; } @@ -366,15 +363,11 @@ public TranslucentData getTranslucentData(BuiltSectionMeshParts translucentMesh, return StaticNormalRelativeData.fromMesh(translucentMesh, this.quads, sectionPos, this); } - if (SodiumClientMod.options().performance.sortBehavior == SortBehavior.ONLY_DYNAMIC_ALL) { - return DynamicData.fromMesh(translucentMesh, null, cameraPos, this.quads, sectionPos, this); - } - // from this point on we know the estimated sort type requires direction mixing // (no backface culling) and all vertices are in the UNASSIGNED direction. NativeBuffer buffer = null; if (this.sortType == SortType.STATIC_TOPO_ACYCLIC - || this.sortType == SortType.DYNAMIC_TOPO_CYCLIC + // || this.sortType == SortType.DYNAMIC_TOPO_CYCLIC || this.sortType == SortType.DYNAMIC_ALL) { // TODO: implement topo sort with unaligned quads if (this.unalignedQuadCount > 0) { @@ -463,7 +456,6 @@ private static void makeEdge(int[][] graph, BitArray leafQuads, int fromQuadInde */ private boolean topoSortAlignedAcyclic(IntBuffer indexBuffer) { - /** * The translucent quad visibility graph is stored as an array for each quad. * Each quad's array stores the indexes of the quads that can see this quad diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/SortType.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/SortType.java index 918d91ed4d..5d6eba8697 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/SortType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/SortType.java @@ -36,7 +36,7 @@ public enum SortType { * in the graph. They are swapped out when the cycle-breaking planes are * triggered in GFNI. */ - DYNAMIC_TOPO_CYCLIC(true, true, true, false), + // DYNAMIC_TOPO_CYCLIC(true, true, true, false), /** * There are multiple sort orders. Sorting is required every time GFNI triggers diff --git a/src/main/resources/assets/sodium/lang/en_us.json b/src/main/resources/assets/sodium/lang/en_us.json index 1ca6f8a1d3..d0cb84a4c7 100644 --- a/src/main/resources/assets/sodium/lang/en_us.json +++ b/src/main/resources/assets/sodium/lang/en_us.json @@ -57,11 +57,6 @@ "sodium.console.game_restart": "The game must be restarted to apply one or more video settings!", "sodium.console.broken_nvidia_driver": "Your NVIDIA graphics drivers are out of date!\n * This will cause severe performance issues and crashes when Sodium is installed.\n * Please update your graphics drivers to the latest version (version 536.23 or newer.)", "sodium.console.pojav_launcher": "PojavLauncher is not supported when using Sodium.\n * You are very likely to run into extreme performance issues, graphical bugs, and crashes.\n * You will be on your own if you decide to continue -- we will not help you with any bugs or crashes!", - "sodium.options.sort_behavior.name": "Sort Behavior", - "sodium.options.sort_behavior.tooltip": "Controls when and with how much effort translucency sorting is performed. Dynamic and adaptive sorting will sort geometry as you move around. Lesser sort types perform sorting on an best-effort basis. The more sorting is performed the higher the performance impact.", - "options.sort_behavior.only_trivial": "No Sorting", - "options.sort_behavior.static_normal_relative": "Static Relative", - "options.sort_behavior.static_topo_acyclic": "Static Topological", - "options.sort_behavior.dynamic_all": "Auto", - "options.sort_behavior.only_dynamic_all": "Only Dynamic" + "sodium.options.sort_behavior.name": "Translucency Sorting", + "sodium.options.sort_behavior.tooltip": "Controls when and with how much effort translucency sorting is performed. Dynamic and adaptive sorting will sort geometry as you move around. Lesser sort types perform sorting on an best-effort basis. The more sorting is performed the higher the performance impact." } From d3090ab33fe4d2a352fd589281af2c55fb91afae Mon Sep 17 00:00:00 2001 From: douira Date: Thu, 21 Sep 2023 16:28:58 +0200 Subject: [PATCH 055/256] cleanup comments --- .../mods/sodium/client/render/chunk/gfni/GroupBuilder.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java index f179249bb5..89ba75302a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java @@ -446,16 +446,15 @@ private static void makeEdge(int[][] graph, BitArray leafQuads, int fromQuadInde * - quads are planar and actually have the normal of their facing * - quads don't intersect * - quads aren't shaped weirdly + * - quads are axis-aligned * - * If it manages to find a topological sort, it populates - * {@link #topoSortResult} and returns {@link SortType#STATIC_TOPO_ACYCLIC}. If - * it fails to find a topo sort it returns {@link SortType#DYNAMIC_TOPO_CYCLIC}. + * If the sort was successful, the index buffer will be populated with the index + * data and {@code true} will be returned. Otherwise, {@code false} is returned. * * @param indexBuffer the buffer to write the topo sort result to * @return if the sort was successful */ private boolean topoSortAlignedAcyclic(IntBuffer indexBuffer) { - /** * The translucent quad visibility graph is stored as an array for each quad. * Each quad's array stores the indexes of the quads that can see this quad From 42e850260060643a366c0d90732ced423eb4a845 Mon Sep 17 00:00:00 2001 From: douira Date: Thu, 21 Sep 2023 16:32:54 +0200 Subject: [PATCH 056/256] more cleanup --- .../client/render/chunk/gfni/GroupBuilder.java | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java index 89ba75302a..d703ff5832 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java @@ -557,15 +557,8 @@ private boolean topoSortAlignedAcyclic(IntBuffer indexBuffer) { } } - // the topological sort result of the graph. The order is reversed comapred to - // how topo sort is usually defined, in that the first index points to the quad - // that should be rendered first since it has no outgoing edges (and thus no - // other quads are visible through it). - // iterate through the set of quads with no outgoing edges until there are none - // left. - // TODO: debug topo sort with the arrangement of blocks I wrote the indices down - // in miro + // left to produce a topological sort of the graph List topoSortResult = new ReferenceArrayList<>(); for (int topoSortPos = 0; topoSortPos < this.quads.length; topoSortPos++) { int nextLeafQuadIndex = leafQuads.nextSetBit(0); @@ -573,8 +566,7 @@ private boolean topoSortAlignedAcyclic(IntBuffer indexBuffer) { // if there are no leaf quads but not yet all quads have been processed, // there must be a cycle! if (nextLeafQuadIndex == -1) { - // since this method may be called if it's known that there are no cycles, when - // they are found it's downgraded to DYNAMIC_TOPO_CYCLIC + // abort, there are cycles return false; } From 40f91dbcadaa9437452ceeea811e409b9312df28 Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 22 Sep 2023 23:27:49 +0200 Subject: [PATCH 057/256] better explanation in the settings --- src/main/resources/assets/sodium/lang/en_us.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/assets/sodium/lang/en_us.json b/src/main/resources/assets/sodium/lang/en_us.json index d0cb84a4c7..dbf563a6fb 100644 --- a/src/main/resources/assets/sodium/lang/en_us.json +++ b/src/main/resources/assets/sodium/lang/en_us.json @@ -58,5 +58,5 @@ "sodium.console.broken_nvidia_driver": "Your NVIDIA graphics drivers are out of date!\n * This will cause severe performance issues and crashes when Sodium is installed.\n * Please update your graphics drivers to the latest version (version 536.23 or newer.)", "sodium.console.pojav_launcher": "PojavLauncher is not supported when using Sodium.\n * You are very likely to run into extreme performance issues, graphical bugs, and crashes.\n * You will be on your own if you decide to continue -- we will not help you with any bugs or crashes!", "sodium.options.sort_behavior.name": "Translucency Sorting", - "sodium.options.sort_behavior.tooltip": "Controls when and with how much effort translucency sorting is performed. Dynamic and adaptive sorting will sort geometry as you move around. Lesser sort types perform sorting on an best-effort basis. The more sorting is performed the higher the performance impact." + "sodium.options.sort_behavior.tooltip": "Controls when and with how much effort translucency sorting is performed. Fast only performs sorting when the chunk it loaded. Only Fancy sorting ensures correct sorting all the time and you may see glitches otherwise. More sorting has a performance impact on chunk loading speeds, but usually not frame rates." } From 6999fa458c06fa948fdf31b04c0eef9fe908abb5 Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 23 Sep 2023 05:26:06 +0200 Subject: [PATCH 058/256] refactor sorting algorithms into their respective classes, change topo sort to be able to do sorting on only visible quads (broken) --- .../render/chunk/gfni/ComplexSorting.java | 311 ++++++++++++++++++ .../client/render/chunk/gfni/DynamicData.java | 93 +----- .../render/chunk/gfni/GroupBuilder.java | 252 +------------- .../chunk/gfni/StaticNormalRelativeData.java | 11 +- .../chunk/gfni/StaticTopoAcyclicData.java | 7 +- .../client/render/chunk/gfni/TQuad.java | 13 + .../client/util/collections/BitArray.java | 10 + 7 files changed, 379 insertions(+), 318 deletions(-) create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TQuad.java diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java new file mode 100644 index 0000000000..648d39a493 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java @@ -0,0 +1,311 @@ +package me.jellysquid.mods.sodium.client.render.chunk.gfni; + +import java.nio.IntBuffer; + +import org.joml.Vector3fc; + +import it.unimi.dsi.fastutil.ints.IntArrays; +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import me.jellysquid.mods.sodium.client.util.collections.BitArray; +import me.jellysquid.mods.sodium.client.util.sorting.MergeSort; + +public class ComplexSorting { + private ComplexSorting() { + } + + private static float halfspace(Vector3fc planeAnchor, Vector3fc planeNormal, Vector3fc point) { + return (point.x() - planeAnchor.x()) * planeNormal.x() + + (point.y() - planeAnchor.y()) * planeNormal.y() + + (point.z() - planeAnchor.z()) * planeNormal.z(); + } + + /** + * Test if the given point is within the half space defined by the plane anchor + * and the plane normal. The normal points away from the space considered to be + * inside. + * + * @param planeAnchor the anchor of the plane + * @param planeNormal the normal of the plane + * @param point the point to test + */ + private static boolean pointOutsideHalfspace(Vector3fc planeAnchor, Vector3fc planeNormal, Vector3fc point) { + return halfspace(planeAnchor, planeNormal, point) > 0; + } + + public static void distanceSortModified(IntBuffer indexBuffer, TQuad[] quads, Vector3fc cameraPos) { + int[] indexes = new int[quads.length]; + BitArray visible = new BitArray(quads.length); + float[] centerDist = new float[quads.length]; + for (int i = 0; i < indexes.length; i++) { + indexes[i] = i; + TQuad quad = quads[i]; + if (pointOutsideHalfspace(quad.center(), quad.normal(), cameraPos)) { + visible.set(i); + centerDist[i] = cameraPos.distanceSquared(quads[i].center()); + } + } + + IntArrays.quickSort(indexes, (a, b) -> { + // returning -1 results in the ordering a, b, returning 1 produces b, a + + boolean aVisible = visible.get(a); + boolean bVisible = visible.get(b); + + // compare only pairs where both are visible + if (aVisible && bVisible) { + var quadA = quads[a]; + var quadB = quads[b]; + var normalA = quadA.normal(); + var normalB = quadB.normal(); + + // this is a heuristic that attempts to reduce the sorting mistakes that happen + // when two parallel planes made up of many quads are seen from different + // angles. For quads with equal normals it sorts them only by their + // normal-relative distance to the camera. This eliminates some of wrong sorting + // that happens in tangent directions. + if (normalA.equals(normalB)) { + var centerA = quadA.center(); + var centerB = quadB.center(); + var cameraDistance = normalB.dot(cameraPos); + var result = Float.compare(Math.abs(cameraDistance - normalB.dot(centerB)), + Math.abs(cameraDistance - normalB.dot(centerA))); + if (result != 0) { + return result; + } + } + + return Float.compare(centerDist[b], centerDist[a]); + + } + + // put invisible quads last + if (aVisible) { + return -1; + } + if (bVisible) { + return 1; + } + + return 0; + }); + + TranslucentData.writeVertexIndexes(indexBuffer, indexes); + } + + private static boolean extentWithinHalfspace(TQuad halfspace, TQuad otherQuad) { + var halfspaceDirection = halfspace.facing().ordinal(); + var otherQuadOppositeDirection = halfspace.facing().getOpposite().ordinal(); + var sign = halfspace.facing().getSign(); + + return sign * halfspace.extents()[halfspaceDirection] > sign * otherQuad.extents()[otherQuadOppositeDirection]; + } + + private static boolean orthogonalQuadVisibleThrough(TQuad quad, TQuad otherQuad) { + // A: test that the other quad has an extent within this quad's halfspace + // B: test that this quad has an extent outside the other quad's halfspace + return extentWithinHalfspace(quad, otherQuad) && !extentWithinHalfspace(otherQuad, quad); + } + + /** + * The index in each node's array in the graph where the number of outgoing + * edges is stored. + */ + private static final int OUTGOING_EDGES = ModelQuadFacing.DIRECTIONS; + + private static void makeEdge(int[][] graph, BitArray leafQuads, + int fromQuadIndex, int toQuadIndex, int direction) { + graph[toQuadIndex][direction] = fromQuadIndex; + + // increment outgoing edges and clear from the no outgoing edges set if it had + // no outgoing edges beforehand + if (graph[fromQuadIndex][OUTGOING_EDGES]++ == 0) { + leafQuads.unset(fromQuadIndex); + } + } + + public static void topoSortAlignedAcyclicSafe(IntBuffer indexBuffer, TQuad[] allQuads, Vector3fc cameraPos) { + if (!topoSortAlignedAcyclic(indexBuffer, allQuads, cameraPos)) { + throw new IllegalStateException("Cyclic quad visibility graph!"); + } + } + + /** + * This scanning topo sort algorithm assumes that a number of invariants about + * the quads hold: + * - quads are planar and actually have the normal of their facing + * - quads don't intersect + * - quads aren't shaped weirdly + * - quads are axis-aligned + * + * If a camera position is provided, the algorithm will only sort visible quads + * and just render the other quads first without any particular ordering. + * + * @param indexBuffer the buffer to write the topo sort result to + * @param quads the quads to sort + * @param cameraPos the camera position, or null if not visibility check + * should be performed + * @return true if the quads were sorted, false if there was a cycle + */ + public static boolean topoSortAlignedAcyclic(IntBuffer indexBuffer, TQuad[] allQuads, Vector3fc cameraPos) { + // if enabled, check for visibility and produce a mapping of indices + TQuad[] quads = null; + int[] activeToRealIndex = null; + int activeQuads = 0; + if (cameraPos != null) { + // allocate the working quads and index map at the full size to avoid needing to + // iterate the quads again after checking visibility + quads = new TQuad[allQuads.length]; + activeToRealIndex = new int[allQuads.length]; + + for (int i = 0; i < allQuads.length; i++) { + TQuad quad = allQuads[i]; + if (pointOutsideHalfspace(quad.center(), quad.normal(), cameraPos)) { + activeToRealIndex[activeQuads] = i; + quads[activeQuads] = quad; + activeQuads++; + } else { + // write the invisible quads right away + TranslucentData.putQuadVertexIndexes(indexBuffer, i); + } + } + } else { + quads = allQuads; + activeQuads = allQuads.length; + } + + /** + * The translucent quad visibility graph is stored as an array for each quad. + * Each quad's array stores the indexes of the quads that can see this quad + * through them. The edges are stored backwards to avoid using dynamically + * sized-lists for outgoing edges. + * + * The last entry stores the number of *outgoing* edges. + */ + int[][] graph = new int[activeQuads][ModelQuadFacing.DIRECTIONS + 1]; + + // the set of quads that have no outgoing edges + BitArray leafQuads = new BitArray(activeQuads); + leafQuads.set(0, activeQuads); + + // initialize the graph with -1 to represent no edge + for (int i = 0; i < activeQuads; i++) { + for (int j = 0; j < ModelQuadFacing.DIRECTIONS; j++) { + graph[i][j] = -1; + } + } + + // the stash of quads that have not yet been visible to the scanned quads + BitArray stashedOrthoQuads = new BitArray(activeQuads); + + // keep around the allocation of the keys array + float[] keys = new float[activeQuads]; + + // to build the graph, perform scans for each direction + for (int direction = 0; direction < ModelQuadFacing.DIRECTIONS; direction++) { + ModelQuadFacing facing = ModelQuadFacing.VALUES[direction]; + ModelQuadFacing oppositeFacing = facing.getOpposite(); + int oppositeDirection = oppositeFacing.ordinal(); + int sign = facing.getSign(); + + // generate keys for this direction + for (int i = 0; i < activeQuads; i++) { + // get the extent in the opposite direction of the scan because quads that are + // visible from a scanning quad should be before it + TQuad quad = quads[i]; + keys[i] = quad.extents()[oppositeDirection] * sign * -1; + } + + int[] sortedQuads = MergeSort.mergeSort(keys); + + // the index of the last quad facing in scan direction (scanning quad) in the + // sorted quad array + int lastScanQuadPos = -1; + + // perform a scan by going through the sorted quads and making edges between the + // scanning quads and the quads that precede them in the sort order + stashedOrthoQuads.unset(); + for (int quadIndexPos = 0; quadIndexPos < activeQuads; quadIndexPos++) { + int quadIndex = sortedQuads[quadIndexPos]; + TQuad quad = quads[quadIndex]; + if (quad.facing() != facing) { + continue; + } + + // connect to the last scan quad if it exists + if (lastScanQuadPos != -1) { + makeEdge(graph, leafQuads, quadIndex, sortedQuads[lastScanQuadPos], direction); + } + + // check if any of the stashed quads are now visible + for (int stashedQuadIndex = stashedOrthoQuads + .nextSetBit(0); stashedQuadIndex != -1; stashedQuadIndex = stashedOrthoQuads + .nextSetBit(stashedQuadIndex + 1)) { + TQuad stashedOrthoQuad = quads[stashedQuadIndex]; + + // if it's visible through the current quad, unstash and connect + if (orthogonalQuadVisibleThrough(quad, stashedOrthoQuad)) { + stashedOrthoQuads.unset(stashedQuadIndex); + makeEdge(graph, leafQuads, quadIndex, stashedQuadIndex, direction); + } + } + + // check the quads facing in other directions than the scan facing. + // initially increment to skip the last scan quad. + for (++lastScanQuadPos; lastScanQuadPos < quadIndexPos; lastScanQuadPos++) { + int otherQuadIndex = sortedQuads[lastScanQuadPos]; + TQuad otherQuad = quads[otherQuadIndex]; + + // discard quads that face in the opposite direction, they are never visible + if (otherQuad.facing() == oppositeFacing) { + continue; + } + + // if it's visible through the current quad, add an edge. + // the quad has a direction that is orthogonal to the scan direction, since + // opposite quads were just ruled out and same facing quads are handled by the + // scan. + if (orthogonalQuadVisibleThrough(quad, otherQuad)) { + makeEdge(graph, leafQuads, quadIndex, otherQuadIndex, direction); + } else { + // otherwise stash it to check if it's visible by later quads in the scan + stashedOrthoQuads.set(otherQuadIndex); + } + } + + // lastScanQuadPos is now at quadIndexPos + } + } + + // iterate through the set of quads with no outgoing edges until there are none + // left to produce a topological sort of the graph + for (int topoSortPos = 0; topoSortPos < activeQuads; topoSortPos++) { + int nextLeafQuadIndex = leafQuads.nextSetBit(0); + + // if there are no leaf quads but not yet all quads have been processed, + // there must be a cycle! + if (nextLeafQuadIndex == -1) { + return false; + } + + leafQuads.unset(nextLeafQuadIndex); + + // add it to the topo sort result + if (cameraPos != null) { + TranslucentData.putQuadVertexIndexes(indexBuffer, activeToRealIndex[nextLeafQuadIndex]); + } else { + TranslucentData.putQuadVertexIndexes(indexBuffer, nextLeafQuadIndex); + } + + // remove the edges to this quad and mark them as leaves if that was the last + // outgoing edge they had + for (int direction = 0; direction < ModelQuadFacing.DIRECTIONS; direction++) { + int otherQuadIndex = graph[nextLeafQuadIndex][direction]; + if (otherQuadIndex != -1 && --graph[otherQuadIndex][OUTGOING_EDGES] == 0) { + leafQuads.set(otherQuadIndex); + } + } + } + + return true; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java index b978fc13c8..3761811e8f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java @@ -1,14 +1,13 @@ package me.jellysquid.mods.sodium.client.render.chunk.gfni; +import java.nio.IntBuffer; + import org.joml.Vector3fc; import it.unimi.dsi.fastutil.ints.Int2ReferenceLinkedOpenHashMap; -import it.unimi.dsi.fastutil.ints.IntArrays; import me.jellysquid.mods.sodium.client.gl.util.VertexRange; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; -import me.jellysquid.mods.sodium.client.render.chunk.gfni.GroupBuilder.Quad; import me.jellysquid.mods.sodium.client.util.NativeBuffer; -import me.jellysquid.mods.sodium.client.util.collections.BitArray; import net.minecraft.util.math.ChunkSectionPos; /** @@ -20,12 +19,12 @@ * Possibly re-use of (incrementally constructed) graph structures is necessary? */ public class DynamicData extends MixedDirectionData { - private final Quad[] quads; + private final TQuad[] quads; private final AccumulationGroup[] axisAlignedDistances; private final Int2ReferenceLinkedOpenHashMap unalignedDistances; DynamicData(ChunkSectionPos sectionPos, - NativeBuffer buffer, VertexRange range, Quad[] quads, + NativeBuffer buffer, VertexRange range, TQuad[] quads, AccumulationGroup[] axisAlignedDistances, Int2ReferenceLinkedOpenHashMap unalignedDistances) { super(sectionPos, buffer, range); @@ -62,86 +61,30 @@ public Int2ReferenceLinkedOpenHashMap getUnalignedDistances() return this.unalignedDistances; } - private static float halfspace(Vector3fc planeAnchor, Vector3fc planeNormal, Vector3fc point) { - return (point.x() - planeAnchor.x()) * planeNormal.x() + - (point.y() - planeAnchor.y()) * planeNormal.y() + - (point.z() - planeAnchor.z()) * planeNormal.z(); - } - @Override public void sort(Vector3fc cameraPos) { - int[] indexes = new int[this.quads.length]; - BitArray visible = new BitArray(this.quads.length); - float[] centerDist = new float[this.quads.length]; - for (int i = 0; i < indexes.length; i++) { - indexes[i] = i; - Quad quad = this.quads[i]; - if (halfspace(quad.center(), quad.normal(), cameraPos) > 0) { - visible.set(i); - centerDist[i] = cameraPos.distanceSquared(this.quads[i].center()); - } - } - - IntArrays.quickSort(indexes, (a, b) -> { - // returning -1 results in the ordering a, b, returning 1 produces b, a - - boolean aVisible = visible.get(a); - boolean bVisible = visible.get(b); - - // compare only pairs where both are visible - if (aVisible && bVisible) { - var quadA = this.quads[a]; - var quadB = this.quads[b]; - var normalA = quadA.normal(); - var normalB = quadB.normal(); - - // this is a heuristic that attempts to reduce the sorting mistakes that happen - // when two parallel planes made up of many quads are seen from different - // angles. For quads with equal normals it sorts them only by their - // normal-relative distance to the camera. This eliminates some of wrong sorting - // that happens in tangent directions. - if (normalA.equals(normalB)) { - var centerA = quadA.center(); - var centerB = quadB.center(); - var cameraDistance = normalB.dot(cameraPos); - var result = Float.compare(Math.abs(cameraDistance - normalB.dot(centerB)), - Math.abs(cameraDistance - normalB.dot(centerA))); - if (result != 0) { - return result; - } - } - - return Float.compare(centerDist[b], centerDist[a]); - - } - - // put invisible quads last - if (aVisible) { - return -1; - } - if (bVisible) { - return 1; - } - - return 0; - }); + IntBuffer indexBuffer = this.buffer.getDirectBuffer().asIntBuffer(); - var intBuffer = this.buffer.getDirectBuffer().asIntBuffer(); - TranslucentData.writeVertexIndexes(intBuffer, indexes); + if (this.unalignedDistances == null || this.unalignedDistances.isEmpty()) { + // TODO: this throws because something is breaking it, either a mistake in the + // algorithm or a violation of the assumptions + ComplexSorting.topoSortAlignedAcyclicSafe(indexBuffer, this.quads, cameraPos); + } else { + ComplexSorting.distanceSortModified(indexBuffer, this.quads, cameraPos); + } } - static DynamicData fromMesh(BuiltSectionMeshParts translucentMesh, NativeBuffer reuseBuffer, - Vector3fc cameraPos, Quad[] quads, ChunkSectionPos sectionPos, GroupBuilder groupBuilder) { + static DynamicData fromMesh(BuiltSectionMeshParts translucentMesh, + Vector3fc cameraPos, TQuad[] quads, ChunkSectionPos sectionPos, GroupBuilder groupBuilder) { VertexRange range = TranslucentData.getUnassignedVertexRange(translucentMesh); - - if (reuseBuffer == null) { - reuseBuffer = new NativeBuffer(TranslucentData.quadCountToIndexBytes(quads.length)); - } + var buffer = new NativeBuffer(TranslucentData.quadCountToIndexBytes(quads.length)); var dynamicData = new DynamicData(sectionPos, - reuseBuffer, range, quads, + buffer, range, quads, groupBuilder.axisAlignedDistances, groupBuilder.unalignedDistances); + dynamicData.sort(cameraPos); + return dynamicData; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java index d703ff5832..22df7122df 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java @@ -1,8 +1,5 @@ package me.jellysquid.mods.sodium.client.render.chunk.gfni; -import java.nio.IntBuffer; -import java.util.List; - import org.joml.Vector3f; import org.joml.Vector3fc; @@ -14,9 +11,6 @@ import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexEncoder; -import me.jellysquid.mods.sodium.client.util.NativeBuffer; -import me.jellysquid.mods.sodium.client.util.collections.BitArray; -import me.jellysquid.mods.sodium.client.util.sorting.MergeSort; import net.minecraft.util.math.ChunkSectionPos; /** @@ -32,16 +26,13 @@ * unaligned faces at all? * - bail early during rendering if we decide not to topo sort, then we don't * need to gather all of the data - * - do normal-relative sorting here too? or keep it in StaticTranslucentData? * - detail how the graph construction and the topo sort works in the GFNI doc - * - make the resulting static index buffer actually available to the renderer + * - optionally add a way to attempt full acyclic topo sort even if the + * heuristic doesn't expect it to be possible. The caveat is that this costs + * doing it once without invisible quad exclusion and once with if the first + * attempt fails. */ public class GroupBuilder { - // TODO: debugging - private static int topoSortHits = 0; - private static int cyclicGraphHits = 0; - private static int unalignedDynamicHits = 0; - private static final Vector3fc[] ALIGNED_NORMALS = new Vector3fc[ModelQuadFacing.DIRECTIONS]; private static final int OPPOSING_X = 1 << ModelQuadFacing.POS_X.ordinal() | 1 << ModelQuadFacing.NEG_X.ordinal(); @@ -66,8 +57,8 @@ public class GroupBuilder { private int unalignedQuadCount = 0; @SuppressWarnings("unchecked") - private ReferenceArrayList[] quadLists = new ReferenceArrayList[ModelQuadFacing.COUNT]; - private Quad[] quads; + private ReferenceArrayList[] quadLists = new ReferenceArrayList[ModelQuadFacing.COUNT]; + private TQuad[] quads; private SortType sortType; @@ -75,9 +66,6 @@ public GroupBuilder(ChunkSectionPos sectionPos) { this.sectionPos = sectionPos; } - record Quad(ModelQuadFacing facing, Vector3fc normal, Vector3f center, float[] extents) { - } - public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] vertices, ModelQuadFacing facing) { float xSum = 0; float ySum = 0; @@ -152,7 +140,7 @@ public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] verti this.unalignedDistances.put(normalKey, accGroup); } - quadList.add(new Quad(facing, accGroup.normal, center, extents)); + quadList.add(new TQuad(facing, accGroup.normal, center, extents)); this.unalignedQuadCount++; } else { if (this.axisAlignedDistances == null) { @@ -168,7 +156,7 @@ public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] verti this.alignedNormalBitmap |= 1 << quadDirection; } - quadList.add(new Quad(facing, accGroup.normal, center, extents)); + quadList.add(new TQuad(facing, accGroup.normal, center, extents)); } var firstVertex = vertices[0]; @@ -182,15 +170,10 @@ public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] verti * doesn't match, then it's set to the NONE sort type. * * @param sortType the sort type to filter - * @param allowDynamicInStatic if true, then the DYNAMIC_ALL is allowed even if - * the sort behavior is STATIC. This is to allow a - * topo sort to be attempted even if the heuristic - * can't determine that it's acyclic. */ - private static SortType filterSortType(SortType sortType, boolean allowDynamicInStatic) { + private static SortType filterSortType(SortType sortType) { SortBehavior sortBehavior = SodiumClientMod.options().performance.sortBehavior; - if (!sortBehavior.sortTypes.contains(sortType) - && !(allowDynamicInStatic && sortBehavior == SortBehavior.STATIC)) { + if (!sortBehavior.sortTypes.contains(sortType)) { return SortType.NONE; } return sortType; @@ -339,7 +322,7 @@ public SortType finishRendering() { totalQuadCount += quadList.size(); } } - this.quads = new Quad[totalQuadCount]; + this.quads = new TQuad[totalQuadCount]; int quadIndex = 0; for (var quadList : this.quadLists) { if (quadList != null) { @@ -350,7 +333,7 @@ public SortType finishRendering() { } this.quadLists = null; - this.sortType = filterSortType(sortTypeHeuristic(), true); + this.sortType = filterSortType(sortTypeHeuristic()); return this.sortType; } @@ -365,227 +348,26 @@ public TranslucentData getTranslucentData(BuiltSectionMeshParts translucentMesh, // from this point on we know the estimated sort type requires direction mixing // (no backface culling) and all vertices are in the UNASSIGNED direction. - NativeBuffer buffer = null; - if (this.sortType == SortType.STATIC_TOPO_ACYCLIC - // || this.sortType == SortType.DYNAMIC_TOPO_CYCLIC - || this.sortType == SortType.DYNAMIC_ALL) { - // TODO: implement topo sort with unaligned quads + if (this.sortType == SortType.STATIC_TOPO_ACYCLIC) { if (this.unalignedQuadCount > 0) { - unalignedDynamicHits++; + // TODO: implement topo sort with unaligned quads this.sortType = SortType.DYNAMIC_ALL; } else { - // it can only perform topo sort on acyclic graphs since it has no cycle - // breaking, but it will detect cycles and bail to DYNAMIC_ALL - // DYNAMIC_TOPO_CYCLIC if there is a cycle - var indexData = StaticTopoAcyclicData.fromMesh(translucentMesh, sectionPos); - buffer = indexData.buffer; - IntBuffer indexBuffer = buffer.getDirectBuffer().asIntBuffer(); - - if (topoSortAlignedAcyclic(indexBuffer)) { - topoSortHits++; - - return indexData; - } else { - // TODO: cyclic topo sort with cycle breaking - cyclicGraphHits++; - - this.sortType = SortType.DYNAMIC_ALL; - } + return StaticTopoAcyclicData.fromMesh(translucentMesh, this.quads, sectionPos); } - - // System.out.println("topo sort hits: " + topoSortHits + ", cyclic graph hits: - // " + cyclicGraphHits - // + ", unaligned dynamic hits: " + unalignedDynamicHits); } // filter the sort type with the user setting and re-evaluate - this.sortType = filterSortType(this.sortType, false); + this.sortType = filterSortType(this.sortType); if (this.sortType == SortType.NONE) { - if (buffer != null) { - buffer.free(); - } return new NoneData(this.sectionPos); } if (this.sortType == SortType.DYNAMIC_ALL) { - return DynamicData.fromMesh(translucentMesh, buffer, cameraPos, quads, sectionPos, this); + return DynamicData.fromMesh(translucentMesh, cameraPos, quads, sectionPos, this); } throw new IllegalStateException("Unknown sort type: " + this.sortType); } - - private static boolean orthogonalQuadVisible(Quad quad, Quad otherQuad) { - var otherQuadDirection = otherQuad.facing.ordinal(); - var sign = otherQuad.facing.getSign(); - - // this only works because the quads are planar and the extent in the direction - // of the quad's normal is the same as in the opposite direction - return sign * quad.extents[otherQuadDirection] > sign * otherQuad.extents[otherQuadDirection]; - } - - /** - * The index in each node's array in the graph where the number of outgoing - * edges is stored. - */ - private static final int OUTGOING_EDGES = ModelQuadFacing.DIRECTIONS; - - private static void makeEdge(int[][] graph, BitArray leafQuads, int fromQuadIndex, int toQuadIndex, int direction) { - graph[toQuadIndex][direction] = fromQuadIndex; - - // increment outgoing edges and clear from the no outgoing edges set if it had - // no outgoing edges beforehand - if (graph[fromQuadIndex][OUTGOING_EDGES]++ == 0) { - leafQuads.unset(fromQuadIndex); - } - } - - /** - * This scanning topo sort algorithm assumes that a number of invariants about - * the quads hold: - * - quads are planar and actually have the normal of their facing - * - quads don't intersect - * - quads aren't shaped weirdly - * - quads are axis-aligned - * - * If the sort was successful, the index buffer will be populated with the index - * data and {@code true} will be returned. Otherwise, {@code false} is returned. - * - * @param indexBuffer the buffer to write the topo sort result to - * @return if the sort was successful - */ - private boolean topoSortAlignedAcyclic(IntBuffer indexBuffer) { - /** - * The translucent quad visibility graph is stored as an array for each quad. - * Each quad's array stores the indexes of the quads that can see this quad - * through them. The edges are stored backwards to avoid using dynamically - * sized-lists for outgoing edges. - * - * The last entry stores the number of *outgoing* edges. - */ - int[][] graph = new int[this.quads.length][ModelQuadFacing.DIRECTIONS + 1]; - - // the set of quads that have no outgoing edges - BitArray leafQuads = new BitArray(this.quads.length); - leafQuads.set(0, this.quads.length); - - for (int i = 0; i < this.quads.length; i++) { - for (int j = 0; j < ModelQuadFacing.DIRECTIONS; j++) { - graph[i][j] = -1; - } - } - - // the stash of quads that have not yet been visible to the scanned quads - BitArray stashedOrthoQuads = new BitArray(this.quads.length); - - // keep around the allocation of the keys array - float[] keys = new float[this.quads.length]; - - // to build the graph, perform scans for each direction - for (int direction = 0; direction < ModelQuadFacing.DIRECTIONS; direction++) { - ModelQuadFacing facing = ModelQuadFacing.VALUES[direction]; - ModelQuadFacing oppositeFacing = facing.getOpposite(); - int oppositeDirection = oppositeFacing.ordinal(); - int sign = facing.getSign(); - - // generate keys for this direction - for (int i = 0; i < this.quads.length; i++) { - // get the extent in the opposite direction of the scan because quads that are - // visible from a scanning quad should be before it - Quad quad = this.quads[i]; - keys[i] = quad.extents[oppositeDirection] * sign * -1; - } - - int[] sortedQuads = MergeSort.mergeSort(keys); - - // the index of the last quad facing in scan direction (scanning quad) in the - // sorted quad array - int lastScanQuadPos = -1; - - // perform a scan by going through the sorted quads and making edges between the - // scanning quads and the quads that precede them in the sort order - stashedOrthoQuads.unset(); - for (int quadIndexPos = 0; quadIndexPos < this.quads.length; quadIndexPos++) { - int quadIndex = sortedQuads[quadIndexPos]; - Quad quad = this.quads[quadIndex]; - if (quad.facing != facing) { - continue; - } - - // connect to the last scan quad if it exists - if (lastScanQuadPos != -1) { - makeEdge(graph, leafQuads, quadIndex, sortedQuads[lastScanQuadPos], direction); - } - - // check if any of the stashed quads are now visible - for (int stashedQuadIndex = stashedOrthoQuads - .nextSetBit(0); stashedQuadIndex != -1; stashedQuadIndex = stashedOrthoQuads - .nextSetBit(stashedQuadIndex + 1)) { - Quad stashedOrthoQuad = this.quads[stashedQuadIndex]; - - // if it's visible through the current quad, unstash and connect - if (orthogonalQuadVisible(quad, stashedOrthoQuad)) { - stashedOrthoQuads.unset(stashedQuadIndex); - makeEdge(graph, leafQuads, quadIndex, stashedQuadIndex, direction); - } - } - - // check the quads facing in other directions than the scan facing. - // initially increment to skip the last scan quad. - for (++lastScanQuadPos; lastScanQuadPos < quadIndexPos; lastScanQuadPos++) { - int otherQuadIndex = sortedQuads[lastScanQuadPos]; - Quad otherQuad = this.quads[otherQuadIndex]; - - // discard quads that face in the opposite direction, they are never visible - if (otherQuad.facing == oppositeFacing) { - continue; - } - - // if it's visible through the current quad, add an edge. - // the quad has a direction that is orthogonal to the scan direction, since - // opposite quads were just ruled out and same facing quads are handled by the - // scan. - if (orthogonalQuadVisible(quad, otherQuad)) { - makeEdge(graph, leafQuads, quadIndex, otherQuadIndex, direction); - } else { - // otherwise stash it to check if it's visible by later quads in the scan - stashedOrthoQuads.set(otherQuadIndex); - } - } - - // lastScanQuad is now at quadIndexPos - } - } - - // iterate through the set of quads with no outgoing edges until there are none - // left to produce a topological sort of the graph - List topoSortResult = new ReferenceArrayList<>(); - for (int topoSortPos = 0; topoSortPos < this.quads.length; topoSortPos++) { - int nextLeafQuadIndex = leafQuads.nextSetBit(0); - - // if there are no leaf quads but not yet all quads have been processed, - // there must be a cycle! - if (nextLeafQuadIndex == -1) { - // abort, there are cycles - return false; - } - - leafQuads.unset(nextLeafQuadIndex); - - // add it to the topo sort result - TranslucentData.putQuadVertexIndexes(indexBuffer, nextLeafQuadIndex); - topoSortResult.add(nextLeafQuadIndex); - - // remove the edges to this quad and mark them as leaves if that was the last - // outgoing edge they had - for (int direction = 0; direction < ModelQuadFacing.DIRECTIONS; direction++) { - int otherQuadIndex = graph[nextLeafQuadIndex][direction]; - if (otherQuadIndex != -1 && --graph[otherQuadIndex][OUTGOING_EDGES] == 0) { - leafQuads.set(otherQuadIndex); - } - } - } - - return true; - } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java index 571ca9ab36..522f2cb408 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java @@ -9,7 +9,6 @@ import me.jellysquid.mods.sodium.client.gl.util.VertexRange; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; -import me.jellysquid.mods.sodium.client.render.chunk.gfni.GroupBuilder.Quad; import me.jellysquid.mods.sodium.client.util.NativeBuffer; import me.jellysquid.mods.sodium.client.util.sorting.MergeSort; import me.jellysquid.mods.sodium.client.util.sorting.VertexSorters; @@ -41,12 +40,12 @@ public SortType getSortType() { } private static StaticNormalRelativeData fromDoubleUnaligned(BuiltSectionMeshParts translucentMesh, - Quad[] quads, ChunkSectionPos sectionPos, GroupBuilder groupBuilder) { + TQuad[] quads, ChunkSectionPos sectionPos, GroupBuilder groupBuilder) { VertexRange[] ranges = translucentMesh.getVertexRanges(); float[] keys = new float[quads.length]; for (int i = 0; i < quads.length; i++) { - Quad quad = quads[i]; + TQuad quad = quads[i]; keys[i] = quad.center().dot(quad.normal()); } @@ -60,7 +59,7 @@ private static StaticNormalRelativeData fromDoubleUnaligned(BuiltSectionMeshPart } private static StaticNormalRelativeData fromAligned(BuiltSectionMeshParts translucentMesh, - Quad[] quads, ChunkSectionPos sectionPos) { + TQuad[] quads, ChunkSectionPos sectionPos) { VertexRange[] ranges = translucentMesh.getVertexRanges(); Vector3f[][] centers = new Vector3f[ModelQuadFacing.COUNT][]; @@ -72,7 +71,7 @@ private static StaticNormalRelativeData fromAligned(BuiltSectionMeshParts transl } int centerCounter = 0; - for (Quad quad : quads) { + for (TQuad quad : quads) { var directionCenters = centers[quad.facing().ordinal()]; directionCenters[centerCounter++] = quad.center(); @@ -109,7 +108,7 @@ private static StaticNormalRelativeData fromAligned(BuiltSectionMeshParts transl } static StaticNormalRelativeData fromMesh(BuiltSectionMeshParts translucentMesh, - Quad[] quads, ChunkSectionPos sectionPos, GroupBuilder groupBuilder) { + TQuad[] quads, ChunkSectionPos sectionPos, GroupBuilder groupBuilder) { if (groupBuilder.alignedNormalBitmap == 0) { return fromDoubleUnaligned(translucentMesh, quads, sectionPos, groupBuilder); } else { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java index 5f17caf55e..da826baf5e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java @@ -15,10 +15,13 @@ public SortType getSortType() { return SortType.STATIC_TOPO_ACYCLIC; } - // NOTE: requires filling the contained buffer with data afterwards - static StaticTopoAcyclicData fromMesh(BuiltSectionMeshParts translucentMesh, ChunkSectionPos sectionPos) { + static StaticTopoAcyclicData fromMesh(BuiltSectionMeshParts translucentMesh, + TQuad[] quads, ChunkSectionPos sectionPos) { VertexRange range = TranslucentData.getUnassignedVertexRange(translucentMesh); var buffer = new NativeBuffer(TranslucentData.vertexCountToIndexBytes(range.vertexCount())); + var indexBuffer = buffer.getDirectBuffer().asIntBuffer(); + + ComplexSorting.topoSortAlignedAcyclicSafe(indexBuffer, quads, null); return new StaticTopoAcyclicData(sectionPos, buffer, range); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TQuad.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TQuad.java new file mode 100644 index 0000000000..55d8506574 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TQuad.java @@ -0,0 +1,13 @@ +package me.jellysquid.mods.sodium.client.render.chunk.gfni; + +import org.joml.Vector3f; +import org.joml.Vector3fc; + +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; + +/** + * Represents a quad for the purposes of translucency sorting. Called TQuad to + * avoid confusion with other quad classes. + */ +record TQuad(ModelQuadFacing facing, Vector3fc normal, Vector3f center, float[] extents) { +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/collections/BitArray.java b/src/main/java/me/jellysquid/mods/sodium/client/util/collections/BitArray.java index 6b9718a724..659952dc7a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/collections/BitArray.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/collections/BitArray.java @@ -257,4 +257,14 @@ public int nextSetBit(int fromIndex) { word = this.words[u]; } } + + public String toBitString() { + StringBuilder sb = new StringBuilder(); + + for (int i = 0; i < this.count; i++) { + sb.append(this.get(i) ? '1' : '0'); + } + + return sb.toString(); + } } From 8ad7df5061fcec64a8753c38629c80a72108b9c2 Mon Sep 17 00:00:00 2001 From: douira Date: Sun, 24 Sep 2023 00:50:17 +0200 Subject: [PATCH 059/256] skip inactive directions in topo sort --- .../client/render/chunk/gfni/ComplexSorting.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java index 648d39a493..9630127f2c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java @@ -187,8 +187,13 @@ public static boolean topoSortAlignedAcyclic(IntBuffer indexBuffer, TQuad[] allQ BitArray leafQuads = new BitArray(activeQuads); leafQuads.set(0, activeQuads); + // a bitfield of the directions that have quads + int activeDirections = 0; + // initialize the graph with -1 to represent no edge for (int i = 0; i < activeQuads; i++) { + activeDirections |= 1 << quads[i].facing().ordinal(); + for (int j = 0; j < ModelQuadFacing.DIRECTIONS; j++) { graph[i][j] = -1; } @@ -202,6 +207,11 @@ public static boolean topoSortAlignedAcyclic(IntBuffer indexBuffer, TQuad[] allQ // to build the graph, perform scans for each direction for (int direction = 0; direction < ModelQuadFacing.DIRECTIONS; direction++) { + // skip directions that have no quads + if ((activeDirections & (1 << direction)) == 0) { + continue; + } + ModelQuadFacing facing = ModelQuadFacing.VALUES[direction]; ModelQuadFacing oppositeFacing = facing.getOpposite(); int oppositeDirection = oppositeFacing.ordinal(); From 8327e3bbb1357ca8beb6ad7f7c536d98a0011624 Mon Sep 17 00:00:00 2001 From: douira Date: Sun, 24 Sep 2023 06:35:52 +0200 Subject: [PATCH 060/256] implement full graph topo sort --- .../render/chunk/gfni/ComplexSorting.java | 192 ++++++++++++++++-- .../client/render/chunk/gfni/DynamicData.java | 9 +- .../chunk/gfni/StaticTopoAcyclicData.java | 4 +- .../render/chunk/gfni/TranslucentData.java | 8 + 4 files changed, 192 insertions(+), 21 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java index 9630127f2c..a23c2e6ce9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java @@ -92,7 +92,21 @@ public static void distanceSortModified(IntBuffer indexBuffer, TQuad[] quads, Ve TranslucentData.writeVertexIndexes(indexBuffer, indexes); } - private static boolean extentWithinHalfspace(TQuad halfspace, TQuad otherQuad) { + private static int[] distanceSortIndexes(TQuad[] quads, Vector3fc cameraPos) { + float[] keys = new float[quads.length]; + for (int i = 0; i < quads.length; i++) { + keys[i] = cameraPos.distanceSquared(quads[i].center()); + } + + return MergeSort.mergeSort(keys); + } + + public static void distanceSortDirect(IntBuffer indexBuffer, TQuad[] quads, Vector3fc cameraPos) { + var indexes = distanceSortIndexes(quads, cameraPos); + TranslucentData.writeVertexIndexes(indexBuffer, indexes); + } + + private static boolean orthoExtentWithinHalfspace(TQuad halfspace, TQuad otherQuad) { var halfspaceDirection = halfspace.facing().ordinal(); var otherQuadOppositeDirection = halfspace.facing().getOpposite().ordinal(); var sign = halfspace.facing().getSign(); @@ -103,7 +117,7 @@ private static boolean extentWithinHalfspace(TQuad halfspace, TQuad otherQuad) { private static boolean orthogonalQuadVisibleThrough(TQuad quad, TQuad otherQuad) { // A: test that the other quad has an extent within this quad's halfspace // B: test that this quad has an extent outside the other quad's halfspace - return extentWithinHalfspace(quad, otherQuad) && !extentWithinHalfspace(otherQuad, quad); + return orthoExtentWithinHalfspace(quad, otherQuad) && !orthoExtentWithinHalfspace(otherQuad, quad); } /** @@ -123,12 +137,6 @@ private static void makeEdge(int[][] graph, BitArray leafQuads, } } - public static void topoSortAlignedAcyclicSafe(IntBuffer indexBuffer, TQuad[] allQuads, Vector3fc cameraPos) { - if (!topoSortAlignedAcyclic(indexBuffer, allQuads, cameraPos)) { - throw new IllegalStateException("Cyclic quad visibility graph!"); - } - } - /** * This scanning topo sort algorithm assumes that a number of invariants about * the quads hold: @@ -140,8 +148,11 @@ public static void topoSortAlignedAcyclicSafe(IntBuffer indexBuffer, TQuad[] all * If a camera position is provided, the algorithm will only sort visible quads * and just render the other quads first without any particular ordering. * + * Sometimes this algorithm will fail even if a topological sort is possible due + * to how it compresses the graph. + * * @param indexBuffer the buffer to write the topo sort result to - * @param quads the quads to sort + * @param allQuads the quads to sort * @param cameraPos the camera position, or null if not visibility check * should be performed * @return true if the quads were sorted, false if there was a cycle @@ -300,11 +311,7 @@ public static boolean topoSortAlignedAcyclic(IntBuffer indexBuffer, TQuad[] allQ leafQuads.unset(nextLeafQuadIndex); // add it to the topo sort result - if (cameraPos != null) { - TranslucentData.putQuadVertexIndexes(indexBuffer, activeToRealIndex[nextLeafQuadIndex]); - } else { - TranslucentData.putQuadVertexIndexes(indexBuffer, nextLeafQuadIndex); - } + TranslucentData.putMappedQuadVertexIndexes(indexBuffer, nextLeafQuadIndex, activeToRealIndex); // remove the edges to this quad and mark them as leaves if that was the last // outgoing edge they had @@ -318,4 +325,161 @@ public static boolean topoSortAlignedAcyclic(IntBuffer indexBuffer, TQuad[] allQ return true; } + + /** + * Checks if one quad is visible through the other quad. This accepts arbitrary + * quads, even unaligned ones. + * + * @param quad the quad through which the other quad is being tested + * @param other the quad being tested + * @return true if the other quad is visible through the first quad + */ + private static boolean quadVisibleThrough(TQuad quad, TQuad other) { + if (quad == other) { + return false; + } + + // aligned quads + var quadFacing = quad.facing(); + var otherFacing = other.facing(); + if (quadFacing != ModelQuadFacing.UNASSIGNED && otherFacing != ModelQuadFacing.UNASSIGNED) { + // opposites never see eachother + if (quadFacing.getOpposite() == otherFacing) { + return false; + } + + // parallel quads, coplanar quads are not visible to eachother + if (quadFacing == otherFacing) { + var sign = quadFacing.getSign(); + var direction = quadFacing.ordinal(); + return sign * quad.extents()[direction] > sign * other.extents()[direction]; + } + + // orthogonal quads + return orthogonalQuadVisibleThrough(quad, other); + } + + // at least one unaligned quad + // this is an approximation since our quads don't store all their vertices. + // check that other center is within the halfspace of quad and that the normals + // are more than 90 degrees apart + return halfspace(quad.center(), quad.normal(), other.center()) < 0 + && quad.normal().dot(other.normal()) < 0; + } + + /** + * Performs a topological sort but constructs the full forward graph without + * using a compression technique like + * {@link #topoSortAlignedAcyclic(IntBuffer, TQuad[], Vector3fc)} does. Only + * sort visible quads if a camera position is provided. + * + * @param indexBuffer the buffer to write the topo sort result to + * @param allQuads the quads to sort + * @param cameraPos the camera position, or null to disable the visibility + * check + * @return true if the quads were sorted, false if there was a cycle + */ + public static boolean topoSortFullGraphAcyclic(IntBuffer indexBuffer, TQuad[] allQuads, Vector3fc cameraPos) { + // TODO: quads visibility filter copy-pasted from topoSortAlignedAcyclic + // if enabled, check for visibility and produce a mapping of indices + TQuad[] quads = null; + int[] activeToRealIndex = null; + int activeQuads = 0; + if (cameraPos != null) { + // allocate the working quads and index map at the full size to avoid needing to + // iterate the quads again after checking visibility + quads = new TQuad[allQuads.length]; + activeToRealIndex = new int[allQuads.length]; + + for (int i = 0; i < allQuads.length; i++) { + TQuad quad = allQuads[i]; + if (pointOutsideHalfspace(quad.center(), quad.normal(), cameraPos)) { + activeToRealIndex[activeQuads] = i; + quads[activeQuads] = quad; + activeQuads++; + } else { + // write the invisible quads right away + TranslucentData.putQuadVertexIndexes(indexBuffer, i); + } + } + } else { + quads = allQuads; + activeQuads = allQuads.length; + } + + // int-based doubly linked list of active quad indexes + int[] forwards = new int[activeQuads]; + int[] backwards = new int[activeQuads]; + int start = 0; + int end = activeQuads - 1; // TODO: this is not used, remove? + for (int i = 0; i < activeQuads - 1; i++) { + forwards[i] = i + 1; + backwards[i + 1] = i; + } + forwards[activeQuads - 1] = -1; + backwards[0] = -1; + + // go through all the active quads and insert them into the list at the point + // where they are after all the quads that are visible through them + for (int quadIndex = 0; quadIndex < activeQuads; quadIndex++) { + TQuad quad = quads[quadIndex]; + + // test all other quads + int insertAfter = -1; + int otherQuadIndex = start; + while (otherQuadIndex != -1) { + TQuad otherQuad = quads[otherQuadIndex]; + if (quadVisibleThrough(quad, otherQuad)) { + insertAfter = otherQuadIndex; + } + otherQuadIndex = forwards[otherQuadIndex]; + } + + // remove from current location + int currentForward = forwards[quadIndex]; + int currentBackward = backwards[quadIndex]; + if (currentForward != -1) { + backwards[currentForward] = currentBackward; + } else { + end = currentBackward; + } + if (currentBackward != -1) { + forwards[currentBackward] = currentForward; + } else { + start = currentForward; + } + + // insert after the identified last quad that this quad needs to be after + if (insertAfter == -1) { + // insert at the start + forwards[quadIndex] = start; + backwards[quadIndex] = -1; + backwards[start] = quadIndex; + start = quadIndex; + } else { + // insert after the identified quad + forwards[quadIndex] = forwards[insertAfter]; + backwards[quadIndex] = insertAfter; + forwards[insertAfter] = quadIndex; + if (forwards[quadIndex] != -1) { + backwards[forwards[quadIndex]] = quadIndex; + } else { + end = quadIndex; + } + } + } + + // write the sorted quads to the buffer + for (int i = 0; i < activeQuads; i++) { + TranslucentData.putMappedQuadVertexIndexes(indexBuffer, start, activeToRealIndex); + start = forwards[start]; + } + + // detect cycles + if (start != -1) { + return false; + } + + return true; + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java index 3761811e8f..2d47f7f1b6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java @@ -65,12 +65,9 @@ public Int2ReferenceLinkedOpenHashMap getUnalignedDistances() public void sort(Vector3fc cameraPos) { IntBuffer indexBuffer = this.buffer.getDirectBuffer().asIntBuffer(); - if (this.unalignedDistances == null || this.unalignedDistances.isEmpty()) { - // TODO: this throws because something is breaking it, either a mistake in the - // algorithm or a violation of the assumptions - ComplexSorting.topoSortAlignedAcyclicSafe(indexBuffer, this.quads, cameraPos); - } else { - ComplexSorting.distanceSortModified(indexBuffer, this.quads, cameraPos); + if (!ComplexSorting.topoSortFullGraphAcyclic(indexBuffer, this.quads, cameraPos)) { + // if a camera position is given, no cycle should be possible + throw new IllegalStateException("Failed to sort"); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java index da826baf5e..2e9d686108 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java @@ -21,7 +21,9 @@ static StaticTopoAcyclicData fromMesh(BuiltSectionMeshParts translucentMesh, var buffer = new NativeBuffer(TranslucentData.vertexCountToIndexBytes(range.vertexCount())); var indexBuffer = buffer.getDirectBuffer().asIntBuffer(); - ComplexSorting.topoSortAlignedAcyclicSafe(indexBuffer, quads, null); + if (!ComplexSorting.topoSortFullGraphAcyclic(indexBuffer, quads, null)) { + System.out.println("Failed to sort topo static because there was a cycle"); + } return new StaticTopoAcyclicData(sectionPos, buffer, range); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java index bb65ab81c5..87dfe7b6c4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java @@ -39,6 +39,14 @@ static int quadCountToIndexBytes(int quadCount) { return quadCount * INDICES_PER_QUAD * BYTES_PER_INDEX; } + static void putMappedQuadVertexIndexes(IntBuffer intBuffer, int quadIndex, int[] indexMapping) { + if (indexMapping == null) { + putQuadVertexIndexes(intBuffer, quadIndex); + } else { + putQuadVertexIndexes(intBuffer, indexMapping[quadIndex]); + } + } + static void putQuadVertexIndexes(IntBuffer intBuffer, int quadIndex) { int vertexOffset = quadIndex * VERTICES_PER_QUAD; From 07559a133f9639c1041f267b7fb945936bd5229c Mon Sep 17 00:00:00 2001 From: douira Date: Sun, 24 Sep 2023 14:54:54 +0200 Subject: [PATCH 061/256] fix issues with sorting 1-long sections --- .../render/chunk/gfni/ComplexSorting.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java index a23c2e6ce9..de20b7c256 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java @@ -407,6 +407,28 @@ public static boolean topoSortFullGraphAcyclic(IntBuffer indexBuffer, TQuad[] al activeQuads = allQuads.length; } + // special case for 0 or 1 quads because the algorithm below doesn't work for + // those cases (and it's just faster to skip it) + if (activeQuads == 0) { + return true; + } + if (activeQuads == 1) { + TranslucentData.putMappedQuadVertexIndexes(indexBuffer, 0, activeToRealIndex); + return true; + } + + // special case 2 quads for performance + if (activeQuads == 2) { + var a = 0; + var b = 1; + if (quadVisibleThrough(quads[a], quads[b])) { + a = 1; + b = 0; + } + TranslucentData.putMappedQuadVertexIndexes(indexBuffer, a, activeToRealIndex); + TranslucentData.putMappedQuadVertexIndexes(indexBuffer, b, activeToRealIndex); + } + // int-based doubly linked list of active quad indexes int[] forwards = new int[activeQuads]; int[] backwards = new int[activeQuads]; From 1cc32c51578d5792e9e679f11e4dd3937eb59ae7 Mon Sep 17 00:00:00 2001 From: douira Date: Sun, 24 Sep 2023 19:18:19 +0200 Subject: [PATCH 062/256] remove end of list tracking --- .../mods/sodium/client/render/chunk/gfni/ComplexSorting.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java index de20b7c256..d153f630d9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java @@ -433,7 +433,6 @@ public static boolean topoSortFullGraphAcyclic(IntBuffer indexBuffer, TQuad[] al int[] forwards = new int[activeQuads]; int[] backwards = new int[activeQuads]; int start = 0; - int end = activeQuads - 1; // TODO: this is not used, remove? for (int i = 0; i < activeQuads - 1; i++) { forwards[i] = i + 1; backwards[i + 1] = i; @@ -462,8 +461,6 @@ public static boolean topoSortFullGraphAcyclic(IntBuffer indexBuffer, TQuad[] al int currentBackward = backwards[quadIndex]; if (currentForward != -1) { backwards[currentForward] = currentBackward; - } else { - end = currentBackward; } if (currentBackward != -1) { forwards[currentBackward] = currentForward; @@ -485,8 +482,6 @@ public static boolean topoSortFullGraphAcyclic(IntBuffer indexBuffer, TQuad[] al forwards[insertAfter] = quadIndex; if (forwards[quadIndex] != -1) { backwards[forwards[quadIndex]] = quadIndex; - } else { - end = quadIndex; } } } From 1684ac13184d1bcca0fa18e1d5ad4ffd6fafe3ea Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 25 Sep 2023 01:03:57 +0200 Subject: [PATCH 063/256] fix missing return that leads to buffer overflow --- .../mods/sodium/client/render/chunk/gfni/ComplexSorting.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java index d153f630d9..0f5f4a4284 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java @@ -427,6 +427,7 @@ public static boolean topoSortFullGraphAcyclic(IntBuffer indexBuffer, TQuad[] al } TranslucentData.putMappedQuadVertexIndexes(indexBuffer, a, activeToRealIndex); TranslucentData.putMappedQuadVertexIndexes(indexBuffer, b, activeToRealIndex); + return true; } // int-based doubly linked list of active quad indexes From 7a714e957396f888cd74abed88c76f593ff3f30d Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 25 Sep 2023 01:04:31 +0200 Subject: [PATCH 064/256] fully disable translucent sorting with option OFF also disable data collection in renderers when off --- .../render/chunk/compile/ChunkSortOutput.java | 5 ----- .../chunk/compile/pipeline/BlockRenderer.java | 5 +---- .../chunk/compile/pipeline/FluidRenderer.java | 5 +---- .../compile/tasks/ChunkBuilderMeshingTask.java | 18 ++++++++++++++---- .../client/render/chunk/gfni/GroupBuilder.java | 4 +++- 5 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java index 84fbbc6fbc..1802249dda 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java @@ -3,10 +3,6 @@ import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; import me.jellysquid.mods.sodium.client.render.chunk.gfni.TranslucentData; -/** - * TODO: translucent data can also be for non-dynamic sort types, so this might - * not make a lot of sense as it is. - */ public class ChunkSortOutput extends BuilderTaskOutput { public final TranslucentData translucentData; @@ -16,7 +12,6 @@ public ChunkSortOutput(RenderSection render, int buildTime, TranslucentData tran this.translucentData = translucentData; } - @Override public void deleteAfterUpload() { super.deleteAfterUpload(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java index 420f48c659..aa33c487bf 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java @@ -147,9 +147,6 @@ private void writeGeometry(BlockRenderContext ctx, ModelQuadFacing normalFace = quad.getNormalFace(); - // if translucent, add this face to the GFNI group builder - boolean isTranslucent = material == DefaultMaterials.TRANSLUCENT; - for (int dstIndex = 0; dstIndex < 4; dstIndex++) { int srcIndex = orientation.getVertexIndex(dstIndex); @@ -166,7 +163,7 @@ private void writeGeometry(BlockRenderContext ctx, out.light = light.lm[srcIndex]; } - if (isTranslucent) { + if (material == DefaultMaterials.TRANSLUCENT && ctx.groupBuilder != null) { ctx.groupBuilder.appendQuad(quad, vertices, normalFace); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java index 50df5686c0..d6707b00d6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java @@ -404,9 +404,6 @@ private void writeQuad(ChunkModelBuilder builder, GroupBuilder groupBuilder, Mat ModelQuadFacing facing, boolean flip) { var vertices = this.vertices; - // if translucent, add this face to the GFNI group builder - boolean isTranslucent = material == DefaultMaterials.TRANSLUCENT; - for (int i = 0; i < 4; i++) { var out = vertices[flip ? 3 - i : i]; out.x = offset.getX() + quad.getX(i); @@ -425,7 +422,7 @@ private void writeQuad(ChunkModelBuilder builder, GroupBuilder groupBuilder, Mat builder.addSprite(sprite); } - if (isTranslucent) { + if (material == DefaultMaterials.TRANSLUCENT && groupBuilder != null) { if (facing == ModelQuadFacing.UNASSIGNED) { // calculate the current GFNI normal but not the unit normal quad.calculateNormals(false); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java index 8de94ff7a1..90e8184d27 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java @@ -1,6 +1,8 @@ package me.jellysquid.mods.sodium.client.render.chunk.compile.tasks; import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; +import me.jellysquid.mods.sodium.client.SodiumClientMod; +import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions.SortBehavior; import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildBuffers; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildContext; @@ -74,7 +76,10 @@ public ChunkBuildOutput execute(ChunkBuildContext buildContext, CancellationToke BlockPos.Mutable blockPos = new BlockPos.Mutable(minX, minY, minZ); BlockPos.Mutable modelOffset = new BlockPos.Mutable(); - GroupBuilder groupBuilder = new GroupBuilder(render.getPosition()); + GroupBuilder groupBuilder = null; + if (SodiumClientMod.options().performance.sortBehavior != SortBehavior.NONE) { + groupBuilder = new GroupBuilder(render.getPosition()); + } BlockRenderContext context = new BlockRenderContext(slice, groupBuilder); try { @@ -137,7 +142,10 @@ public ChunkBuildOutput execute(ChunkBuildContext buildContext, CancellationToke throw fillCrashInfo(CrashReport.create(ex, "Encountered exception while building chunk meshes"), slice, blockPos); } - SortType sortType = groupBuilder.finishRendering(); + SortType sortType = SortType.NONE; + if (groupBuilder != null) { + sortType = groupBuilder.finishRendering(); + } Map meshes = new Reference2ReferenceOpenHashMap<>(); @@ -153,8 +161,10 @@ public ChunkBuildOutput execute(ChunkBuildContext buildContext, CancellationToke } } - TranslucentData translucentData = groupBuilder.getTranslucentData( - meshes.get(DefaultTerrainRenderPasses.TRANSLUCENT), cameraPos); + TranslucentData translucentData = null; + if (groupBuilder != null) { + groupBuilder.getTranslucentData(meshes.get(DefaultTerrainRenderPasses.TRANSLUCENT), cameraPos); + } renderData.setOcclusionData(occluder.build()); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java index 22df7122df..bb196c4e84 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java @@ -31,6 +31,8 @@ * heuristic doesn't expect it to be possible. The caveat is that this costs * doing it once without invisible quad exclusion and once with if the first * attempt fails. + * - disable translucent data collection when setting is set to OFF to prevent + * overhead if no sorting is wanted. */ public class GroupBuilder { private static final Vector3fc[] ALIGNED_NORMALS = new Vector3fc[ModelQuadFacing.DIRECTIONS]; @@ -169,7 +171,7 @@ public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] verti * Filters the given sort type to fit within the selected sorting mode. If it * doesn't match, then it's set to the NONE sort type. * - * @param sortType the sort type to filter + * @param sortType the sort type to filter */ private static SortType filterSortType(SortType sortType) { SortBehavior sortBehavior = SodiumClientMod.options().performance.sortBehavior; From 6c5e18083eb4c180da3336a95e497e4ccd2872de Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 25 Sep 2023 01:31:45 +0200 Subject: [PATCH 065/256] fix translucent data not being returned from builder threads --- .../sodium/client/render/chunk/RenderSectionManager.java | 7 ++++--- .../client/render/chunk/compile/ChunkSortOutput.java | 2 +- .../chunk/compile/tasks/ChunkBuilderMeshingTask.java | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index 82c91a52eb..111acd17f4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -283,11 +283,12 @@ public void updateChunks(boolean updateImmediately) { var blockingRebuilds = new ChunkJobCollector(Integer.MAX_VALUE, this.buildResults::add); var deferredRebuilds = new ChunkJobCollector(this.builder.getSchedulingBudget(), this.buildResults::add); + var optionallyBlockingCollector = updateImmediately ? blockingRebuilds : deferredRebuilds; this.submitSectionTasks(blockingRebuilds, ChunkUpdateType.IMPORTANT_REBUILD); - this.submitSectionTasks(updateImmediately ? blockingRebuilds : deferredRebuilds, ChunkUpdateType.REBUILD); - this.submitSectionTasks(updateImmediately ? blockingRebuilds : deferredRebuilds, ChunkUpdateType.INITIAL_BUILD); - this.submitSectionTasks(updateImmediately ? blockingRebuilds : deferredRebuilds, ChunkUpdateType.TRANSLUCENT_SORT); + this.submitSectionTasks(optionallyBlockingCollector, ChunkUpdateType.REBUILD); + this.submitSectionTasks(optionallyBlockingCollector, ChunkUpdateType.INITIAL_BUILD); + this.submitSectionTasks(optionallyBlockingCollector, ChunkUpdateType.TRANSLUCENT_SORT); blockingRebuilds.awaitCompletion(this.builder); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java index 1802249dda..f8e5995999 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java @@ -17,7 +17,7 @@ public void deleteAfterUpload() { super.deleteAfterUpload(); // delete translucent data if it's not persisted for dynamic sorting - if (this.translucentData != null && !translucentData.getSortType().needsPlaneTrigger) { + if (this.translucentData != null && !this.translucentData.getSortType().needsPlaneTrigger) { this.translucentData.delete(); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java index 90e8184d27..1c407c5369 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java @@ -163,7 +163,7 @@ public ChunkBuildOutput execute(ChunkBuildContext buildContext, CancellationToke TranslucentData translucentData = null; if (groupBuilder != null) { - groupBuilder.getTranslucentData(meshes.get(DefaultTerrainRenderPasses.TRANSLUCENT), cameraPos); + translucentData = groupBuilder.getTranslucentData(meshes.get(DefaultTerrainRenderPasses.TRANSLUCENT), cameraPos); } renderData.setOcclusionData(occluder.build()); From 5197f26b6f2c6e70a50c49ea675c3ed1dff170d7 Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 25 Sep 2023 01:36:40 +0200 Subject: [PATCH 066/256] explicitly use NONE and remove unnecessary enum field --- .../jellysquid/mods/sodium/client/gui/SodiumGameOptions.java | 2 -- .../mods/sodium/client/render/chunk/DefaultChunkRenderer.java | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java index ca520449b2..0d851b0293 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java @@ -60,13 +60,11 @@ public enum SortBehavior implements TextProvider { private final Text name; public final Set sortTypes; public final boolean needsPlaneTrigger; - public final boolean needsIndexBuffer; SortBehavior(String name, Set sortTypes) { this.name = Text.translatable(name); this.sortTypes = sortTypes; this.needsPlaneTrigger = sortTypes.stream().anyMatch(type -> type.needsPlaneTrigger); - this.needsIndexBuffer = sortTypes.stream().anyMatch(type -> type.needsIndexBuffer); } @Override diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java index 1c736a7e59..8c2251372b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java @@ -10,6 +10,7 @@ import me.jellysquid.mods.sodium.client.gl.tessellation.GlPrimitiveType; import me.jellysquid.mods.sodium.client.gl.tessellation.GlTessellation; import me.jellysquid.mods.sodium.client.gl.tessellation.TessellationBinding; +import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions.SortBehavior; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.render.chunk.data.SectionRenderDataStorage; import me.jellysquid.mods.sodium.client.render.chunk.data.SectionRenderDataUnsafe; @@ -51,7 +52,7 @@ public void render(ChunkRenderMatrices matrices, // TODO: also disable this if there is only NONE-type sorting or no translucent geometry in the region boolean isTranslucent = renderPass == DefaultTerrainRenderPasses.TRANSLUCENT - && SodiumClientMod.options().performance.sortBehavior.needsIndexBuffer; + && SodiumClientMod.options().performance.sortBehavior != SortBehavior.NONE; boolean useBlockFaceCulling = SodiumClientMod.options().performance.useBlockFaceCulling; ChunkShaderInterface shader = this.activeProgram.getInterface(); From d0e719eb38309f24574e4563ec0d2ca179f9fcae Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 25 Sep 2023 02:13:43 +0200 Subject: [PATCH 067/256] add index buffer generation for sections where sorting doesn't matter --- .../render/chunk/gfni/AnyOrderData.java | 37 +++++++++++++++++++ .../chunk/gfni/DynamicTopoCyclicData.java | 6 +-- .../render/chunk/gfni/GroupBuilder.java | 11 ++++-- .../render/chunk/gfni/MixedDirectionData.java | 9 +++++ .../client/render/chunk/gfni/NoData.java | 21 +++++++++++ .../client/render/chunk/gfni/NoneData.java | 25 ------------- .../chunk/gfni/PresentTranslucentData.java | 7 ++++ .../render/chunk/gfni/SplitDirectionData.java | 19 ++++++++++ .../chunk/gfni/StaticNormalRelativeData.java | 7 +--- .../render/chunk/gfni/TranslucentData.java | 1 + .../chunk/region/RenderRegionManager.java | 22 +---------- 11 files changed, 109 insertions(+), 56 deletions(-) create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AnyOrderData.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NoData.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NoneData.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/SplitDirectionData.java diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AnyOrderData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AnyOrderData.java new file mode 100644 index 0000000000..537ee3d63f --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AnyOrderData.java @@ -0,0 +1,37 @@ +package me.jellysquid.mods.sodium.client.render.chunk.gfni; + +import me.jellysquid.mods.sodium.client.gl.util.VertexRange; +import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; +import me.jellysquid.mods.sodium.client.util.NativeBuffer; +import net.minecraft.util.math.ChunkSectionPos; + +/** + * With this sort type the section's translucent quads can be rendered in any + * order. However, they do need to be rendered with some index buffer, so that + * vertices are assembled into quads. Since the sort order doesn't matter, all + * sections with this sort type can share the same data in the index buffer. + * + * TODO: share the buffer on the CPU and on the GPU. This is essentially the + * same as SharedQuadIndexBuffer but it has to be compatible with sections in + * the same region using custom index buffers. + */ +public class AnyOrderData extends SplitDirectionData { + AnyOrderData(ChunkSectionPos sectionPos, NativeBuffer buffer, VertexRange[] ranges) { + super(sectionPos, buffer, ranges); + } + + @Override + public SortType getSortType() { + return SortType.NONE; + } + + static AnyOrderData fromMesh(BuiltSectionMeshParts translucentMesh, + TQuad[] quads, ChunkSectionPos sectionPos) { + var buffer = PresentTranslucentData.nativeBufferForQuads(quads); + var indexBuffer = buffer.getDirectBuffer().asIntBuffer(); + for (int i = 0; i < quads.length; i++) { + TranslucentData.putQuadVertexIndexes(indexBuffer, i); + } + return new AnyOrderData(sectionPos, buffer, translucentMesh.getVertexRanges()); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicTopoCyclicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicTopoCyclicData.java index a0acd7e2c6..d360101e91 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicTopoCyclicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicTopoCyclicData.java @@ -10,15 +10,15 @@ /** * TODO: implement */ -public class DynamicTopoCyclicData extends PresentTranslucentData { +public class DynamicTopoCyclicData extends MixedDirectionData { public final ReferenceArrayList orders; public static record SortOrder(VertexRange range, Vector3fc normal, double distance) { } public DynamicTopoCyclicData(ChunkSectionPos sectionPos, - NativeBuffer buffer, ReferenceArrayList orders) { - super(sectionPos, buffer); + NativeBuffer buffer, VertexRange range, ReferenceArrayList orders) { + super(sectionPos, buffer, range); this.orders = orders; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java index bb196c4e84..d3392dff89 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java @@ -340,8 +340,13 @@ public SortType finishRendering() { } public TranslucentData getTranslucentData(BuiltSectionMeshParts translucentMesh, Vector3fc cameraPos) { - if (this.sortType == SortType.NONE || translucentMesh == null) { - return new NoneData(this.sectionPos); + // means there is no translucent geometry + if (translucentMesh == null) { + return new NoData(sectionPos); + } + + if (this.sortType == SortType.NONE) { + return AnyOrderData.fromMesh(translucentMesh, quads, sectionPos); } if (this.sortType == SortType.STATIC_NORMAL_RELATIVE) { @@ -363,7 +368,7 @@ public TranslucentData getTranslucentData(BuiltSectionMeshParts translucentMesh, this.sortType = filterSortType(this.sortType); if (this.sortType == SortType.NONE) { - return new NoneData(this.sectionPos); + return AnyOrderData.fromMesh(translucentMesh, quads, sectionPos); } if (this.sortType == SortType.DYNAMIC_ALL) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/MixedDirectionData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/MixedDirectionData.java index 7417acfad8..98e02e8385 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/MixedDirectionData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/MixedDirectionData.java @@ -1,6 +1,7 @@ package me.jellysquid.mods.sodium.client.render.chunk.gfni; import me.jellysquid.mods.sodium.client.gl.util.VertexRange; +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.util.NativeBuffer; import net.minecraft.util.math.ChunkSectionPos; @@ -11,4 +12,12 @@ public abstract class MixedDirectionData extends PresentTranslucentData { super(sectionPos, buffer); this.range = range; } + + @Override + public VertexRange[] getVertexRanges() { + // TODO: cache this array? + var ranges = new VertexRange[ModelQuadFacing.COUNT]; + ranges[ModelQuadFacing.UNASSIGNED.ordinal()] = this.range; + return ranges; + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NoData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NoData.java new file mode 100644 index 0000000000..d474c347a9 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NoData.java @@ -0,0 +1,21 @@ +package me.jellysquid.mods.sodium.client.render.chunk.gfni; + +import net.minecraft.util.math.ChunkSectionPos; + +/** + * This class means there is no translucent data and is used to signal to GFNI + * to remove the section from the triggering structure. + * + * If no translucent sorting is being performed, not even this class is used but + * null is passed instead. + */ +public class NoData extends TranslucentData { + public NoData(ChunkSectionPos sectionPos) { + super(sectionPos); + } + + @Override + public SortType getSortType() { + return SortType.NONE; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NoneData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NoneData.java deleted file mode 100644 index 1bcdd02d16..0000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NoneData.java +++ /dev/null @@ -1,25 +0,0 @@ -package me.jellysquid.mods.sodium.client.render.chunk.gfni; - -import net.minecraft.util.math.ChunkSectionPos; - -/** - * None translucent data exists to signal to GFNI that if a section previously - * had triggering data, it no longer does and should be removed. - * - * With this sort type the section's translucent quads can be rendered in any - * order. However, they do need to be rendered with some index buffer, so that - * vertices are assembled into quads. Since the sort order doesn't matter, all - * sections with this sort type can share the same data in the index buffer. - * - * TODO: make shared NoneData in the SectionRenderDataStorage or sth - */ -public class NoneData extends TranslucentData { - public NoneData(ChunkSectionPos sectionPos) { - super(sectionPos); - } - - @Override - public SortType getSortType() { - return SortType.NONE; - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/PresentTranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/PresentTranslucentData.java index 2493c60958..aea6b0895d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/PresentTranslucentData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/PresentTranslucentData.java @@ -1,5 +1,6 @@ package me.jellysquid.mods.sodium.client.render.chunk.gfni; +import me.jellysquid.mods.sodium.client.gl.util.VertexRange; import me.jellysquid.mods.sodium.client.util.NativeBuffer; import net.minecraft.util.math.ChunkSectionPos; @@ -11,6 +12,8 @@ public abstract class PresentTranslucentData extends TranslucentData { this.buffer = buffer; } + public abstract VertexRange[] getVertexRanges(); + @Override public void delete() { super.delete(); @@ -19,4 +22,8 @@ public void delete() { this.buffer = null; } } + + static NativeBuffer nativeBufferForQuads(TQuad[] quads) { + return new NativeBuffer(TranslucentData.quadCountToIndexBytes(quads.length)); + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/SplitDirectionData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/SplitDirectionData.java new file mode 100644 index 0000000000..5aa0823760 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/SplitDirectionData.java @@ -0,0 +1,19 @@ +package me.jellysquid.mods.sodium.client.render.chunk.gfni; + +import me.jellysquid.mods.sodium.client.gl.util.VertexRange; +import me.jellysquid.mods.sodium.client.util.NativeBuffer; +import net.minecraft.util.math.ChunkSectionPos; + +public abstract class SplitDirectionData extends PresentTranslucentData { + public final VertexRange[] ranges; + + public SplitDirectionData(ChunkSectionPos sectionPos, NativeBuffer buffer, VertexRange[] ranges) { + super(sectionPos, buffer); + this.ranges = ranges; + } + + @Override + public VertexRange[] getVertexRanges() { + return this.ranges; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java index 522f2cb408..bc5861f9db 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java @@ -14,12 +14,9 @@ import me.jellysquid.mods.sodium.client.util.sorting.VertexSorters; import net.minecraft.util.math.ChunkSectionPos; -public class StaticNormalRelativeData extends PresentTranslucentData { - public final VertexRange[] ranges; - +public class StaticNormalRelativeData extends SplitDirectionData { public StaticNormalRelativeData(ChunkSectionPos sectionPos, NativeBuffer buffer, VertexRange[] ranges) { - super(sectionPos, buffer); - this.ranges = ranges; + super(sectionPos, buffer, ranges); } @Override diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java index 87dfe7b6c4..449b3629dc 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java @@ -22,6 +22,7 @@ public abstract class TranslucentData { public abstract SortType getSortType(); + public void delete() { } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java index 28d03066fc..d0ee7b6144 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java @@ -10,16 +10,12 @@ import me.jellysquid.mods.sodium.client.gl.arena.staging.StagingBuffer; import me.jellysquid.mods.sodium.client.gl.device.CommandList; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; -import me.jellysquid.mods.sodium.client.gl.util.VertexRange; -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; import me.jellysquid.mods.sodium.client.render.chunk.compile.BuilderTaskOutput; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildOutput; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkSortOutput; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; -import me.jellysquid.mods.sodium.client.render.chunk.gfni.MixedDirectionData; import me.jellysquid.mods.sodium.client.render.chunk.gfni.PresentTranslucentData; -import me.jellysquid.mods.sodium.client.render.chunk.gfni.StaticNormalRelativeData; import me.jellysquid.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses; import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; import org.jetbrains.annotations.NotNull; @@ -136,22 +132,8 @@ private void uploadResults(CommandList commandList, RenderRegion region, Collect for (PendingSectionIndexBufferUpload upload : indexUploads) { var storage = region.createTranslucentStorage(); - - // TODO: doesn't support DynamicTopoCyclicData yet because of SectionRenderDataStorage's internals - VertexRange[] vertexRanges = null; - var translucentData = upload.translucentData; - if (translucentData instanceof StaticNormalRelativeData data) { - vertexRanges = data.ranges; - } else if (translucentData instanceof MixedDirectionData data) { - vertexRanges = new VertexRange[ModelQuadFacing.COUNT]; - vertexRanges[ModelQuadFacing.UNASSIGNED.ordinal()] = data.range; - } else { - throw new UnsupportedOperationException("Unsupported translucent data type: " + translucentData.getClass()); - } - if (vertexRanges != null) { - storage.setMeshes(upload.section.getSectionIndex(), - upload.indexBufferUpload.getResult(), vertexRanges); - } + storage.setMeshes(upload.section.getSectionIndex(), + upload.indexBufferUpload.getResult(), upload.translucentData.getVertexRanges()); } } } From c1c3242949f9d537ea8a95853558589ea3edded4 Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 25 Sep 2023 02:14:23 +0200 Subject: [PATCH 068/256] formatting --- .../mods/sodium/client/render/chunk/gfni/TranslucentData.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java index 449b3629dc..87dfe7b6c4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java @@ -22,7 +22,6 @@ public abstract class TranslucentData { public abstract SortType getSortType(); - public void delete() { } From bf89a385b7f3c94c5a99f869de86080077f742fe Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 25 Sep 2023 02:53:37 +0200 Subject: [PATCH 069/256] rename group builder to TranslucentGeometryCollector --- .../sodium/client/gui/SodiumGameOptions.java | 2 -- .../compile/pipeline/BlockRenderContext.java | 8 ++++---- .../chunk/compile/pipeline/BlockRenderer.java | 4 ++-- .../chunk/compile/pipeline/FluidRenderer.java | 20 +++++++++---------- .../tasks/ChunkBuilderMeshingTask.java | 18 ++++++++--------- .../render/chunk/gfni/AccumulationGroup.java | 6 +++--- .../client/render/chunk/gfni/DynamicData.java | 12 +++++------ .../sodium/client/render/chunk/gfni/GFNI.java | 16 +++++++-------- .../client/render/chunk/gfni/Group.java | 4 ++-- .../client/render/chunk/gfni/NormalList.java | 16 +++++++-------- .../chunk/gfni/StaticNormalRelativeData.java | 8 ++++---- ...java => TranslucentGeometryCollector.java} | 15 +++++++------- 12 files changed, 64 insertions(+), 65 deletions(-) rename src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/{GroupBuilder.java => TranslucentGeometryCollector.java} (96%) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java index 0d851b0293..772542ddd8 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java @@ -59,12 +59,10 @@ public enum SortBehavior implements TextProvider { private final Text name; public final Set sortTypes; - public final boolean needsPlaneTrigger; SortBehavior(String name, Set sortTypes) { this.name = Text.translatable(name); this.sortTypes = sortTypes; - this.needsPlaneTrigger = sortTypes.stream().anyMatch(type -> type.needsPlaneTrigger); } @Override diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderContext.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderContext.java index 7f8c8b36f3..7c14942e86 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderContext.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderContext.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline; -import me.jellysquid.mods.sodium.client.render.chunk.gfni.GroupBuilder; +import me.jellysquid.mods.sodium.client.render.chunk.gfni.TranslucentGeometryCollector; import me.jellysquid.mods.sodium.client.world.WorldSlice; import net.minecraft.block.BlockState; import net.minecraft.client.render.model.BakedModel; @@ -10,7 +10,7 @@ public class BlockRenderContext { private final WorldSlice world; - public final GroupBuilder groupBuilder; + public final TranslucentGeometryCollector collector; private final BlockPos.Mutable pos = new BlockPos.Mutable(); @@ -22,9 +22,9 @@ public class BlockRenderContext { private long seed; - public BlockRenderContext(WorldSlice world, GroupBuilder groupBuilder) { + public BlockRenderContext(WorldSlice world, TranslucentGeometryCollector collector) { this.world = world; - this.groupBuilder = groupBuilder; + this.collector = collector; } public void update(BlockPos pos, BlockPos origin, BlockState state, BakedModel model, long seed) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java index aa33c487bf..69b67d9566 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java @@ -163,8 +163,8 @@ private void writeGeometry(BlockRenderContext ctx, out.light = light.lm[srcIndex]; } - if (material == DefaultMaterials.TRANSLUCENT && ctx.groupBuilder != null) { - ctx.groupBuilder.appendQuad(quad, vertices, normalFace); + if (material == DefaultMaterials.TRANSLUCENT && ctx.collector != null) { + ctx.collector.appendQuad(quad, vertices, normalFace); } var vertexBuffer = builder.getVertexBuffer(normalFace); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java index d6707b00d6..7f3159ab15 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java @@ -14,7 +14,7 @@ import me.jellysquid.mods.sodium.client.model.color.DefaultColorProviders; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildBuffers; import me.jellysquid.mods.sodium.client.render.chunk.compile.buffers.ChunkModelBuilder; -import me.jellysquid.mods.sodium.client.render.chunk.gfni.GroupBuilder; +import me.jellysquid.mods.sodium.client.render.chunk.gfni.TranslucentGeometryCollector; import me.jellysquid.mods.sodium.client.render.chunk.terrain.material.DefaultMaterials; import me.jellysquid.mods.sodium.client.render.chunk.terrain.material.Material; import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexEncoder; @@ -102,7 +102,7 @@ private boolean isSideExposed(BlockRenderView world, int x, int y, int z, Direct return true; } - public void render(WorldSlice world, FluidState fluidState, BlockPos blockPos, BlockPos offset, GroupBuilder groupBuilder, ChunkBuildBuffers buffers) { + public void render(WorldSlice world, FluidState fluidState, BlockPos blockPos, BlockPos offset, TranslucentGeometryCollector collector, ChunkBuildBuffers buffers) { var material = DefaultMaterials.forFluidState(fluidState); var meshBuilder = buffers.get(material); @@ -229,10 +229,10 @@ public void render(WorldSlice world, FluidState fluidState, BlockPos blockPos, B setVertex(quad, 3, 1.0F, northEastHeight, 0.0f, u4, v4); this.updateQuad(quad, world, blockPos, lighter, Direction.UP, 1.0F, colorProvider, fluidState); - this.writeQuad(meshBuilder, groupBuilder, material, offset, quad, facing, false); + this.writeQuad(meshBuilder, collector, material, offset, quad, facing, false); if (fluidState.canFlowTo(world, this.scratchPos.set(posX, posY + 1, posZ))) { - this.writeQuad(meshBuilder, groupBuilder, material, offset, quad, + this.writeQuad(meshBuilder, collector, material, offset, quad, ModelQuadFacing.NEG_Y, true); } @@ -254,7 +254,7 @@ public void render(WorldSlice world, FluidState fluidState, BlockPos blockPos, B setVertex(quad, 3, 1.0F, yOffset, 1.0F, maxU, maxV); this.updateQuad(quad, world, blockPos, lighter, Direction.DOWN, 1.0F, colorProvider, fluidState); - this.writeQuad(meshBuilder, groupBuilder, material, offset, quad, ModelQuadFacing.NEG_Y, false); + this.writeQuad(meshBuilder, collector, material, offset, quad, ModelQuadFacing.NEG_Y, false); } @@ -355,10 +355,10 @@ public void render(WorldSlice world, FluidState fluidState, BlockPos blockPos, B ModelQuadFacing facing = ModelQuadFacing.fromDirection(dir); this.updateQuad(quad, world, blockPos, lighter, dir, br, colorProvider, fluidState); - this.writeQuad(meshBuilder, groupBuilder, material, offset, quad, facing, false); + this.writeQuad(meshBuilder, collector, material, offset, quad, facing, false); if (!isOverlay) { - this.writeQuad(meshBuilder, groupBuilder, material, offset, quad, facing.getOpposite(), true); + this.writeQuad(meshBuilder, collector, material, offset, quad, facing.getOpposite(), true); } } @@ -400,7 +400,7 @@ private void updateQuad(ModelQuadView quad, WorldSlice world, BlockPos pos, Ligh } } - private void writeQuad(ChunkModelBuilder builder, GroupBuilder groupBuilder, Material material, BlockPos offset, ModelQuadView quad, + private void writeQuad(ChunkModelBuilder builder, TranslucentGeometryCollector collector, Material material, BlockPos offset, ModelQuadView quad, ModelQuadFacing facing, boolean flip) { var vertices = this.vertices; @@ -422,12 +422,12 @@ private void writeQuad(ChunkModelBuilder builder, GroupBuilder groupBuilder, Mat builder.addSprite(sprite); } - if (material == DefaultMaterials.TRANSLUCENT && groupBuilder != null) { + if (material == DefaultMaterials.TRANSLUCENT && collector != null) { if (facing == ModelQuadFacing.UNASSIGNED) { // calculate the current GFNI normal but not the unit normal quad.calculateNormals(false); } - groupBuilder.appendQuad(quad, vertices, facing); + collector.appendQuad(quad, vertices, facing); } var vertexBuffer = builder.getVertexBuffer(facing); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java index 1c407c5369..288cff9601 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java @@ -11,7 +11,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.BlockRenderContext; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionInfo; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; -import me.jellysquid.mods.sodium.client.render.chunk.gfni.GroupBuilder; +import me.jellysquid.mods.sodium.client.render.chunk.gfni.TranslucentGeometryCollector; import me.jellysquid.mods.sodium.client.render.chunk.gfni.SortType; import me.jellysquid.mods.sodium.client.render.chunk.gfni.TranslucentData; import me.jellysquid.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses; @@ -76,11 +76,11 @@ public ChunkBuildOutput execute(ChunkBuildContext buildContext, CancellationToke BlockPos.Mutable blockPos = new BlockPos.Mutable(minX, minY, minZ); BlockPos.Mutable modelOffset = new BlockPos.Mutable(); - GroupBuilder groupBuilder = null; + TranslucentGeometryCollector collector = null; if (SodiumClientMod.options().performance.sortBehavior != SortBehavior.NONE) { - groupBuilder = new GroupBuilder(render.getPosition()); + collector = new TranslucentGeometryCollector(render.getPosition()); } - BlockRenderContext context = new BlockRenderContext(slice, groupBuilder); + BlockRenderContext context = new BlockRenderContext(slice, collector); try { for (int y = minY; y < maxY; y++) { @@ -113,7 +113,7 @@ public ChunkBuildOutput execute(ChunkBuildContext buildContext, CancellationToke FluidState fluidState = blockState.getFluidState(); if (!fluidState.isEmpty()) { - cache.getFluidRenderer().render(slice, fluidState, blockPos, modelOffset, groupBuilder, buffers); + cache.getFluidRenderer().render(slice, fluidState, blockPos, modelOffset, collector, buffers); } if (blockState.hasBlockEntity()) { @@ -143,8 +143,8 @@ public ChunkBuildOutput execute(ChunkBuildContext buildContext, CancellationToke } SortType sortType = SortType.NONE; - if (groupBuilder != null) { - sortType = groupBuilder.finishRendering(); + if (collector != null) { + sortType = collector.finishRendering(); } Map meshes = new Reference2ReferenceOpenHashMap<>(); @@ -162,8 +162,8 @@ public ChunkBuildOutput execute(ChunkBuildContext buildContext, CancellationToke } TranslucentData translucentData = null; - if (groupBuilder != null) { - translucentData = groupBuilder.getTranslucentData(meshes.get(DefaultTerrainRenderPasses.TRANSLUCENT), cameraPos); + if (collector != null) { + translucentData = collector.getTranslucentData(meshes.get(DefaultTerrainRenderPasses.TRANSLUCENT), cameraPos); } renderData.setOcclusionData(occluder.build()); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AccumulationGroup.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AccumulationGroup.java index 76eec1e571..caa489f80a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AccumulationGroup.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AccumulationGroup.java @@ -11,17 +11,17 @@ class AccumulationGroup { final DoubleOpenHashSet relativeDistances = new DoubleOpenHashSet(16); final Vector3fc normal; - final int groupBuilderKey; + final int collectorKey; final ChunkSectionPos sectionPos; long relDistanceHash = 0; private double relMinDistance = Double.POSITIVE_INFINITY; private double relMaxDistance = Double.NEGATIVE_INFINITY; - AccumulationGroup(ChunkSectionPos sectionPos, Vector3fc normal, int groupBuilderKey) { + AccumulationGroup(ChunkSectionPos sectionPos, Vector3fc normal, int collectorKey) { this.sectionPos = sectionPos; this.normal = normal; - this.groupBuilderKey = groupBuilderKey; + this.collectorKey = collectorKey; } boolean addPlaneMember(float vertexX, float vertexY, float vertexZ) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java index 2d47f7f1b6..80e9920f70 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java @@ -39,17 +39,17 @@ public SortType getSortType() { } AccumulationGroup getGroupForNormal(NormalList normalList) { - int groupBuilderKey = normalList.getGroupBuilderKey(); - if (groupBuilderKey < 0xFF) { + int collectorKey = normalList.getCollectorKey(); + if (collectorKey < 0xFF) { if (this.axisAlignedDistances == null) { return null; } - return this.axisAlignedDistances[groupBuilderKey]; + return this.axisAlignedDistances[collectorKey]; } else { if (this.unalignedDistances == null) { return null; } - return this.unalignedDistances.get(groupBuilderKey); + return this.unalignedDistances.get(collectorKey); } } @@ -72,13 +72,13 @@ public void sort(Vector3fc cameraPos) { } static DynamicData fromMesh(BuiltSectionMeshParts translucentMesh, - Vector3fc cameraPos, TQuad[] quads, ChunkSectionPos sectionPos, GroupBuilder groupBuilder) { + Vector3fc cameraPos, TQuad[] quads, ChunkSectionPos sectionPos, TranslucentGeometryCollector collector) { VertexRange range = TranslucentData.getUnassignedVertexRange(translucentMesh); var buffer = new NativeBuffer(TranslucentData.quadCountToIndexBytes(quads.length)); var dynamicData = new DynamicData(sectionPos, buffer, range, quads, - groupBuilder.axisAlignedDistances, groupBuilder.unalignedDistances); + collector.axisAlignedDistances, collector.unalignedDistances); dynamicData.sort(cameraPos); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java index c05adf5a29..00990e10c1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java @@ -119,9 +119,9 @@ public void triggerSections( triggerSectionCallback = null; } - void triggerSection(ChunkSectionPos section, int groupBuilderKey) { + void triggerSection(ChunkSectionPos section, int collectorKey) { this.triggeredSections.add(section.asLong()); - this.triggeredNormals.add(groupBuilderKey); + this.triggeredNormals.add(collectorKey); // by simply setting a chunk update type on the section, it naturally only gets // updated once the section becomes visible. @@ -160,19 +160,19 @@ private void addSectionInNewNormalLists(AccumulationGroup accGroup) { var normal = accGroup.normal; var normalList = this.normalLists.get(normal); if (normalList == null) { - normalList = new NormalList(normal, accGroup.groupBuilderKey); + normalList = new NormalList(normal, accGroup.collectorKey); this.normalLists.put(normal, normalList); normalList.addSection(accGroup, accGroup.sectionPos.asLong()); } } /** - * Integrates the data from a group builder into GFNI. The group builder + * Integrates the data from a geometry collector into GFNI. The geometry collector * contains the translucent face planes of a single section. This method may * also remove the section if it has become irrelevant. * - * @param builder the group builder to integrate - * @return the sort type that the group builder's relevance heuristic determined + * @param builder the geometry collector to integrate + * @return the sort type that the geometry collector's relevance heuristic determined */ public void integrateTranslucentData(TranslucentData oldTranslucentData, TranslucentData translucentData) { long chunkSectionLongPos = translucentData.sectionPos.asLong(); @@ -198,7 +198,7 @@ public void integrateTranslucentData(TranslucentData oldTranslucentData, Translu // builder has. if the normal list has data for the section, but the group // builder doesn't, the group is removed. otherwise, the group is updated. for (var normalList : this.normalLists.values()) { - // check if the group builder includes data for this normal. + // check if the geometry collector includes data for this normal. var accGroup = dynamicData.getGroupForNormal(normalList); if (normalList.hasSection(chunkSectionLongPos)) { if (accGroup == null) { @@ -211,7 +211,7 @@ public void integrateTranslucentData(TranslucentData oldTranslucentData, Translu } } - // go through the data of the group builder to check for data of new normals + // go through the data of the geometry collector to check for data of new normals // for which there are no normal lists yet. This only checks for new normal // lists since new data for existing normal lists is handled above. if (dynamicData.getAxisAlignedDistances() != null) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java index f43d90521e..0e976b1210 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java @@ -50,11 +50,11 @@ void replaceWith(AccumulationGroup accGroup, DoubleInterval accGroupDistances, d } } - void triggerRange(GFNI gfni, double start, double end, int groupBuilderKey) { + void triggerRange(GFNI gfni, double start, double end, int collectorKey) { // trigger self on the section if the query range overlaps with the group if (start < this.distances.getEnd() && end > this.distances.getStart() && !this.facePlaneDistances.subSet(start, end).isEmpty()) { - gfni.triggerSection(this.sectionPos, groupBuilderKey); + gfni.triggerSection(this.sectionPos, collectorKey); } } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java index 0ed9574f07..eb3c34135e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java @@ -41,12 +41,12 @@ class NormalList { /** * If this normal list is for an axis-aligned normal, this is the index of it - * for querying in {@link GroupBuilder#getGroupForNormal(Vector3fc)}. + * for querying in {@link TranslucentGeometryCollector#getGroupForNormal(Vector3fc)}. * * If this normal list is for an unaligned normal, this is the key for the * hash map of quantized normals. */ - private final int groupBuilderKey; + private final int collectorKey; /** * An interval tree of group intervals. Since this only stores intervals, the @@ -71,20 +71,20 @@ class NormalList { * normal index. * * @param normal The unit normal vector - * @param groupBuilderKey The group builder index + * @param collectorKey The geometry collector index */ - NormalList(Vector3fc normal, int groupBuilderKey) { + NormalList(Vector3fc normal, int collectorKey) { this.normalf = normal; this.normal = new Vector3d(normal); - this.groupBuilderKey = groupBuilderKey; + this.collectorKey = collectorKey; } Vector3fc getNormal() { return normalf; } - int getGroupBuilderKey() { - return groupBuilderKey; + int getCollectorKey() { + return collectorKey; } void processMovement(GFNI gfni, double lastCameraX, double lastCameraY, double lastCameraZ, @@ -104,7 +104,7 @@ void processMovement(GFNI gfni, double lastCameraX, double lastCameraY, double l var interval = new DoubleInterval(start, end, Bounded.CLOSED); for (Interval groupInterval : groupIntervals.query(interval)) { for (Group group : groupsByInterval.get(groupInterval)) { - group.triggerRange(gfni, start, end, this.groupBuilderKey); + group.triggerRange(gfni, start, end, this.collectorKey); } } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java index bc5861f9db..29d30b0811 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java @@ -37,7 +37,7 @@ public SortType getSortType() { } private static StaticNormalRelativeData fromDoubleUnaligned(BuiltSectionMeshParts translucentMesh, - TQuad[] quads, ChunkSectionPos sectionPos, GroupBuilder groupBuilder) { + TQuad[] quads, ChunkSectionPos sectionPos, TranslucentGeometryCollector collector) { VertexRange[] ranges = translucentMesh.getVertexRanges(); float[] keys = new float[quads.length]; @@ -105,9 +105,9 @@ private static StaticNormalRelativeData fromAligned(BuiltSectionMeshParts transl } static StaticNormalRelativeData fromMesh(BuiltSectionMeshParts translucentMesh, - TQuad[] quads, ChunkSectionPos sectionPos, GroupBuilder groupBuilder) { - if (groupBuilder.alignedNormalBitmap == 0) { - return fromDoubleUnaligned(translucentMesh, quads, sectionPos, groupBuilder); + TQuad[] quads, ChunkSectionPos sectionPos, TranslucentGeometryCollector collector) { + if (collector.alignedNormalBitmap == 0) { + return fromDoubleUnaligned(translucentMesh, quads, sectionPos, collector); } else { return fromAligned(translucentMesh, quads, sectionPos); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java similarity index 96% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java rename to src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java index d3392dff89..6dd996f79c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GroupBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java @@ -14,10 +14,11 @@ import net.minecraft.util.math.ChunkSectionPos; /** - * The group builder collects the data from the renderers and builds data - * structures for either dynamic triggering or static sorting. It determines the - * best sort type for the section and performs translucency visibility graph - * sorting with a topological sort algorithm if necessary. + * The translucent geometry collector collects the data from the renderers and + * builds data structures for either dynamic triggering or static sorting. It + * determines the best sort type for the section and constructs various types of + * translucent data objects that then perform sorting and get registered with + * GFNI for triggering. * * TODO: can use a bunch more optimizations, this is a prototype. * TODO list: @@ -34,7 +35,7 @@ * - disable translucent data collection when setting is set to OFF to prevent * overhead if no sorting is wanted. */ -public class GroupBuilder { +public class TranslucentGeometryCollector { private static final Vector3fc[] ALIGNED_NORMALS = new Vector3fc[ModelQuadFacing.DIRECTIONS]; private static final int OPPOSING_X = 1 << ModelQuadFacing.POS_X.ordinal() | 1 << ModelQuadFacing.NEG_X.ordinal(); @@ -64,7 +65,7 @@ public class GroupBuilder { private SortType sortType; - public GroupBuilder(ChunkSectionPos sectionPos) { + public TranslucentGeometryCollector(ChunkSectionPos sectionPos) { this.sectionPos = sectionPos; } @@ -182,7 +183,7 @@ private static SortType filterSortType(SortType sortType) { } /** - * Checks if this group builder is relevant for translucency sort triggering. It + * Determines the sort type for the collected geometry from the section. It * determines a sort type, which is either no sorting, a static sort or a * dynamic sort (section in GFNI only in this case). * From 198a438633a93a8db229a6aea19cc92106b91ddb Mon Sep 17 00:00:00 2001 From: douira Date: Tue, 26 Sep 2023 01:43:42 +0200 Subject: [PATCH 070/256] comment --- .../sodium/client/render/chunk/compile/ChunkBuildBuffers.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildBuffers.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildBuffers.java index 52ff44d65c..65bfad62d6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildBuffers.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildBuffers.java @@ -95,7 +95,7 @@ public BuiltSectionMeshParts createMesh(TerrainRenderPass pass, boolean forceUna mergedBufferBuilder.put(buffer); } - mergedBufferBuilder.flip(); + mergedBufferBuilder.flip(); // TODO: necessary? return new BuiltSectionMeshParts(mergedBuffer, vertexRanges); } From 24bbb4d515b9992028d046efdacc8798bc7c0f04 Mon Sep 17 00:00:00 2001 From: douira Date: Tue, 26 Sep 2023 16:28:07 +0200 Subject: [PATCH 071/256] this appears to be an int to byte conversion and not qua to vertices --- .../mods/sodium/client/render/chunk/DefaultChunkRenderer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java index 8c2251372b..88231de0f8 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java @@ -157,7 +157,7 @@ private static void addDrawCommands(MultiDrawBatch batch, long pMeshData, int ma MemoryUtil.memPutInt(pBaseVertex + (size << 2), SectionRenderDataUnsafe.getVertexOffset(pMeshData, facing)); MemoryUtil.memPutInt(pElementCount + (size << 2), SectionRenderDataUnsafe.getElementCount(pMeshData, facing)); if (pIndexData != -1) { - MemoryUtil.memPutAddress(pElementPointer + (size << 3), SectionRenderDataUnsafe.getVertexOffset(pIndexData, facing) * TranslucentData.VERTICES_PER_QUAD); + MemoryUtil.memPutAddress(pElementPointer + (size << 3), SectionRenderDataUnsafe.getVertexOffset(pIndexData, facing) << 2); } else { MemoryUtil.memPutAddress(pElementPointer + (size << 3), 0); } From ffc36776217bcbbc3b044b6cff018d706bb458d8 Mon Sep 17 00:00:00 2001 From: douira Date: Tue, 26 Sep 2023 16:40:12 +0200 Subject: [PATCH 072/256] rename sort behavior to off, avoids confusion --- .../jellysquid/mods/sodium/client/gui/SodiumGameOptions.java | 2 +- .../mods/sodium/client/render/chunk/DefaultChunkRenderer.java | 3 +-- .../render/chunk/compile/tasks/ChunkBuilderMeshingTask.java | 2 +- .../client/render/chunk/gfni/TranslucentGeometryCollector.java | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java index 772542ddd8..54e56dc409 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java @@ -53,7 +53,7 @@ public static class PerformanceSettings { } public enum SortBehavior implements TextProvider { - NONE("options.off", Set.of(SortType.NONE)), + OFF("options.off", Set.of(SortType.NONE)), STATIC("options.clouds.fast", getUpTo(SortType.STATIC_TOPO_ACYCLIC)), DYNAMIC("options.clouds.fancy", getUpTo(SortType.DYNAMIC_ALL)); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java index 88231de0f8..16c8aeae61 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java @@ -14,7 +14,6 @@ import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.render.chunk.data.SectionRenderDataStorage; import me.jellysquid.mods.sodium.client.render.chunk.data.SectionRenderDataUnsafe; -import me.jellysquid.mods.sodium.client.render.chunk.gfni.TranslucentData; import me.jellysquid.mods.sodium.client.render.chunk.lists.ChunkRenderListIterable; import me.jellysquid.mods.sodium.client.render.chunk.lists.ChunkRenderList; import me.jellysquid.mods.sodium.client.render.chunk.region.RenderRegion; @@ -52,7 +51,7 @@ public void render(ChunkRenderMatrices matrices, // TODO: also disable this if there is only NONE-type sorting or no translucent geometry in the region boolean isTranslucent = renderPass == DefaultTerrainRenderPasses.TRANSLUCENT - && SodiumClientMod.options().performance.sortBehavior != SortBehavior.NONE; + && SodiumClientMod.options().performance.sortBehavior != SortBehavior.OFF; boolean useBlockFaceCulling = SodiumClientMod.options().performance.useBlockFaceCulling; ChunkShaderInterface shader = this.activeProgram.getInterface(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java index 288cff9601..a7672028c4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java @@ -77,7 +77,7 @@ public ChunkBuildOutput execute(ChunkBuildContext buildContext, CancellationToke BlockPos.Mutable modelOffset = new BlockPos.Mutable(); TranslucentGeometryCollector collector = null; - if (SodiumClientMod.options().performance.sortBehavior != SortBehavior.NONE) { + if (SodiumClientMod.options().performance.sortBehavior != SortBehavior.OFF) { collector = new TranslucentGeometryCollector(render.getPosition()); } BlockRenderContext context = new BlockRenderContext(slice, collector); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java index 6dd996f79c..5d18024f71 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java @@ -232,7 +232,7 @@ private SortType sortTypeHeuristic() { SortBehavior sortBehavior = SodiumClientMod.options().performance.sortBehavior; // special case A - if (sortBehavior == SortBehavior.NONE || this.facePlaneCount <= 1) { + if (sortBehavior == SortBehavior.OFF || this.facePlaneCount <= 1) { return SortType.NONE; } From c68f711093029752b41f5c2977e1bb04fdd2391f Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 2 Oct 2023 17:27:46 +0200 Subject: [PATCH 073/256] don't do comparisons of quads with themselves --- .../client/render/chunk/data/SectionRenderDataStorage.java | 2 +- .../mods/sodium/client/render/chunk/gfni/ComplexSorting.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java index 8deee78c21..dbb39a9d3e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java @@ -103,4 +103,4 @@ public void delete() { SectionRenderDataUnsafe.freeHeap(this.pMeshDataArray); } -} \ No newline at end of file +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java index 0f5f4a4284..b063d8e0d3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java @@ -451,7 +451,7 @@ public static boolean topoSortFullGraphAcyclic(IntBuffer indexBuffer, TQuad[] al int otherQuadIndex = start; while (otherQuadIndex != -1) { TQuad otherQuad = quads[otherQuadIndex]; - if (quadVisibleThrough(quad, otherQuad)) { + if (quadIndex != otherQuadIndex && quadVisibleThrough(quad, otherQuad)) { insertAfter = otherQuadIndex; } otherQuadIndex = forwards[otherQuadIndex]; From 70ea0e66c41e22bec2d5abfeef760980b3ce9b29 Mon Sep 17 00:00:00 2001 From: douira Date: Tue, 3 Oct 2023 01:15:05 +0200 Subject: [PATCH 074/256] use sorted array of doubles instead of avl tree --- .../client/render/chunk/gfni/Group.java | 51 +++++++++++++++---- .../client/render/chunk/gfni/NormalList.java | 2 +- 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java index 0e976b1210..0cbb34c83a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java @@ -2,11 +2,12 @@ import com.lodborg.intervaltree.DoubleInterval; -import it.unimi.dsi.fastutil.doubles.DoubleAVLTreeSet; +import it.unimi.dsi.fastutil.doubles.DoubleArrays; import net.minecraft.util.math.ChunkSectionPos; /** - * A group represents a set of face planes of the same normal within a bucket. A + * A group represents a set of face planes of the same normal within a section. + * A * group keeps a tree of its face plane distances to determine if it needs to be * triggered. */ @@ -17,10 +18,9 @@ class Group { ChunkSectionPos sectionPos; /** - * A tree of all the face plane distances in this group, relative to the - * enclosing bucket's startDistance. + * A sorted list of all the face plane distances in this group. */ - DoubleAVLTreeSet facePlaneDistances = new DoubleAVLTreeSet(); + double[] facePlaneDistances; /** * A hash of all the face plane distances in this group (before adding the base @@ -42,18 +42,47 @@ void replaceWith(AccumulationGroup accGroup, DoubleInterval accGroupDistances, d this.distances = accGroupDistances; this.relDistanceHash = accGroup.relDistanceHash; - // clear the existing tree and add all the face plane distances but add the base - // distance to each relative distance - this.facePlaneDistances.clear(); - for (double distance : accGroup.relativeDistances) { - this.facePlaneDistances.add(distance + baseDistance); + // store the absolute face plane distances in an array + this.facePlaneDistances = new double[accGroup.relativeDistances.size()]; + int i = 0; + for (double relDistance : accGroup.relativeDistances) { + this.facePlaneDistances[i++] = relDistance + baseDistance; } + + // sort the array ascending + DoubleArrays.quickSort(facePlaneDistances); + } + + public static boolean queryRange(double[] sortedDistances, double start, double end) { + // test that there is actually an entry in the query range + int result = DoubleArrays.binarySearch(sortedDistances, start); + if (result < 0) { + // recover the insertion point + int insertionPoint = -result - 1; + if (insertionPoint >= sortedDistances.length) { + // no entry in the query range + return false; + } + + // check if the entry at the insertion point, which is the next one greater than + // the start value, is less than or equal to the end value + if (sortedDistances[insertionPoint] <= end) { + // there is an entry in the query range + return true; + } + } else { + // exact match, trigger + return true; + } + return false; } void triggerRange(GFNI gfni, double start, double end, int collectorKey) { // trigger self on the section if the query range overlaps with the group + // testing for strict inequality because if the two intervals just touch at the + // start/end, there can be no overlap if (start < this.distances.getEnd() && end > this.distances.getStart() - && !this.facePlaneDistances.subSet(start, end).isEmpty()) { + && queryRange(this.facePlaneDistances, start, end)) { gfni.triggerSection(this.sectionPos, collectorKey); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java index eb3c34135e..de5c404c89 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java @@ -177,7 +177,7 @@ void updateSection(AccumulationGroup accGroup, long chunkSectionLongPos) { // from the map for the right position. // TODO: how common are collisions and are they bad? // If they are common, use second hash - if (group.facePlaneDistances.size() == accGroup.relativeDistances.size() + if (group.facePlaneDistances.length == accGroup.relativeDistances.size() && group.distances.equals(accGroupDistances) && group.relDistanceHash == accGroup.relDistanceHash) { // don't update if they are the same From a8ec8b666cdc9312c64d6daef1e490db28edd3fe Mon Sep 17 00:00:00 2001 From: douira Date: Tue, 3 Oct 2023 17:19:31 +0200 Subject: [PATCH 075/256] use separator plane-based visibility graph refinement --- .../quad/properties/ModelQuadFacing.java | 27 ++- .../render/chunk/RenderSectionManager.java | 6 +- .../render/chunk/gfni/AccumulationGroup.java | 44 +++-- .../render/chunk/gfni/ComplexSorting.java | 182 +++++++++++++----- .../client/render/chunk/gfni/DynamicData.java | 86 +++++---- .../sodium/client/render/chunk/gfni/GFNI.java | 46 +++-- .../client/render/chunk/gfni/Group.java | 47 +++-- .../client/render/chunk/gfni/NormalList.java | 24 +-- .../chunk/gfni/StaticTopoAcyclicData.java | 2 +- .../gfni/TranslucentGeometryCollector.java | 35 ++-- 10 files changed, 315 insertions(+), 184 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java index 61c1dbf06d..226d5d3660 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java @@ -1,5 +1,8 @@ package me.jellysquid.mods.sodium.client.model.quad.properties; +import org.joml.Vector3f; +import org.joml.Vector3fc; + import net.minecraft.util.math.Direction; public enum ModelQuadFacing { @@ -19,14 +22,26 @@ public enum ModelQuadFacing { public static final int NONE = 0; public static final int ALL = (1 << COUNT) - 1; + public static final Vector3fc[] NORMALS = new Vector3fc[ModelQuadFacing.DIRECTIONS]; + + static { + for (int i = 0; i < ModelQuadFacing.DIRECTIONS; i++) { + NORMALS[i] = new Vector3f(ModelQuadFacing.VALUES[i].toDirection().getUnitVector()); + } + } + + public static final int OPPOSING_X = 1 << ModelQuadFacing.POS_X.ordinal() | 1 << ModelQuadFacing.NEG_X.ordinal(); + public static final int OPPOSING_Y = 1 << ModelQuadFacing.POS_Y.ordinal() | 1 << ModelQuadFacing.NEG_Y.ordinal(); + public static final int OPPOSING_Z = 1 << ModelQuadFacing.POS_Z.ordinal() | 1 << ModelQuadFacing.NEG_Z.ordinal(); + public static ModelQuadFacing fromDirection(Direction dir) { return switch (dir) { - case DOWN -> NEG_Y; - case UP -> POS_Y; - case NORTH -> NEG_Z; - case SOUTH -> POS_Z; - case WEST -> NEG_X; - case EAST -> POS_X; + case DOWN -> NEG_Y; + case UP -> POS_Y; + case NORTH -> NEG_Z; + case SOUTH -> POS_Z; + case WEST -> NEG_X; + case EAST -> POS_X; }; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index 111acd17f4..11710f57d4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -315,13 +315,15 @@ private void processChunkBuildResults(ArrayList results) { this.regions.uploadResults(RenderDevice.INSTANCE.createCommandList(), filtered); for (var result : filtered) { + TranslucentData oldData = result.render.getTranslucentData(); if (result instanceof ChunkBuildOutput chunkBuildOutput) { this.updateSectionInfo(result.render, chunkBuildOutput.info); + if (chunkBuildOutput.translucentData != null) { + this.gfni.integrateTranslucentData(oldData, chunkBuildOutput.translucentData); + } } if (result instanceof ChunkSortOutput chunkSortOutput && chunkSortOutput.translucentData != null) { - TranslucentData oldData = result.render.getTranslucentData(); result.render.setTranslucentData(chunkSortOutput.translucentData); - this.gfni.integrateTranslucentData(oldData, chunkSortOutput.translucentData); } var job = result.render.getTaskCancellationToken(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AccumulationGroup.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AccumulationGroup.java index caa489f80a..7d30148650 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AccumulationGroup.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AccumulationGroup.java @@ -5,6 +5,7 @@ import com.lodborg.intervaltree.DoubleInterval; import com.lodborg.intervaltree.Interval.Bounded; +import it.unimi.dsi.fastutil.doubles.DoubleArrays; import it.unimi.dsi.fastutil.doubles.DoubleOpenHashSet; import net.minecraft.util.math.ChunkSectionPos; @@ -13,10 +14,11 @@ class AccumulationGroup { final Vector3fc normal; final int collectorKey; final ChunkSectionPos sectionPos; - long relDistanceHash = 0; - private double relMinDistance = Double.POSITIVE_INFINITY; - private double relMaxDistance = Double.NEGATIVE_INFINITY; + double[] facePlaneDistances; // relative to the base distance + DoubleInterval distances; + long relDistanceHash; + double baseDistance; AccumulationGroup(ChunkSectionPos sectionPos, Vector3fc normal, int collectorKey) { this.sectionPos = sectionPos; @@ -28,21 +30,35 @@ boolean addPlaneMember(float vertexX, float vertexY, float vertexZ) { double distance = this.normal.dot(vertexX, vertexY, vertexZ); // add the distance to the set and update the min/max distances if necessary - if (this.relativeDistances.add(distance)) { - this.relMinDistance = Math.min(this.relMinDistance, distance); - this.relMaxDistance = Math.max(this.relMaxDistance, distance); + return this.relativeDistances.add(distance); + } + + void prepareIntegration() { + // stop if already prepared + if (this.facePlaneDistances != null) { + throw new IllegalStateException("Already prepared"); + } + + // store the absolute face plane distances in an array + var size = this.relativeDistances.size(); + this.facePlaneDistances = new double[this.relativeDistances.size()]; + int i = 0; + for (double relDistance : this.relativeDistances) { + this.facePlaneDistances[i++] = relDistance; - long distanceBits = Double.doubleToLongBits(distance); + long distanceBits = Double.doubleToLongBits(relDistance); this.relDistanceHash ^= distanceBits; - return true; } - return false; - } - DoubleInterval getDistanceInterval(double baseDistance) { - return new DoubleInterval( - this.relMinDistance + baseDistance, - this.relMaxDistance + baseDistance, + // sort the array ascending + DoubleArrays.quickSort(facePlaneDistances); + + this.baseDistance = this.normal.dot( + sectionPos.getMinX(), sectionPos.getMinY(), sectionPos.getMinZ()); + this.distances = new DoubleInterval( + this.facePlaneDistances[0] + this.baseDistance, + this.facePlaneDistances[size - 1] + this.baseDistance, Bounded.CLOSED); + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java index b063d8e0d3..24e1aea49c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java @@ -5,6 +5,7 @@ import org.joml.Vector3fc; import it.unimi.dsi.fastutil.ints.IntArrays; +import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.util.collections.BitArray; import me.jellysquid.mods.sodium.client.util.sorting.MergeSort; @@ -326,15 +327,68 @@ public static boolean topoSortAlignedAcyclic(IntBuffer indexBuffer, TQuad[] allQ return true; } + private static boolean testSeparatorRange(Object2ReferenceOpenHashMap distancesByNormal, + Vector3fc normal, float start, float end) { + var distances = distancesByNormal.get(normal); + if (distances == null) { + return false; + } + return Group.queryRange(distances, start, end); + } + + private static boolean visibilityWithSeparator(TQuad quadA, TQuad quadB, + Object2ReferenceOpenHashMap distancesByNormal, Vector3fc cameraPos) { + // check if there is an aligned separator + for (int direction = 0; direction < ModelQuadFacing.DIRECTIONS; direction++) { + var facing = ModelQuadFacing.VALUES[direction]; + var oppositeFacing = facing.getOpposite(); + var oppositeDirection = oppositeFacing.ordinal(); + var sign = facing.getSign(); + + // test that they're not overlapping in this direction + var separatorRangeStart = sign * quadB.extents()[direction]; + var separatorRangeEnd = sign * quadA.extents()[oppositeDirection]; + if (separatorRangeStart > separatorRangeEnd) { + continue; + } + + // test that the camera doesn't exclude all separators + var facingNormal = ModelQuadFacing.NORMALS[direction]; + var cameraDistance = facingNormal.dot(cameraPos); + if (cameraDistance > separatorRangeEnd) { + continue; + } + + // restrict the separator range start to the camera distance + separatorRangeStart = Math.max(separatorRangeStart, cameraDistance); + + // test if there is a separator plane that is outside/on the surface of the + // current trigger volume + if (testSeparatorRange(distancesByNormal, facingNormal, + separatorRangeStart, separatorRangeEnd)) { + return false; + } + } + + // visibility not disproven + return true; + } + /** * Checks if one quad is visible through the other quad. This accepts arbitrary * quads, even unaligned ones. * - * @param quad the quad through which the other quad is being tested - * @param other the quad being tested + * @param quad the quad through which the other quad is being + * tested + * @param other the quad being tested + * @param distancesByNormal a map of normals to sorted arrays of face plane + * distances for disproving that the quads are visible + * through eachother, null to disable + * * @return true if the other quad is visible through the first quad */ - private static boolean quadVisibleThrough(TQuad quad, TQuad other) { + private static boolean quadVisibleThrough(TQuad quad, TQuad other, + Object2ReferenceOpenHashMap distancesByNormal, Vector3fc cameraPos) { if (quad == other) { return false; } @@ -342,6 +396,7 @@ private static boolean quadVisibleThrough(TQuad quad, TQuad other) { // aligned quads var quadFacing = quad.facing(); var otherFacing = other.facing(); + boolean result; if (quadFacing != ModelQuadFacing.UNASSIGNED && otherFacing != ModelQuadFacing.UNASSIGNED) { // opposites never see eachother if (quadFacing.getOpposite() == otherFacing) { @@ -352,19 +407,27 @@ private static boolean quadVisibleThrough(TQuad quad, TQuad other) { if (quadFacing == otherFacing) { var sign = quadFacing.getSign(); var direction = quadFacing.ordinal(); - return sign * quad.extents()[direction] > sign * other.extents()[direction]; + result = sign * quad.extents()[direction] > sign * other.extents()[direction]; + } else { + // orthogonal quads + result = orthogonalQuadVisibleThrough(quad, other); } + } else { + // at least one unaligned quad + // this is an approximation since our quads don't store all their vertices. + // check that other center is within the halfspace of quad and that the normals + // are more than 90 degrees apart + result = halfspace(quad.center(), quad.normal(), other.center()) < 0 + && quad.normal().dot(other.normal()) < 0; + } - // orthogonal quads - return orthogonalQuadVisibleThrough(quad, other); + // if enabled and necessary, try to disprove this see-through relationship with + // a separator plane + if (result && distancesByNormal != null) { + return visibilityWithSeparator(quad, other, distancesByNormal, cameraPos); } - // at least one unaligned quad - // this is an approximation since our quads don't store all their vertices. - // check that other center is within the halfspace of quad and that the normals - // are more than 90 degrees apart - return halfspace(quad.center(), quad.normal(), other.center()) < 0 - && quad.normal().dot(other.normal()) < 0; + return result; } /** @@ -373,13 +436,18 @@ private static boolean quadVisibleThrough(TQuad quad, TQuad other) { * {@link #topoSortAlignedAcyclic(IntBuffer, TQuad[], Vector3fc)} does. Only * sort visible quads if a camera position is provided. * - * @param indexBuffer the buffer to write the topo sort result to - * @param allQuads the quads to sort - * @param cameraPos the camera position, or null to disable the visibility - * check + * @param indexBuffer the buffer to write the topo sort result to + * @param allQuads the quads to sort + * @param distancesByNormal a map of normals to sorted arrays of face plane + * distances, null to disable + * @param cameraPos the camera position, or null to disable the + * visibility check * @return true if the quads were sorted, false if there was a cycle */ - public static boolean topoSortFullGraphAcyclic(IntBuffer indexBuffer, TQuad[] allQuads, Vector3fc cameraPos) { + public static boolean topoSortFullGraphAcyclic( + IntBuffer indexBuffer, TQuad[] allQuads, + Object2ReferenceOpenHashMap distancesByNormal, + Vector3fc cameraPos) { // TODO: quads visibility filter copy-pasted from topoSortAlignedAcyclic // if enabled, check for visibility and produce a mapping of indices TQuad[] quads = null; @@ -421,7 +489,7 @@ public static boolean topoSortFullGraphAcyclic(IntBuffer indexBuffer, TQuad[] al if (activeQuads == 2) { var a = 0; var b = 1; - if (quadVisibleThrough(quads[a], quads[b])) { + if (quadVisibleThrough(quads[a], quads[b], null, null)) { a = 1; b = 0; } @@ -431,15 +499,16 @@ public static boolean topoSortFullGraphAcyclic(IntBuffer indexBuffer, TQuad[] al } // int-based doubly linked list of active quad indexes - int[] forwards = new int[activeQuads]; - int[] backwards = new int[activeQuads]; + // TODO: put this linked list in a class + int[] next = new int[activeQuads]; + int[] prev = new int[activeQuads]; int start = 0; for (int i = 0; i < activeQuads - 1; i++) { - forwards[i] = i + 1; - backwards[i + 1] = i; + next[i] = i + 1; + prev[i + 1] = i; } - forwards[activeQuads - 1] = -1; - backwards[0] = -1; + next[activeQuads - 1] = -1; + prev[0] = -1; // go through all the active quads and insert them into the list at the point // where they are after all the quads that are visible through them @@ -451,46 +520,69 @@ public static boolean topoSortFullGraphAcyclic(IntBuffer indexBuffer, TQuad[] al int otherQuadIndex = start; while (otherQuadIndex != -1) { TQuad otherQuad = quads[otherQuadIndex]; - if (quadIndex != otherQuadIndex && quadVisibleThrough(quad, otherQuad)) { + if (quadIndex != otherQuadIndex + && quadVisibleThrough(quad, otherQuad, distancesByNormal, cameraPos)) { insertAfter = otherQuadIndex; } - otherQuadIndex = forwards[otherQuadIndex]; + otherQuadIndex = next[otherQuadIndex]; } - // remove from current location - int currentForward = forwards[quadIndex]; - int currentBackward = backwards[quadIndex]; - if (currentForward != -1) { - backwards[currentForward] = currentBackward; + // if the move index is lower than insert after, instead move the insert after + // to be right before the move index + int removeIndex = quadIndex; + boolean swapped = quadIndex < insertAfter; // implies insertAfter != -1 + if (swapped) { + removeIndex = insertAfter; } - if (currentBackward != -1) { - forwards[currentBackward] = currentForward; + + // remove quadIndex or insertAfter from current location + int currentNext = next[removeIndex]; + int currentPrev = prev[removeIndex]; + if (currentNext != -1) { + prev[currentNext] = currentPrev; + } + if (currentPrev != -1) { + next[currentPrev] = currentNext; } else { - start = currentForward; + start = currentNext; } // insert after the identified last quad that this quad needs to be after if (insertAfter == -1) { - // insert at the start - forwards[quadIndex] = start; - backwards[quadIndex] = -1; - backwards[start] = quadIndex; + // insert quadIndex at the start + next[quadIndex] = start; + prev[quadIndex] = -1; + prev[start] = quadIndex; start = quadIndex; + } else if (swapped) { + // insert insertAfter at the start if quadIndex is the start + if (start == quadIndex) { + next[insertAfter] = start; + prev[insertAfter] = -1; + prev[start] = insertAfter; + start = insertAfter; + } else { + // insert insertAfter before quadIndex + next[insertAfter] = quadIndex; + next[prev[quadIndex]] = insertAfter; + prev[insertAfter] = prev[quadIndex]; + prev[quadIndex] = insertAfter; + } } else { - // insert after the identified quad - forwards[quadIndex] = forwards[insertAfter]; - backwards[quadIndex] = insertAfter; - forwards[insertAfter] = quadIndex; - if (forwards[quadIndex] != -1) { - backwards[forwards[quadIndex]] = quadIndex; + // insert quadIndex after insertAfter + prev[quadIndex] = insertAfter; + if (next[insertAfter] != -1) { // end of chain + prev[next[insertAfter]] = quadIndex; } + next[quadIndex] = next[insertAfter]; + next[insertAfter] = quadIndex; } } // write the sorted quads to the buffer for (int i = 0; i < activeQuads; i++) { TranslucentData.putMappedQuadVertexIndexes(indexBuffer, start, activeToRealIndex); - start = forwards[start]; + start = next[start]; } // detect cycles diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java index 80e9920f70..138dc7de55 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java @@ -4,33 +4,26 @@ import org.joml.Vector3fc; -import it.unimi.dsi.fastutil.ints.Int2ReferenceLinkedOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; import me.jellysquid.mods.sodium.client.gl.util.VertexRange; +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; import me.jellysquid.mods.sodium.client.util.NativeBuffer; import net.minecraft.util.math.ChunkSectionPos; -/** - * TODO: the sort algorithm uses a heuristic to avoid issues arising from - * parallel planes of many quads. (see below) This heuristic is imperfect and - * can cause some artifacts. A better approach would be a visible-only - * topological sort. That's hard though, because it needs to handle arbitrary - * amounts of (potentially unaligned) quads and run on every trigger event. - * Possibly re-use of (incrementally constructed) graph structures is necessary? - */ public class DynamicData extends MixedDirectionData { private final TQuad[] quads; - private final AccumulationGroup[] axisAlignedDistances; - private final Int2ReferenceLinkedOpenHashMap unalignedDistances; + private TranslucentGeometryCollector collector; + private Object2ReferenceOpenHashMap distancesByNormal; DynamicData(ChunkSectionPos sectionPos, NativeBuffer buffer, VertexRange range, TQuad[] quads, - AccumulationGroup[] axisAlignedDistances, - Int2ReferenceLinkedOpenHashMap unalignedDistances) { + TranslucentGeometryCollector collector, + Object2ReferenceOpenHashMap distancesByNormal) { super(sectionPos, buffer, range); this.quads = quads; - this.axisAlignedDistances = axisAlignedDistances; - this.unalignedDistances = unalignedDistances; + this.collector = collector; + this.distancesByNormal = distancesByNormal; } @Override @@ -38,47 +31,56 @@ public SortType getSortType() { return SortType.DYNAMIC_ALL; } - AccumulationGroup getGroupForNormal(NormalList normalList) { - int collectorKey = normalList.getCollectorKey(); - if (collectorKey < 0xFF) { - if (this.axisAlignedDistances == null) { - return null; - } - return this.axisAlignedDistances[collectorKey]; - } else { - if (this.unalignedDistances == null) { - return null; - } - return this.unalignedDistances.get(collectorKey); - } - } - - public AccumulationGroup[] getAxisAlignedDistances() { - return this.axisAlignedDistances; - } - - public Int2ReferenceLinkedOpenHashMap getUnalignedDistances() { - return this.unalignedDistances; - } - @Override public void sort(Vector3fc cameraPos) { IntBuffer indexBuffer = this.buffer.getDirectBuffer().asIntBuffer(); - if (!ComplexSorting.topoSortFullGraphAcyclic(indexBuffer, this.quads, cameraPos)) { + if (!ComplexSorting.topoSortFullGraphAcyclic(indexBuffer, this.quads, this.distancesByNormal, cameraPos)) { // if a camera position is given, no cycle should be possible throw new IllegalStateException("Failed to sort"); } } + TranslucentGeometryCollector getCollector() { + return this.collector; + } + + void finishIntegration() { + this.collector = null; + } + static DynamicData fromMesh(BuiltSectionMeshParts translucentMesh, Vector3fc cameraPos, TQuad[] quads, ChunkSectionPos sectionPos, TranslucentGeometryCollector collector) { + // prepare accumulation groups for GFNI integration and copy + var size = 0; + if (collector.axisAlignedDistances != null) { + size += Integer.bitCount(collector.alignedNormalBitmap); + } + if (collector.unalignedDistances != null) { + size += collector.unalignedDistances.size(); + } + var distancesByNormal = new Object2ReferenceOpenHashMap(size); + if (collector.axisAlignedDistances != null) { + for (int direction = 0; direction < ModelQuadFacing.DIRECTIONS; direction++) { + var accGroup = collector.axisAlignedDistances[direction]; + if (accGroup != null) { + accGroup.prepareIntegration(); + distancesByNormal.put(accGroup.normal, accGroup.facePlaneDistances); + } + } + } + if (collector.unalignedDistances != null) { + for (var accGroup : collector.unalignedDistances.values()) { + // TODO: get rid of collector key and just use the normal vector's hash code + accGroup.prepareIntegration(); + distancesByNormal.put(accGroup.normal, accGroup.facePlaneDistances); + } + } + VertexRange range = TranslucentData.getUnassignedVertexRange(translucentMesh); var buffer = new NativeBuffer(TranslucentData.quadCountToIndexBytes(quads.length)); - var dynamicData = new DynamicData(sectionPos, - buffer, range, quads, - collector.axisAlignedDistances, collector.unalignedDistances); + var dynamicData = new DynamicData(sectionPos, buffer, range, quads, collector, distancesByNormal); dynamicData.sort(cameraPos); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java index 00990e10c1..1c2266969d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java @@ -29,7 +29,8 @@ * - problem: when there are two parallel planes made up of many quads each, * sorting the whole thing from one perspective means the sorting is wrong when * we look at it from another perspective. This happens because there is no - * trigger in the plane. Sorting as if the entire thing was one quad would fix it. + * trigger in the plane. Sorting as if the entire thing was one quad would fix + * it. * * @author douira */ @@ -109,11 +110,12 @@ public void triggerSections( // int triggerCount = this.triggeredSections.size(); // if (triggerCount > 0) { - // System.out.println("Triggered " + triggerCount + " sections"); - // for (long section : this.triggeredSections) { - // ChunkSectionPos sectionPos = ChunkSectionPos.from(section); - // System.out.println(sectionPos.getX() + " " + sectionPos.getY() + " " + sectionPos.getZ()); - // } + // System.out.println("Triggered " + triggerCount + " sections"); + // for (long section : this.triggeredSections) { + // ChunkSectionPos sectionPos = ChunkSectionPos.from(section); + // System.out.println(sectionPos.getX() + " " + sectionPos.getY() + " " + + // sectionPos.getZ()); + // } // } triggerSectionCallback = null; @@ -156,7 +158,7 @@ public void removeSection(TranslucentData oldTranslucentData, long chunkSectionL decrementSortTypeCounter(oldTranslucentData); } - private void addSectionInNewNormalLists(AccumulationGroup accGroup) { + private void addSectionInNewNormalLists(DynamicData dynamicData, AccumulationGroup accGroup) { var normal = accGroup.normal; var normalList = this.normalLists.get(normal); if (normalList == null) { @@ -167,12 +169,14 @@ private void addSectionInNewNormalLists(AccumulationGroup accGroup) { } /** - * Integrates the data from a geometry collector into GFNI. The geometry collector + * Integrates the data from a geometry collector into GFNI. The geometry + * collector * contains the translucent face planes of a single section. This method may * also remove the section if it has become irrelevant. * * @param builder the geometry collector to integrate - * @return the sort type that the geometry collector's relevance heuristic determined + * @return the sort type that the geometry collector's relevance heuristic + * determined */ public void integrateTranslucentData(TranslucentData oldTranslucentData, TranslucentData translucentData) { long chunkSectionLongPos = translucentData.sectionPos.asLong(); @@ -188,18 +192,15 @@ public void integrateTranslucentData(TranslucentData oldTranslucentData, Translu decrementSortTypeCounter(oldTranslucentData); - // TODO: implement cycle breaking and multiple sort orders - if (!(translucentData instanceof DynamicData)) { - throw new RuntimeException("Dynamic topo sort not implemented yet"); - } var dynamicData = (DynamicData) translucentData; + var collector = dynamicData.getCollector(); // go through all normal lists and check against the normals that the group // builder has. if the normal list has data for the section, but the group // builder doesn't, the group is removed. otherwise, the group is updated. for (var normalList : this.normalLists.values()) { // check if the geometry collector includes data for this normal. - var accGroup = dynamicData.getGroupForNormal(normalList); + var accGroup = collector.getGroupForNormal(normalList); if (normalList.hasSection(chunkSectionLongPos)) { if (accGroup == null) { removeSectionFromList(normalList, chunkSectionLongPos); @@ -211,21 +212,24 @@ public void integrateTranslucentData(TranslucentData oldTranslucentData, Translu } } - // go through the data of the geometry collector to check for data of new normals + // go through the data of the geometry collector to check for data of new + // normals // for which there are no normal lists yet. This only checks for new normal // lists since new data for existing normal lists is handled above. - if (dynamicData.getAxisAlignedDistances() != null) { - for (var accGroup : dynamicData.getAxisAlignedDistances()) { + if (collector.axisAlignedDistances != null) { + for (var accGroup : collector.axisAlignedDistances) { if (accGroup != null) { - addSectionInNewNormalLists(accGroup); + addSectionInNewNormalLists(dynamicData, accGroup); } } } - if (dynamicData.getUnalignedDistances() != null) { - for (var accGroup : dynamicData.getUnalignedDistances().values()) { - addSectionInNewNormalLists(accGroup); + if (collector.unalignedDistances != null) { + for (var accGroup : collector.unalignedDistances.values()) { + addSectionInNewNormalLists(dynamicData, accGroup); } } + + dynamicData.finishIntegration(); } public void addDebugStrings(List list) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java index 0cbb34c83a..bd86a8ab25 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java @@ -18,7 +18,8 @@ class Group { ChunkSectionPos sectionPos; /** - * A sorted list of all the face plane distances in this group. + * A sorted list of all the face plane distances in this group. Relative to the + * base distance. */ double[] facePlaneDistances; @@ -26,31 +27,26 @@ class Group { * A hash of all the face plane distances in this group (before adding the base * distance) */ - long relDistanceHash = 0; + long relDistanceHash; /** * The closed (inclusive of both boundaries) minimum and maximum distances. + * Absolute values, not relative to the base distance. */ DoubleInterval distances; - Group(AccumulationGroup accGroup, DoubleInterval accGroupDistances, double baseDistance) { - replaceWith(accGroup, accGroupDistances, baseDistance); + double baseDistance; + + Group(AccumulationGroup accGroup) { + replaceWith(accGroup); } - void replaceWith(AccumulationGroup accGroup, DoubleInterval accGroupDistances, double baseDistance) { + void replaceWith(AccumulationGroup accGroup) { this.sectionPos = accGroup.sectionPos; - this.distances = accGroupDistances; + this.distances = accGroup.distances; this.relDistanceHash = accGroup.relDistanceHash; - - // store the absolute face plane distances in an array - this.facePlaneDistances = new double[accGroup.relativeDistances.size()]; - int i = 0; - for (double relDistance : accGroup.relativeDistances) { - this.facePlaneDistances[i++] = relDistance + baseDistance; - } - - // sort the array ascending - DoubleArrays.quickSort(facePlaneDistances); + this.facePlaneDistances = accGroup.facePlaneDistances; + this.baseDistance = accGroup.baseDistance; } public static boolean queryRange(double[] sortedDistances, double start, double end) { @@ -82,8 +78,25 @@ void triggerRange(GFNI gfni, double start, double end, int collectorKey) { // testing for strict inequality because if the two intervals just touch at the // start/end, there can be no overlap if (start < this.distances.getEnd() && end > this.distances.getStart() - && queryRange(this.facePlaneDistances, start, end)) { + && queryRange(this.facePlaneDistances, + start - this.baseDistance, end - this.baseDistance)) { gfni.triggerSection(this.sectionPos, collectorKey); } } + + /** + * A pretty good heuristic for equality of captured translucent geometry data. + * + * It assumes that if the size, bounds, and hash are equal, they are most likely + * the same. We also know that the existing and new data is for the same section + * position since the group was retrieved from the map for the right position. + * + * TODO: how common are collisions and are they bad? + * If they are common, use second hash + */ + boolean equalsAccGroup(AccumulationGroup accGroup) { + return this.facePlaneDistances.length == accGroup.relativeDistances.size() + && this.distances.equals(accGroup.distances) + && this.relDistanceHash == accGroup.relDistanceHash; + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java index de5c404c89..88b3c316f5 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java @@ -15,7 +15,6 @@ import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; import it.unimi.dsi.fastutil.objects.ReferenceArraySet; import it.unimi.dsi.fastutil.objects.ReferenceLinkedOpenHashSet; -import net.minecraft.util.math.ChunkSectionPos; /** * A normal list contains all the face planes that have the same normal. @@ -147,11 +146,7 @@ boolean isEmpty() { } void addSection(AccumulationGroup accGroup, long chunkSectionLongPos) { - ChunkSectionPos pos = accGroup.sectionPos; - double baseDistance = accGroup.normal.dot(pos.getMinX(), pos.getMinY(), pos.getMinZ()); - DoubleInterval accGroupDistances = accGroup.getDistanceInterval(baseDistance); - - var group = new Group(accGroup, accGroupDistances, baseDistance); + var group = new Group(accGroup); this.groupsBySection.put(chunkSectionLongPos, group); addGroupInterval(group); @@ -165,27 +160,16 @@ void removeSection(long chunkSectionLongPos) { } void updateSection(AccumulationGroup accGroup, long chunkSectionLongPos) { - ChunkSectionPos pos = accGroup.sectionPos; - double baseDistance = accGroup.normal.dot(pos.getMinX(), pos.getMinY(), pos.getMinZ()); - DoubleInterval accGroupDistances = accGroup.getDistanceInterval(baseDistance); - Group group = this.groupsBySection.get(chunkSectionLongPos); - // this is just a heuristic, but it assumes that if the size, bounds and - // hash are equal, they are most likely the same. We also know that the existing - // and new data is for the same section position since the group was retrieved - // from the map for the right position. - // TODO: how common are collisions and are they bad? - // If they are common, use second hash - if (group.facePlaneDistances.length == accGroup.relativeDistances.size() - && group.distances.equals(accGroupDistances) - && group.relDistanceHash == accGroup.relDistanceHash) { + // only update on changes to translucent geometry + if (group.equalsAccGroup(accGroup)) { // don't update if they are the same return; } removeGroupInterval(group); - group.replaceWith(accGroup, accGroupDistances, baseDistance); + group.replaceWith(accGroup); addGroupInterval(group); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java index 2e9d686108..10aa0c0b1a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java @@ -21,7 +21,7 @@ static StaticTopoAcyclicData fromMesh(BuiltSectionMeshParts translucentMesh, var buffer = new NativeBuffer(TranslucentData.vertexCountToIndexBytes(range.vertexCount())); var indexBuffer = buffer.getDirectBuffer().asIntBuffer(); - if (!ComplexSorting.topoSortFullGraphAcyclic(indexBuffer, quads, null)) { + if (!ComplexSorting.topoSortFullGraphAcyclic(indexBuffer, quads, null, null)) { System.out.println("Failed to sort topo static because there was a cycle"); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java index 5d18024f71..1014f26797 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java @@ -36,18 +36,6 @@ * overhead if no sorting is wanted. */ public class TranslucentGeometryCollector { - private static final Vector3fc[] ALIGNED_NORMALS = new Vector3fc[ModelQuadFacing.DIRECTIONS]; - - private static final int OPPOSING_X = 1 << ModelQuadFacing.POS_X.ordinal() | 1 << ModelQuadFacing.NEG_X.ordinal(); - private static final int OPPOSING_Y = 1 << ModelQuadFacing.POS_Y.ordinal() | 1 << ModelQuadFacing.NEG_Y.ordinal(); - private static final int OPPOSING_Z = 1 << ModelQuadFacing.POS_Z.ordinal() | 1 << ModelQuadFacing.NEG_Z.ordinal(); - - static { - for (int i = 0; i < ModelQuadFacing.DIRECTIONS; i++) { - ALIGNED_NORMALS[i] = new Vector3f(ModelQuadFacing.VALUES[i].toDirection().getUnitVector()); - } - } - AccumulationGroup[] axisAlignedDistances; Int2ReferenceLinkedOpenHashMap unalignedDistances; @@ -154,7 +142,7 @@ public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] verti accGroup = this.axisAlignedDistances[quadDirection]; if (accGroup == null) { - accGroup = new AccumulationGroup(sectionPos, ALIGNED_NORMALS[quadDirection], quadDirection); + accGroup = new AccumulationGroup(sectionPos, ModelQuadFacing.NORMALS[quadDirection], quadDirection); this.axisAlignedDistances[quadDirection] = accGroup; this.alignedNormalBitmap |= 1 << quadDirection; } @@ -237,9 +225,9 @@ private SortType sortTypeHeuristic() { } if (this.unalignedDistances == null) { - boolean twoOpposingNormals = this.alignedNormalBitmap == OPPOSING_X - || this.alignedNormalBitmap == OPPOSING_Y - || this.alignedNormalBitmap == OPPOSING_Z; + boolean twoOpposingNormals = this.alignedNormalBitmap == ModelQuadFacing.OPPOSING_X + || this.alignedNormalBitmap == ModelQuadFacing.OPPOSING_Y + || this.alignedNormalBitmap == ModelQuadFacing.OPPOSING_Z; // special case B // if there are just two normals, they are exact opposites of eachother and they @@ -378,4 +366,19 @@ public TranslucentData getTranslucentData(BuiltSectionMeshParts translucentMesh, throw new IllegalStateException("Unknown sort type: " + this.sortType); } + + AccumulationGroup getGroupForNormal(NormalList normalList) { + int collectorKey = normalList.getCollectorKey(); + if (collectorKey < 0xFF) { + if (this.axisAlignedDistances == null) { + return null; + } + return this.axisAlignedDistances[collectorKey]; + } else { + if (this.unalignedDistances == null) { + return null; + } + return this.unalignedDistances.get(collectorKey); + } + } } From 81a62ab9f3493db4485fee20f746876aa11ac11a Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 6 Oct 2023 18:06:57 +0200 Subject: [PATCH 076/256] implement and use depth first search sorting --- .../render/chunk/gfni/ComplexSorting.java | 123 +++++++++++++++++- .../client/render/chunk/gfni/DynamicData.java | 2 +- .../chunk/gfni/StaticTopoAcyclicData.java | 2 +- 3 files changed, 122 insertions(+), 5 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java index 24e1aea49c..501d6cc2f1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java @@ -158,7 +158,7 @@ private static void makeEdge(int[][] graph, BitArray leafQuads, * should be performed * @return true if the quads were sorted, false if there was a cycle */ - public static boolean topoSortAlignedAcyclic(IntBuffer indexBuffer, TQuad[] allQuads, Vector3fc cameraPos) { + public static boolean topoSortAlignedScanningCyclic(IntBuffer indexBuffer, TQuad[] allQuads, Vector3fc cameraPos) { // if enabled, check for visibility and produce a mapping of indices TQuad[] quads = null; int[] activeToRealIndex = null; @@ -433,7 +433,8 @@ private static boolean quadVisibleThrough(TQuad quad, TQuad other, /** * Performs a topological sort but constructs the full forward graph without * using a compression technique like - * {@link #topoSortAlignedAcyclic(IntBuffer, TQuad[], Vector3fc)} does. Only + * {@link #topoSortAlignedScanningCyclic(IntBuffer, TQuad[], Vector3fc)} does. + * Only * sort visible quads if a camera position is provided. * * @param indexBuffer the buffer to write the topo sort result to @@ -444,7 +445,7 @@ private static boolean quadVisibleThrough(TQuad quad, TQuad other, * visibility check * @return true if the quads were sorted, false if there was a cycle */ - public static boolean topoSortFullGraphAcyclic( + public static boolean topoSortLinkedListAcyclic( IntBuffer indexBuffer, TQuad[] allQuads, Object2ReferenceOpenHashMap distancesByNormal, Vector3fc cameraPos) { @@ -500,6 +501,7 @@ public static boolean topoSortFullGraphAcyclic( // int-based doubly linked list of active quad indexes // TODO: put this linked list in a class + // TODO: sorting is sometimes wrong, see example in sandstone world int[] next = new int[activeQuads]; int[] prev = new int[activeQuads]; int start = 0; @@ -592,4 +594,119 @@ && quadVisibleThrough(quad, otherQuad, distancesByNormal, cameraPos)) { return true; } + + public static boolean topoSortDepthFirstCyclic( + IntBuffer indexBuffer, TQuad[] allQuads, + Object2ReferenceOpenHashMap distancesByNormal, + Vector3fc cameraPos) { + // TODO: quads visibility filter copy-pasted from topoSortAlignedAcyclic + // if enabled, check for visibility and produce a mapping of indices + TQuad[] quads = null; + int[] activeToRealIndex = null; + int activeQuads = 0; + if (cameraPos != null) { + // allocate the working quads and index map at the full size to avoid needing to + // iterate the quads again after checking visibility + quads = new TQuad[allQuads.length]; + activeToRealIndex = new int[allQuads.length]; + + for (int i = 0; i < allQuads.length; i++) { + TQuad quad = allQuads[i]; + if (pointOutsideHalfspace(quad.center(), quad.normal(), cameraPos)) { + activeToRealIndex[activeQuads] = i; + quads[activeQuads] = quad; + activeQuads++; + } else { + // write the invisible quads right away + TranslucentData.putQuadVertexIndexes(indexBuffer, i); + } + } + } else { + quads = allQuads; + activeQuads = allQuads.length; + } + + // special case for 0 to 2 quads + if (activeQuads == 0) { + return true; + } + if (activeQuads == 1) { + TranslucentData.putMappedQuadVertexIndexes(indexBuffer, 0, activeToRealIndex); + return true; + } + + // special case 2 quads for performance + if (activeQuads == 2) { + var a = 0; + var b = 1; + if (quadVisibleThrough(quads[a], quads[b], null, null)) { + a = 1; + b = 0; + } + TranslucentData.putMappedQuadVertexIndexes(indexBuffer, a, activeToRealIndex); + TranslucentData.putMappedQuadVertexIndexes(indexBuffer, b, activeToRealIndex); + return true; + } + + BitArray unvisited = new BitArray(activeQuads); + unvisited.set(0, activeQuads); + int visitedCount = 0; + BitArray onStack = new BitArray(activeQuads); + int[] stack = new int[activeQuads]; + int[] nextEdge = new int[activeQuads]; + + // start dfs searches until all quads are visited + while (visitedCount < activeQuads) { + int stackPos = 0; + var root = unvisited.nextSetBit(0); + stack[stackPos] = root; + onStack.set(root); + nextEdge[stackPos] = 0; + + while (stackPos >= 0) { + // start at next edge and find an unvisited quad + var currentQuadIndex = stack[stackPos]; + var nextEdgeTest = unvisited.nextSetBit(nextEdge[stackPos]); + if (nextEdgeTest != -1) { + var currentQuad = quads[currentQuadIndex]; + var nextQuad = quads[nextEdgeTest]; + if (quadVisibleThrough(currentQuad, nextQuad, distancesByNormal, cameraPos)) { + // if the visible quad is on the stack, there is a cycle + if (onStack.getAndSet(nextEdgeTest)) { + return false; + } + + // set the next edge + nextEdge[stackPos] = nextEdgeTest + 1; + + // visit the next quad, onStack is already set + stackPos++; + stack[stackPos] = nextEdgeTest; + nextEdge[stackPos] = 0; + continue; + } else { + // go to the next edge + nextEdgeTest++; + + // if we haven't reached the end of the edges yet + if (nextEdgeTest < activeQuads) { + nextEdge[stackPos] = nextEdgeTest; + continue; + } + } + } + + // no more edges left, pop the stack + onStack.unset(currentQuadIndex); + visitedCount++; + unvisited.unset(currentQuadIndex); + stackPos--; + + // write to the index buffer since the order is now correct + TranslucentData.putMappedQuadVertexIndexes(indexBuffer, currentQuadIndex, activeToRealIndex); + } + } + + return true; + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java index 138dc7de55..ba5b9748a3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java @@ -35,7 +35,7 @@ public SortType getSortType() { public void sort(Vector3fc cameraPos) { IntBuffer indexBuffer = this.buffer.getDirectBuffer().asIntBuffer(); - if (!ComplexSorting.topoSortFullGraphAcyclic(indexBuffer, this.quads, this.distancesByNormal, cameraPos)) { + if (!ComplexSorting.topoSortDepthFirstCyclic(indexBuffer, this.quads, this.distancesByNormal, cameraPos)) { // if a camera position is given, no cycle should be possible throw new IllegalStateException("Failed to sort"); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java index 10aa0c0b1a..5c104be708 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java @@ -21,7 +21,7 @@ static StaticTopoAcyclicData fromMesh(BuiltSectionMeshParts translucentMesh, var buffer = new NativeBuffer(TranslucentData.vertexCountToIndexBytes(range.vertexCount())); var indexBuffer = buffer.getDirectBuffer().asIntBuffer(); - if (!ComplexSorting.topoSortFullGraphAcyclic(indexBuffer, quads, null, null)) { + if (!ComplexSorting.topoSortDepthFirstCyclic(indexBuffer, quads, null, null)) { System.out.println("Failed to sort topo static because there was a cycle"); } From 18941544f2f5ffea018420e33d0021ad5a0b1e35 Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 6 Oct 2023 18:49:08 +0200 Subject: [PATCH 077/256] do sorts immediately if they are close --- .../client/render/chunk/ChunkUpdateType.java | 12 ++++-- .../render/chunk/RenderSectionManager.java | 37 +++++++++++-------- .../client/render/chunk/gfni/DynamicData.java | 3 +- .../chunk/gfni/PresentTranslucentData.java | 4 ++ 4 files changed, 36 insertions(+), 20 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkUpdateType.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkUpdateType.java index acdf4cc544..5ef6229651 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkUpdateType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkUpdateType.java @@ -1,10 +1,11 @@ package me.jellysquid.mods.sodium.client.render.chunk; public enum ChunkUpdateType { - TRANSLUCENT_SORT(Integer.MAX_VALUE), // TODO: translucent sort queuing + SORT(Integer.MAX_VALUE), INITIAL_BUILD(128), REBUILD(Integer.MAX_VALUE), - IMPORTANT_REBUILD(Integer.MAX_VALUE); + IMPORTANT_REBUILD(Integer.MAX_VALUE), + IMPORTANT_SORT(Integer.MAX_VALUE); private final int maximumQueueSize; @@ -13,7 +14,10 @@ public enum ChunkUpdateType { } public static boolean canPromote(ChunkUpdateType prev, ChunkUpdateType next) { - return prev == null || prev == TRANSLUCENT_SORT || (prev == REBUILD && next == IMPORTANT_REBUILD); + return prev == null + || prev == SORT + || (prev == REBUILD && next == IMPORTANT_REBUILD) + || (prev == IMPORTANT_SORT && next == IMPORTANT_REBUILD); } public int getMaximumQueueSize() { @@ -21,6 +25,6 @@ public int getMaximumQueueSize() { } public boolean isImportant() { - return this == IMPORTANT_REBUILD; + return this == IMPORTANT_REBUILD || this == IMPORTANT_SORT; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index 11710f57d4..00d2842ccb 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -86,7 +86,7 @@ public class RenderSectionManager { private int lastUpdatedFrame; - private boolean needsUpdate; + private boolean needsGraphUpdate; private @Nullable BlockPos cameraBlockPos; private @Nullable Vector3fc cameraPosition; @@ -99,7 +99,7 @@ public RenderSectionManager(ClientWorld world, int renderDistance, CommandList c this.builder = new ChunkBuilder(world, ChunkMeshFormats.COMPACT); - this.needsUpdate = true; + this.needsGraphUpdate = true; this.renderDistance = renderDistance; this.regions = new RenderRegionManager(commandList); @@ -121,7 +121,7 @@ public void update(Vector3fc cameraPosition, Camera camera, Viewport viewport, i this.createTerrainRenderList(camera, viewport, frame, spectator); - this.needsUpdate = false; + this.needsGraphUpdate = false; this.lastUpdatedFrame = frame; } @@ -198,7 +198,7 @@ public void onSectionAdded(int x, int y, int z) { this.connectNeighborNodes(renderSection); - this.needsUpdate = true; + this.needsGraphUpdate = true; } public void onSectionRemoved(int x, int y, int z) { @@ -222,7 +222,7 @@ public void onSectionRemoved(int x, int y, int z) { this.gfni.removeSection(section.getTranslucentData(), chunkSectionLongPos); - this.needsUpdate = true; + this.needsGraphUpdate = true; } public void renderLayer(ChunkRenderMatrices matrices, TerrainRenderPass pass, double x, double y, double z) { @@ -286,9 +286,10 @@ public void updateChunks(boolean updateImmediately) { var optionallyBlockingCollector = updateImmediately ? blockingRebuilds : deferredRebuilds; this.submitSectionTasks(blockingRebuilds, ChunkUpdateType.IMPORTANT_REBUILD); + this.submitSectionTasks(blockingRebuilds, ChunkUpdateType.IMPORTANT_SORT); this.submitSectionTasks(optionallyBlockingCollector, ChunkUpdateType.REBUILD); this.submitSectionTasks(optionallyBlockingCollector, ChunkUpdateType.INITIAL_BUILD); - this.submitSectionTasks(optionallyBlockingCollector, ChunkUpdateType.TRANSLUCENT_SORT); + this.submitSectionTasks(optionallyBlockingCollector, ChunkUpdateType.SORT); blockingRebuilds.awaitCompletion(this.builder); } @@ -306,7 +307,7 @@ public void uploadChunks() { result.deleteAfterUpload(); } - this.needsUpdate = true; + this.needsGraphUpdate = true; } private void processChunkBuildResults(ArrayList results) { @@ -389,7 +390,7 @@ private void submitSectionTasks(ChunkJobCollector collector, ChunkUpdateType typ int frame = this.lastUpdatedFrame; ChunkBuilderTask task; - if (type == ChunkUpdateType.TRANSLUCENT_SORT) { + if (type == ChunkUpdateType.SORT || type == ChunkUpdateType.IMPORTANT_SORT) { task = this.createSortTask(section, frame); } else { task = this.createRebuildTask(section, frame); @@ -436,11 +437,11 @@ public void processGFNIMovement( } public void markGraphDirty() { - this.needsUpdate = true; + this.needsGraphUpdate = true; } public boolean needsUpdate() { - return this.needsUpdate; + return this.needsGraphUpdate; } public ChunkBuilder getBuilder() { @@ -488,8 +489,14 @@ public void scheduleSort(ChunkSectionPos pos) { RenderSection section = this.sectionByPosition.get(pos.asLong()); - if (section != null && ChunkUpdateType.canPromote(section.getPendingUpdate(), ChunkUpdateType.TRANSLUCENT_SORT)) { - section.setPendingUpdate(ChunkUpdateType.TRANSLUCENT_SORT); + if (section != null) { + var pendingUpdate = ChunkUpdateType.SORT; + if (this.shouldPrioritizeTask(section)) { + pendingUpdate = ChunkUpdateType.IMPORTANT_SORT; + } + if (ChunkUpdateType.canPromote(section.getPendingUpdate(), pendingUpdate)) { + section.setPendingUpdate(pendingUpdate); + } } } @@ -501,7 +508,7 @@ public void scheduleRebuild(int x, int y, int z, boolean important) { if (section != null && section.isBuilt()) { ChunkUpdateType pendingUpdate; - if (allowImportantRebuilds() && (important || this.shouldPrioritizeRebuild(section))) { + if (allowImportantRebuilds() && (important || this.shouldPrioritizeTask(section))) { pendingUpdate = ChunkUpdateType.IMPORTANT_REBUILD; } else { pendingUpdate = ChunkUpdateType.REBUILD; @@ -510,14 +517,14 @@ public void scheduleRebuild(int x, int y, int z, boolean important) { if (ChunkUpdateType.canPromote(section.getPendingUpdate(), pendingUpdate)) { section.setPendingUpdate(pendingUpdate); - this.needsUpdate = true; + this.needsGraphUpdate = true; } } } private static final float NEARBY_REBUILD_DISTANCE = MathHelper.square(16.0f); - private boolean shouldPrioritizeRebuild(RenderSection section) { + private boolean shouldPrioritizeTask(RenderSection section) { return this.cameraPosition != null && section.getSquaredDistance(this.cameraBlockPos) < NEARBY_REBUILD_DISTANCE; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java index ba5b9748a3..387e083a6c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java @@ -37,7 +37,8 @@ public void sort(Vector3fc cameraPos) { if (!ComplexSorting.topoSortDepthFirstCyclic(indexBuffer, this.quads, this.distancesByNormal, cameraPos)) { // if a camera position is given, no cycle should be possible - throw new IllegalStateException("Failed to sort"); + // throw new IllegalStateException("Failed to sort at" + this.sectionPos); + System.out.println("Failed to sort at " + this.sectionPos); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/PresentTranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/PresentTranslucentData.java index aea6b0895d..b10b7cb32a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/PresentTranslucentData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/PresentTranslucentData.java @@ -23,6 +23,10 @@ public void delete() { } } + public int getQuadLength() { + return this.buffer.getLength() / BYTES_PER_INDEX / VERTICES_PER_QUAD; + } + static NativeBuffer nativeBufferForQuads(TQuad[] quads) { return new NativeBuffer(TranslucentData.quadCountToIndexBytes(quads.length)); } From 2abc0113baeb167081fe8ee26c2ee5111bacb8e9 Mon Sep 17 00:00:00 2001 From: douira Date: Tue, 10 Oct 2023 01:59:05 +0200 Subject: [PATCH 078/256] split tesselation deletion into two methods --- .../sodium/client/render/chunk/region/RenderRegion.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java index 285c870fd4..8841e7b909 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java @@ -149,7 +149,7 @@ public void refresh(CommandList commandList) { public void refreshTranslucent(CommandList commandList) { if (this.resources != null) { - this.resources.deleteTessellations(commandList); + this.resources.deleteIndexedTessellation(commandList); } if (this.translucentIndexData != null) { @@ -260,6 +260,9 @@ public void deleteTessellations(CommandList commandList) { this.tessellation.delete(commandList); this.tessellation = null; } + } + + public void deleteIndexedTessellation(CommandList commandList) { if (this.indexedTessellation != null) { this.indexedTessellation.delete(commandList); this.indexedTessellation = null; @@ -276,6 +279,7 @@ public GlBuffer getIndexBuffer() { public void delete(CommandList commandList) { this.deleteTessellations(commandList); + this.deleteIndexedTessellation(commandList); this.geometryArena.delete(commandList); this.indexArena.delete(commandList); } From c29428fa4be5105b89aacb9a0019266a8d4f4940 Mon Sep 17 00:00:00 2001 From: douira Date: Tue, 10 Oct 2023 02:37:08 +0200 Subject: [PATCH 079/256] rename index buffer writing methods for clarity --- .../client/render/chunk/gfni/StaticNormalRelativeData.java | 4 ++-- .../mods/sodium/client/render/chunk/gfni/TranslucentData.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java index 29d30b0811..ae3541067b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java @@ -50,7 +50,7 @@ private static StaticNormalRelativeData fromDoubleUnaligned(BuiltSectionMeshPart ranges[ModelQuadFacing.UNASSIGNED.ordinal()].vertexCount())); IntBuffer bufferBuilder = buffer.getDirectBuffer().asIntBuffer(); - TranslucentData.writeVertexIndexes(bufferBuilder, MergeSort.mergeSort(keys)); + TranslucentData.writeQuadVertexIndexes(bufferBuilder, MergeSort.mergeSort(keys)); return new StaticNormalRelativeData(sectionPos, buffer, ranges); } @@ -96,7 +96,7 @@ private static StaticNormalRelativeData fromAligned(BuiltSectionMeshParts transl // add the vertex start converted to quads to the offset to get the real quad // index and not just the index local to the direction's set of quads - TranslucentData.writeVertexIndexesOffset(bufferBuilder, sorter.sort(centers[i]), + TranslucentData.writeQuadVertexIndexesOffset(bufferBuilder, sorter.sort(centers[i]), range.vertexStart() / TranslucentData.VERTICES_PER_QUAD); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java index 87dfe7b6c4..14bfadfdf1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java @@ -59,13 +59,13 @@ static void putQuadVertexIndexes(IntBuffer intBuffer, int quadIndex) { intBuffer.put(vertexOffset + 0); } - static void writeVertexIndexes(IntBuffer intBuffer, int[] quadIndexes) { + static void writeQuadVertexIndexes(IntBuffer intBuffer, int[] quadIndexes) { for (int quadIndexPos = 0; quadIndexPos < quadIndexes.length; quadIndexPos++) { putQuadVertexIndexes(intBuffer, quadIndexes[quadIndexPos]); } } - static void writeVertexIndexesOffset(IntBuffer intBuffer, int[] quadIndexes, int offset) { + static void writeQuadVertexIndexesOffset(IntBuffer intBuffer, int[] quadIndexes, int offset) { for (int quadIndexPos = 0; quadIndexPos < quadIndexes.length; quadIndexPos++) { putQuadVertexIndexes(intBuffer, quadIndexes[quadIndexPos] + offset); } From c0d4606e26222f22d54d1be21a0195e944e45864 Mon Sep 17 00:00:00 2001 From: douira Date: Tue, 10 Oct 2023 04:27:44 +0200 Subject: [PATCH 080/256] rename last task time on render section to something more useful --- .../mods/sodium/client/render/chunk/RenderSection.java | 10 +++++----- .../client/render/chunk/RenderSectionManager.java | 7 ++++--- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java index e566b5c3ce..8fa3ac7bcb 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java @@ -59,7 +59,7 @@ public class RenderSection { @Nullable private ChunkUpdateType pendingUpdateType; - private int lastTaskFrame = -1; + private int lastUploadFrame = -1; private int lastSubmittedFrame = -1; // Lifetime state @@ -344,12 +344,12 @@ public void setPendingUpdate(@Nullable ChunkUpdateType type) { this.pendingUpdateType = type; } - public int getLastTaskFrame() { - return this.lastTaskFrame; + public int getLastUploadFrame() { + return this.lastUploadFrame; } - public void setLastTaskFrame(int lastSortFrame) { - this.lastTaskFrame = lastSortFrame; + public void setLastUploadFrame(int lastSortFrame) { + this.lastUploadFrame = lastSortFrame; } public int getLastSubmittedFrame() { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index 00d2842ccb..2fbf2bc587 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -307,7 +307,8 @@ public void uploadChunks() { result.deleteAfterUpload(); } - this.needsGraphUpdate = true; + // TODO: only needed if the tasks actually changed the visibility (sort tasks don't count, though there would never be a sort task without camera movement so it likely doesn't matter) + this.needsGraphUpdate = true; } private void processChunkBuildResults(ArrayList results) { @@ -333,7 +334,7 @@ private void processChunkBuildResults(ArrayList results) { result.render.setTaskCancellationToken(null); } - result.render.setLastTaskFrame(result.submitTime); + result.render.setLastUploadFrame(result.submitTime); } } @@ -352,7 +353,7 @@ private static List filterChunkBuildResults(ArrayList(); for (var output : outputs) { - if (output.render.isDisposed() || output.render.getLastTaskFrame() > output.submitTime) { + if (output.render.isDisposed() || output.render.getLastUploadFrame() > output.submitTime) { continue; } From 20341dab86b9fc43abb15d1cd1e4b5105f148d0c Mon Sep 17 00:00:00 2001 From: douira Date: Tue, 10 Oct 2023 04:44:36 +0200 Subject: [PATCH 081/256] fix issues with topo sort by introducing epsilon uncertainty --- .../render/chunk/gfni/ComplexSorting.java | 42 +++++++++++++++---- .../sodium/client/render/chunk/gfni/GFNI.java | 19 +++++---- .../render/chunk/gfni/TranslucentData.java | 6 ++- 3 files changed, 49 insertions(+), 18 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java index 501d6cc2f1..56af6ec9a6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java @@ -33,6 +33,10 @@ private static boolean pointOutsideHalfspace(Vector3fc planeAnchor, Vector3fc pl return halfspace(planeAnchor, planeNormal, point) > 0; } + private static boolean pointInsideHalfSpace(Vector3fc planeAnchor, Vector3fc planeNormal, Vector3fc point) { + return halfspace(planeAnchor, planeNormal, point) < 0; + } + public static void distanceSortModified(IntBuffer indexBuffer, TQuad[] quads, Vector3fc cameraPos) { int[] indexes = new int[quads.length]; BitArray visible = new BitArray(quads.length); @@ -90,7 +94,7 @@ public static void distanceSortModified(IntBuffer indexBuffer, TQuad[] quads, Ve return 0; }); - TranslucentData.writeVertexIndexes(indexBuffer, indexes); + TranslucentData.writeQuadVertexIndexes(indexBuffer, indexes); } private static int[] distanceSortIndexes(TQuad[] quads, Vector3fc cameraPos) { @@ -104,7 +108,7 @@ private static int[] distanceSortIndexes(TQuad[] quads, Vector3fc cameraPos) { public static void distanceSortDirect(IntBuffer indexBuffer, TQuad[] quads, Vector3fc cameraPos) { var indexes = distanceSortIndexes(quads, cameraPos); - TranslucentData.writeVertexIndexes(indexBuffer, indexes); + TranslucentData.writeQuadVertexIndexes(indexBuffer, indexes); } private static boolean orthoExtentWithinHalfspace(TQuad halfspace, TQuad otherQuad) { @@ -112,7 +116,7 @@ private static boolean orthoExtentWithinHalfspace(TQuad halfspace, TQuad otherQu var otherQuadOppositeDirection = halfspace.facing().getOpposite().ordinal(); var sign = halfspace.facing().getSign(); - return sign * halfspace.extents()[halfspaceDirection] > sign * otherQuad.extents()[otherQuadOppositeDirection]; + return sign * halfspace.extents()[halfspaceDirection] - QUERY_EPSILON > sign * otherQuad.extents()[otherQuadOppositeDirection]; } private static boolean orthogonalQuadVisibleThrough(TQuad quad, TQuad otherQuad) { @@ -327,13 +331,15 @@ public static boolean topoSortAlignedScanningCyclic(IntBuffer indexBuffer, TQuad return true; } + private static final float QUERY_EPSILON = 0.0011f; + private static boolean testSeparatorRange(Object2ReferenceOpenHashMap distancesByNormal, Vector3fc normal, float start, float end) { var distances = distancesByNormal.get(normal); if (distances == null) { return false; } - return Group.queryRange(distances, start, end); + return Group.queryRange(distances, start - QUERY_EPSILON, end + QUERY_EPSILON); } private static boolean visibilityWithSeparator(TQuad quadA, TQuad quadB, @@ -370,6 +376,8 @@ private static boolean visibilityWithSeparator(TQuad quadA, TQuad quadB, } } + // TODO: check all other normals too + // visibility not disproven return true; } @@ -415,10 +423,10 @@ private static boolean quadVisibleThrough(TQuad quad, TQuad other, } else { // at least one unaligned quad // this is an approximation since our quads don't store all their vertices. - // check that other center is within the halfspace of quad and that the normals - // are more than 90 degrees apart - result = halfspace(quad.center(), quad.normal(), other.center()) < 0 - && quad.normal().dot(other.normal()) < 0; + // check that other center is within the halfspace of quad and that quad isn't + // in the halfspace of other + result = pointInsideHalfSpace(quad.center(), quad.normal(), other.center()) + && !pointInsideHalfSpace(other.center(), other.normal(), quad.center()); } // if enabled and necessary, try to disprove this see-through relationship with @@ -595,6 +603,21 @@ && quadVisibleThrough(quad, otherQuad, distancesByNormal, cameraPos)) { return true; } + /** + * Performs a topological sort without constructing the full graph in memory by + * doing a DFS on the implicit graph. Edges are tested as they are searched for + * and if necessary separator planes are used to disprove visibility. + * + * TODO: the issue with it sometimes failing to sort is probably from the + * separator mechanism not working for unaligned quads yet. + * + * @param indexBuffer the buffer to write the topo sort result to + * @param allQuads the quads to sort + * @param distancesByNormal a map of normals to sorted arrays of face plane + * distances, null to disable + * @param cameraPos the camera position, or null to disable the + * visibility check + */ public static boolean topoSortDepthFirstCyclic( IntBuffer indexBuffer, TQuad[] allQuads, Object2ReferenceOpenHashMap distancesByNormal, @@ -612,6 +635,9 @@ public static boolean topoSortDepthFirstCyclic( for (int i = 0; i < allQuads.length; i++) { TQuad quad = allQuads[i]; + // TODO: this could introduce wrong sorting if the real normal and the quantized + // normal don't line up, ignoring the quad if it's not visible through the + // quantized one but visible in-camera if (pointOutsideHalfspace(quad.center(), quad.normal(), cameraPos)) { activeToRealIndex[activeQuads] = i; quads[activeQuads] = quad; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java index 1c2266969d..7c92d16e5a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java @@ -17,20 +17,21 @@ * Distances are stored as doubles and normals are stored as float vectors. * * TODO: - * - sort the triggered sections by camera distance and possibly also use number - * of translucent faces as a heuristic for importance - * - baked models could possibly precompute normals and then just calculate - * distances when processing a chunk? * - many sections can be marked as needing an update but they are only actually * scheduled for sorting when the RenderSectionManager makes them visible. This * may result in many sections suddenly needing sorting when the camera moves. * Maybe it's better to schedule them to be sorted gradually even if not * visible, if there are idle threads. - * - problem: when there are two parallel planes made up of many quads each, - * sorting the whole thing from one perspective means the sorting is wrong when - * we look at it from another perspective. This happens because there is no - * trigger in the plane. Sorting as if the entire thing was one quad would fix - * it. + * - sort only up to a certain number of quads to limit rebuild time to some + * fixed value. determine how many that is by observing timings. + * - there's a scheduling issue when moving around flowing water on the floor + * and adding blocks in movement. Probably an issue with upgrading sort tasks to + * rebuild while they're running. Maybe it marks sections as built when + * they've been sorted even though it shouldn't? + * - De-epsilon all the geometry by snapping to multiples of 0.005 or sth like + * that. Would simplify the ComplexSorting code so that it doesn't need to deal + * with the existence of error margins (epsilons in the trigger distances and + * the centers). * * @author douira */ diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java index 14bfadfdf1..e194f30003 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java @@ -26,10 +26,14 @@ public void delete() { } public void sort(Vector3fc cameraPos) { - // there should be no sort calls to data that doesn't need sorting + // there should be no sort calls to data that doesn't need dynamic sorting throw new UnsupportedOperationException(); } + public void timedSort(Vector3fc cameraPos) { + // TODO: collect and analyze timing data, actually call this method instead of sort + } + static int vertexCountToIndexBytes(int vertexCount) { // convert vertex count to quads, and then to indices, and then to bytes return vertexCount / VERTICES_PER_QUAD * INDICES_PER_QUAD * BYTES_PER_INDEX; From a0050e8e55763713321dd75bde547a43a4b7868a Mon Sep 17 00:00:00 2001 From: douira Date: Tue, 10 Oct 2023 21:37:39 +0200 Subject: [PATCH 082/256] fix chunk task promotion --- .../client/render/chunk/ChunkUpdateType.java | 15 ++++++++----- .../render/chunk/RenderSectionManager.java | 22 +++++++++++++------ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkUpdateType.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkUpdateType.java index 5ef6229651..0c00fb0ecd 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkUpdateType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkUpdateType.java @@ -13,11 +13,16 @@ public enum ChunkUpdateType { this.maximumQueueSize = maximumQueueSize; } - public static boolean canPromote(ChunkUpdateType prev, ChunkUpdateType next) { - return prev == null - || prev == SORT - || (prev == REBUILD && next == IMPORTANT_REBUILD) - || (prev == IMPORTANT_SORT && next == IMPORTANT_REBUILD); + public static ChunkUpdateType getPromotionUpdateType(ChunkUpdateType prev, ChunkUpdateType next) { + if (prev == null || prev == SORT || prev == next) { + return next; + } + if (next == IMPORTANT_REBUILD + || (prev == IMPORTANT_SORT && next == REBUILD) + || (prev == REBUILD && next == IMPORTANT_SORT)) { + return IMPORTANT_REBUILD; + } + return null; } public int getMaximumQueueSize() { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index 2fbf2bc587..c0b4442ec8 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -307,8 +307,10 @@ public void uploadChunks() { result.deleteAfterUpload(); } - // TODO: only needed if the tasks actually changed the visibility (sort tasks don't count, though there would never be a sort task without camera movement so it likely doesn't matter) - this.needsGraphUpdate = true; + // TODO: only needed if the tasks actually changed the visibility (sort tasks + // don't count, though there would never be a sort task without camera movement + // so it likely doesn't matter) + this.needsGraphUpdate = true; } private void processChunkBuildResults(ArrayList results) { @@ -339,7 +341,8 @@ private void processChunkBuildResults(ArrayList results) { } private void updateSectionInfo(RenderSection render, BuiltSectionInfo info) { - // TODO: make this work with translucent data and figure out a nice way to use BuilderTaskOutput + // TODO: make this work with translucent data and figure out a nice way to use + // BuilderTaskOutput render.setInfo(info); if (info == null || ArrayUtils.isEmpty(info.globalBlockEntities)) { @@ -403,8 +406,11 @@ private void submitSectionTasks(ChunkJobCollector collector, ChunkUpdateType typ section.setTaskCancellationToken(job); } else { - // TODO: why does this exist and where is this data read? is null translucent data ok? - var result = ChunkJobResult.successfully(new ChunkBuildOutput(section, frame, null, BuiltSectionInfo.EMPTY, Collections.emptyMap())); + // TODO: why does this exist and where is this data read? is null translucent + // data ok? + var result = ChunkJobResult.successfully(new ChunkBuildOutput( + section, frame, null, + BuiltSectionInfo.EMPTY, Collections.emptyMap())); this.buildResults.add(result); section.setTaskCancellationToken(null); @@ -495,7 +501,8 @@ public void scheduleSort(ChunkSectionPos pos) { if (this.shouldPrioritizeTask(section)) { pendingUpdate = ChunkUpdateType.IMPORTANT_SORT; } - if (ChunkUpdateType.canPromote(section.getPendingUpdate(), pendingUpdate)) { + pendingUpdate = ChunkUpdateType.getPromotionUpdateType(section.getPendingUpdate(), pendingUpdate); + if (pendingUpdate != null) { section.setPendingUpdate(pendingUpdate); } } @@ -515,7 +522,8 @@ public void scheduleRebuild(int x, int y, int z, boolean important) { pendingUpdate = ChunkUpdateType.REBUILD; } - if (ChunkUpdateType.canPromote(section.getPendingUpdate(), pendingUpdate)) { + pendingUpdate = ChunkUpdateType.getPromotionUpdateType(section.getPendingUpdate(), pendingUpdate); + if (pendingUpdate != null) { section.setPendingUpdate(pendingUpdate); this.needsGraphUpdate = true; From a8e9433ef5320e0c9814469e82c07b2ed628f6ac Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 13 Oct 2023 03:45:56 +0200 Subject: [PATCH 083/256] fix SNR sort order --- .../mods/sodium/client/util/sorting/VertexSorters.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/VertexSorters.java b/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/VertexSorters.java index a2c6e5ce99..2f96189b1d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/VertexSorters.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/VertexSorters.java @@ -61,7 +61,7 @@ private SortByAxis(int axis, float sign) { @Override protected float getKey(Vector3f position) { - return sign * position.get(this.axis); + return -sign * position.get(this.axis); } } @@ -78,6 +78,9 @@ protected float getKey(Vector3f position) { } } + /** + * Sorts the keys given by the subclass by descending value. + */ private static abstract class AbstractVertexSorter implements VertexSorter { @Override public final int[] sort(Vector3f[] positions) { From 2c5d97ce2e6cccf0ee716ee6a86613c5dba953de Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 13 Oct 2023 03:59:09 +0200 Subject: [PATCH 084/256] fix rendering corruption and index buffer generation, thanks to embeddedt for helping out with debugging --- .../render/chunk/data/SectionRenderDataStorage.java | 12 ++++++++---- .../render/chunk/data/SectionRenderDataUnsafe.java | 12 +++++++++++- .../client/render/chunk/gfni/AnyOrderData.java | 9 ++++++++- .../render/chunk/gfni/PresentTranslucentData.java | 3 +++ .../render/chunk/gfni/SplitDirectionData.java | 5 +++++ .../render/chunk/gfni/StaticNormalRelativeData.java | 3 +-- .../client/render/chunk/gfni/TranslucentData.java | 13 ++++++------- .../client/render/chunk/region/RenderRegion.java | 4 ++-- 8 files changed, 44 insertions(+), 17 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java index dbb39a9d3e..409502a752 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java @@ -11,9 +11,11 @@ public class SectionRenderDataStorage { private final GlBufferSegment[] allocations = new GlBufferSegment[RenderRegion.REGION_SIZE]; private final long pMeshDataArray; + private final boolean storesIndices; - public SectionRenderDataStorage() { + public SectionRenderDataStorage(boolean storesIndices) { this.pMeshDataArray = SectionRenderDataUnsafe.allocateHeap(RenderRegion.REGION_SIZE); + this.storesIndices = storesIndices; } public void setMeshes(int localSectionIndex, @@ -41,13 +43,14 @@ public void setMeshes(int localSectionIndex, } SectionRenderDataUnsafe.setVertexOffset(pMeshData, facingIndex, vertexOffset); - SectionRenderDataUnsafe.setElementCount(pMeshData, facingIndex, (vertexCount >> 2) * 6); + var elementCount = (vertexCount >> 2) * 6; + SectionRenderDataUnsafe.setElementCount(pMeshData, facingIndex, elementCount); if (vertexCount > 0) { sliceMask |= 1 << facingIndex; } - vertexOffset += vertexCount; + vertexOffset += this.storesIndices ? elementCount : vertexCount; } SectionRenderDataUnsafe.setSliceMask(pMeshData, sliceMask); @@ -84,7 +87,8 @@ private void updateMeshes(int sectionIndex) { SectionRenderDataUnsafe.setVertexOffset(data, facing, offset); var count = SectionRenderDataUnsafe.getElementCount(data, facing); - offset += (count / 6) * 4; // convert elements back into vertices + // TODO: fix this when storesIndices is true, it currently just explodes + offset += this.storesIndices ? count : (count / 6) * 4; // convert elements back into vertices } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataUnsafe.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataUnsafe.java index 6b87cb32c8..f536aeaad2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataUnsafe.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataUnsafe.java @@ -14,6 +14,16 @@ // // Please never try to write performance critical code in Java. This is what it will do to you. And you will still be // three times slower than the most naive solution in literally any other language that LLVM can compile. + +// the structure is roughly as follows: +// struct SectionRenderData { // 64 bytes +// mask: u32, +// ranges: [VertexRange; 7] +// } +// struct VertexRange { // 8 bytes +// offset: u32, +// count: u32 +// } public class SectionRenderDataUnsafe { private static final long OFFSET_SLICE_MASK = 0; private static final long OFFSET_SLICE_RANGES = 8; @@ -59,4 +69,4 @@ public static void setElementCount(long ptr, int facing, int value) { public static int getElementCount(long ptr, int facing) { return MemoryUtil.memGetInt(ptr + OFFSET_SLICE_RANGES + (facing * 8L) + 4L); } -} \ No newline at end of file +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AnyOrderData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AnyOrderData.java index 537ee3d63f..1297e8c72e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AnyOrderData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AnyOrderData.java @@ -29,8 +29,15 @@ static AnyOrderData fromMesh(BuiltSectionMeshParts translucentMesh, TQuad[] quads, ChunkSectionPos sectionPos) { var buffer = PresentTranslucentData.nativeBufferForQuads(quads); var indexBuffer = buffer.getDirectBuffer().asIntBuffer(); + var counter = 0; + var lastFacing = quads[0].facing(); for (int i = 0; i < quads.length; i++) { - TranslucentData.putQuadVertexIndexes(indexBuffer, i); + var currentFacing = quads[i].facing(); + if (i > 0 && currentFacing != lastFacing) { + counter = 0; + } + lastFacing = currentFacing; + TranslucentData.putQuadVertexIndexes(indexBuffer, counter++); } return new AnyOrderData(sectionPos, buffer, translucentMesh.getVertexRanges()); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/PresentTranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/PresentTranslucentData.java index b10b7cb32a..1343f47b20 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/PresentTranslucentData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/PresentTranslucentData.java @@ -4,6 +4,9 @@ import me.jellysquid.mods.sodium.client.util.NativeBuffer; import net.minecraft.util.math.ChunkSectionPos; +/** + * Super class for translucent data that contains an actual buffer. + */ public abstract class PresentTranslucentData extends TranslucentData { public NativeBuffer buffer; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/SplitDirectionData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/SplitDirectionData.java index 5aa0823760..a82d03f627 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/SplitDirectionData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/SplitDirectionData.java @@ -4,6 +4,11 @@ import me.jellysquid.mods.sodium.client.util.NativeBuffer; import net.minecraft.util.math.ChunkSectionPos; +/** + * Super class for translucent data that is rendered separately for each facing. + * It's important that the indices are inserted starting at zero for each + * direction. + */ public abstract class SplitDirectionData extends PresentTranslucentData { public final VertexRange[] ranges; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java index ae3541067b..124bd7ce00 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java @@ -96,8 +96,7 @@ private static StaticNormalRelativeData fromAligned(BuiltSectionMeshParts transl // add the vertex start converted to quads to the offset to get the real quad // index and not just the index local to the direction's set of quads - TranslucentData.writeQuadVertexIndexesOffset(bufferBuilder, sorter.sort(centers[i]), - range.vertexStart() / TranslucentData.VERTICES_PER_QUAD); + TranslucentData.writeQuadVertexIndexes(bufferBuilder, sorter.sort(centers[i])); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java index e194f30003..0edfee80b7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java @@ -9,6 +9,10 @@ import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; import net.minecraft.util.math.ChunkSectionPos; +/** + * The base class for all types of translucent data. Subclasses are generated by + * the geometry collector after the section is built. + */ public abstract class TranslucentData { public static final int INDICES_PER_QUAD = 6; public static final int VERTICES_PER_QUAD = 4; @@ -31,7 +35,8 @@ public void sort(Vector3fc cameraPos) { } public void timedSort(Vector3fc cameraPos) { - // TODO: collect and analyze timing data, actually call this method instead of sort + // TODO: collect and analyze timing data, actually call this method instead of + // sort } static int vertexCountToIndexBytes(int vertexCount) { @@ -69,12 +74,6 @@ static void writeQuadVertexIndexes(IntBuffer intBuffer, int[] quadIndexes) { } } - static void writeQuadVertexIndexesOffset(IntBuffer intBuffer, int[] quadIndexes, int offset) { - for (int quadIndexPos = 0; quadIndexPos < quadIndexes.length; quadIndexPos++) { - putQuadVertexIndexes(intBuffer, quadIndexes[quadIndexPos] + offset); - } - } - static VertexRange getUnassignedVertexRange(BuiltSectionMeshParts translucentMesh) { VertexRange range = translucentMesh.getVertexRanges()[ModelQuadFacing.UNASSIGNED.ordinal()]; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java index 8841e7b909..7ecc1c49ae 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java @@ -123,7 +123,7 @@ public SectionRenderDataStorage createStorage(TerrainRenderPass pass) { var storage = this.sectionRenderData.get(pass); if (storage == null) { - this.sectionRenderData.put(pass, storage = new SectionRenderDataStorage()); + this.sectionRenderData.put(pass, storage = new SectionRenderDataStorage(false)); } return storage; @@ -131,7 +131,7 @@ public SectionRenderDataStorage createStorage(TerrainRenderPass pass) { public SectionRenderDataStorage createTranslucentStorage() { if (this.translucentIndexData == null) { - return this.translucentIndexData = new SectionRenderDataStorage(); + return this.translucentIndexData = new SectionRenderDataStorage(true); } return this.translucentIndexData; From 692bd9ab76fa3095e30d8e2e05d84012d7626b57 Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 13 Oct 2023 05:19:42 +0200 Subject: [PATCH 085/256] make the bottom face of flowing liquids UNASSIGNED to fix translucency sorting issues --- .../client/render/chunk/compile/pipeline/FluidRenderer.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java index 6a65276e75..f4fabb53b7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java @@ -27,7 +27,6 @@ import net.minecraft.block.BlockState; import net.minecraft.block.SideShapeType; import net.minecraft.client.MinecraftClient; -import net.minecraft.client.render.model.ModelLoader; import net.minecraft.client.texture.Sprite; import net.minecraft.fluid.Fluid; import net.minecraft.fluid.FluidState; @@ -232,7 +231,7 @@ public void render(WorldSlice world, FluidState fluidState, BlockPos blockPos, B if (fluidState.canFlowTo(world, this.scratchPos.set(posX, posY + 1, posZ))) { this.writeQuad(meshBuilder, collector, material, offset, quad, - ModelQuadFacing.NEG_Y, true); + ModelQuadFacing.UNASSIGNED, true); } From 8d7b9f5eb85b709bd0aa2c80c53a81080973245f Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 14 Oct 2023 02:13:12 +0200 Subject: [PATCH 086/256] make sorting non-dynamic data not an error --- .../chunk/gfni/DynamicTopoCyclicData.java | 29 ------------------- .../render/chunk/gfni/TranslucentData.java | 5 ++-- 2 files changed, 3 insertions(+), 31 deletions(-) delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicTopoCyclicData.java diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicTopoCyclicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicTopoCyclicData.java deleted file mode 100644 index d360101e91..0000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicTopoCyclicData.java +++ /dev/null @@ -1,29 +0,0 @@ -package me.jellysquid.mods.sodium.client.render.chunk.gfni; - -import org.joml.Vector3fc; - -import it.unimi.dsi.fastutil.objects.ReferenceArrayList; -import me.jellysquid.mods.sodium.client.gl.util.VertexRange; -import me.jellysquid.mods.sodium.client.util.NativeBuffer; -import net.minecraft.util.math.ChunkSectionPos; - -/** - * TODO: implement - */ -public class DynamicTopoCyclicData extends MixedDirectionData { - public final ReferenceArrayList orders; - - public static record SortOrder(VertexRange range, Vector3fc normal, double distance) { - } - - public DynamicTopoCyclicData(ChunkSectionPos sectionPos, - NativeBuffer buffer, VertexRange range, ReferenceArrayList orders) { - super(sectionPos, buffer, range); - this.orders = orders; - } - - @Override - public SortType getSortType() { - throw new UnsupportedOperationException(); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java index 0edfee80b7..7d4ee367cc 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java @@ -30,8 +30,9 @@ public void delete() { } public void sort(Vector3fc cameraPos) { - // there should be no sort calls to data that doesn't need dynamic sorting - throw new UnsupportedOperationException(); + // noop sorting when this is called on non-dynamic data. + // this can happen when the section is rebuilt as non-dynamic after it's been + // scheduled for sorting } public void timedSort(Vector3fc cameraPos) { From 9b424a2d8ec5e2d37cb035649905771409bd6894 Mon Sep 17 00:00:00 2001 From: douira Date: Tue, 17 Oct 2023 02:41:28 +0200 Subject: [PATCH 087/256] notes --- .../mods/sodium/client/render/chunk/gfni/GFNI.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java index 7c92d16e5a..2daae4b351 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java @@ -24,10 +24,7 @@ * visible, if there are idle threads. * - sort only up to a certain number of quads to limit rebuild time to some * fixed value. determine how many that is by observing timings. - * - there's a scheduling issue when moving around flowing water on the floor - * and adding blocks in movement. Probably an issue with upgrading sort tasks to - * rebuild while they're running. Maybe it marks sections as built when - * they've been sorted even though it shouldn't? + * - implement angle-based triggering for difficult or large sections * - De-epsilon all the geometry by snapping to multiples of 0.005 or sth like * that. Would simplify the ComplexSorting code so that it doesn't need to deal * with the existence of error margins (epsilons in the trigger distances and From f1590db09a651a265dcce99f332be4525b15aebe Mon Sep 17 00:00:00 2001 From: douira Date: Thu, 19 Oct 2023 16:23:25 +0200 Subject: [PATCH 088/256] add cancellation opportunity right before translucent sorting --- .../render/chunk/compile/tasks/ChunkBuilderMeshingTask.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java index a7672028c4..804d4d0f6f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java @@ -161,6 +161,11 @@ public ChunkBuildOutput execute(ChunkBuildContext buildContext, CancellationToke } } + // cancellation opportunity right before translucent sorting + if (cancellationToken.isCancelled()) { + return null; + } + TranslucentData translucentData = null; if (collector != null) { translucentData = collector.getTranslucentData(meshes.get(DefaultTerrainRenderPasses.TRANSLUCENT), cameraPos); From 035000ecb96776b9b98853f93e0d7d33c31c1807 Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 20 Oct 2023 01:56:50 +0200 Subject: [PATCH 089/256] implement angle-based triggering as fallback, WIP doesn't yet work with very close sections --- .../client/render/SodiumWorldRenderer.java | 24 +- .../client/render/chunk/RenderSection.java | 7 + .../render/chunk/RenderSectionManager.java | 36 ++- .../render/chunk/compile/ChunkSortOutput.java | 2 +- .../tasks/ChunkBuilderMeshingTask.java | 4 +- .../tasks/ChunkBuilderSortingTask.java | 7 +- .../chunk/compile/tasks/ChunkBuilderTask.java | 16 +- .../render/chunk/gfni/CameraMovement.java | 6 + .../render/chunk/gfni/ComplexSorting.java | 1 + .../client/render/chunk/gfni/DynamicData.java | 115 ++++++- .../sodium/client/render/chunk/gfni/GFNI.java | 294 ++++++++++++++---- .../client/render/chunk/gfni/Group.java | 7 +- .../client/render/chunk/gfni/NormalList.java | 23 +- .../client/render/chunk/gfni/SortType.java | 17 +- .../render/chunk/gfni/TranslucentData.java | 22 +- 15 files changed, 444 insertions(+), 137 deletions(-) create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/CameraMovement.java diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index 39f95a0d51..325d851b7a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -7,6 +7,7 @@ import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; import me.jellysquid.mods.sodium.client.render.chunk.ChunkRenderMatrices; import me.jellysquid.mods.sodium.client.render.chunk.RenderSectionManager; +import me.jellysquid.mods.sodium.client.render.chunk.gfni.CameraMovement; import me.jellysquid.mods.sodium.client.render.chunk.lists.ChunkRenderList; import me.jellysquid.mods.sodium.client.render.chunk.lists.SortedRenderLists; import me.jellysquid.mods.sodium.client.render.chunk.map.ChunkTracker; @@ -31,6 +32,8 @@ import java.util.Iterator; import java.util.SortedSet; +import org.joml.Vector3d; + /** * Provides an extension to vanilla's {@link WorldRenderer}. */ @@ -40,7 +43,7 @@ public class SodiumWorldRenderer { private ClientWorld world; private int renderDistance; - private double lastCameraX, lastCameraY, lastCameraZ; + private Vector3d lastCameraPos; private double lastCameraPitch, lastCameraYaw; private float lastFogDistance; @@ -163,12 +166,16 @@ public void setupTerrain(Camera camera, throw new IllegalStateException("Client instance has no active player entity"); } - Vec3d pos = camera.getPos(); + Vec3d posRaw = camera.getPos(); + Vector3d pos = new Vector3d(posRaw.getX(), posRaw.getY(), posRaw.getZ()); float pitch = camera.getPitch(); float yaw = camera.getYaw(); float fogDistance = RenderSystem.getShaderFogEnd(); - boolean cameraLocationChanged = pos.x != this.lastCameraX || pos.y != this.lastCameraY || pos.z != this.lastCameraZ; + if (this.lastCameraPos == null) { + this.lastCameraPos = new Vector3d(pos); + } + boolean cameraLocationChanged = !pos.equals(this.lastCameraPos); boolean dirty = cameraLocationChanged || pitch != this.lastCameraPitch || yaw != this.lastCameraYaw || fogDistance != this.lastFogDistance; @@ -192,16 +199,17 @@ public void setupTerrain(Camera camera, if (this.renderSectionManager.needsUpdate()) { profiler.swap("chunk_render_lists"); - this.renderSectionManager.update(pos.toVector3f(), camera, viewport, frame, spectator); + this.renderSectionManager.update(pos, camera, viewport, frame, spectator); } if (cameraLocationChanged) { profiler.swap("gfni_query"); - this.renderSectionManager.processGFNIMovement(lastCameraX, lastCameraY, lastCameraZ, pos.x, pos.y, pos.z); - this.lastCameraX = pos.x; - this.lastCameraY = pos.y; - this.lastCameraZ = pos.z; + this.renderSectionManager.processGFNIMovement( + new CameraMovement(lastCameraPos, new Vector3d(pos.x, pos.y, pos.z))); + this.lastCameraPos.x = pos.x; + this.lastCameraPos.y = pos.y; + this.lastCameraPos.z = pos.z; } if (updateChunksImmediately) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java index 8fa3ac7bcb..74dc44b321 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java @@ -344,6 +344,13 @@ public void setPendingUpdate(@Nullable ChunkUpdateType type) { this.pendingUpdateType = type; } + public boolean prepareTrigger(boolean isAngleTrigger) { + if (this.translucentData != null) { + return this.translucentData.prepareTrigger(isAngleTrigger); + } + return false; + } + public int getLastUploadFrame() { return this.lastUploadFrame; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index c0b4442ec8..1e368b9f9b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -21,6 +21,8 @@ import me.jellysquid.mods.sodium.client.render.chunk.compile.tasks.ChunkBuilderSortingTask; import me.jellysquid.mods.sodium.client.render.chunk.compile.tasks.ChunkBuilderTask; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionInfo; +import me.jellysquid.mods.sodium.client.render.chunk.gfni.CameraMovement; +import me.jellysquid.mods.sodium.client.render.chunk.gfni.DynamicData; import me.jellysquid.mods.sodium.client.render.chunk.gfni.GFNI; import me.jellysquid.mods.sodium.client.render.chunk.gfni.TranslucentData; import me.jellysquid.mods.sodium.client.render.chunk.lists.ChunkRenderList; @@ -51,7 +53,7 @@ import org.apache.commons.lang3.ArrayUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.joml.Vector3fc; +import org.joml.Vector3dc; import java.util.*; import java.util.concurrent.ConcurrentLinkedDeque; @@ -89,7 +91,7 @@ public class RenderSectionManager { private boolean needsGraphUpdate; private @Nullable BlockPos cameraBlockPos; - private @Nullable Vector3fc cameraPosition; + private @Nullable Vector3dc cameraPosition; public RenderSectionManager(ClientWorld world, int renderDistance, CommandList commandList) { this.chunkRenderer = new DefaultChunkRenderer(RenderDevice.INSTANCE, ChunkMeshFormats.COMPACT); @@ -115,7 +117,7 @@ public RenderSectionManager(ClientWorld world, int renderDistance, CommandList c } } - public void update(Vector3fc cameraPosition, Camera camera, Viewport viewport, int frame, boolean spectator) { + public void update(Vector3dc cameraPosition, Camera camera, Viewport viewport, int frame, boolean spectator) { this.cameraBlockPos = camera.getBlockPos(); this.cameraPosition = cameraPosition; @@ -202,8 +204,8 @@ public void onSectionAdded(int x, int y, int z) { } public void onSectionRemoved(int x, int y, int z) { - long chunkSectionLongPos = ChunkSectionPos.asLong(x, y, z); - RenderSection section = this.sectionByPosition.remove(chunkSectionLongPos); + long sectionPos = ChunkSectionPos.asLong(x, y, z); + RenderSection section = this.sectionByPosition.remove(sectionPos); if (section == null) { return; @@ -220,7 +222,7 @@ public void onSectionRemoved(int x, int y, int z) { section.delete(); - this.gfni.removeSection(section.getTranslucentData(), chunkSectionLongPos); + this.gfni.removeSection(section.getTranslucentData(), sectionPos); this.needsGraphUpdate = true; } @@ -323,11 +325,14 @@ private void processChunkBuildResults(ArrayList results) { if (result instanceof ChunkBuildOutput chunkBuildOutput) { this.updateSectionInfo(result.render, chunkBuildOutput.info); if (chunkBuildOutput.translucentData != null) { - this.gfni.integrateTranslucentData(oldData, chunkBuildOutput.translucentData); + this.gfni.integrateTranslucentData(oldData, chunkBuildOutput.translucentData, this.cameraPosition); } } if (result instanceof ChunkSortOutput chunkSortOutput && chunkSortOutput.translucentData != null) { result.render.setTranslucentData(chunkSortOutput.translucentData); + if (chunkSortOutput.translucentData instanceof DynamicData dynamicData && dynamicData.hasTriggerChanges()) { + this.gfni.applyTriggerChanges(dynamicData, result.render.getPosition(), this.cameraPosition); + } } var job = result.render.getTaskCancellationToken(); @@ -435,12 +440,8 @@ public ChunkBuilderSortingTask createSortTask(RenderSection render, int frame) { return new ChunkBuilderSortingTask(render, frame, this.cameraPosition); } - public void processGFNIMovement( - double lastCameraX, double lastCameraY, double lastCameraZ, - double cameraX, double cameraY, double cameraZ) { - this.gfni.triggerSections(this::scheduleSort, - lastCameraX, lastCameraY, lastCameraZ, - cameraX, cameraY, cameraZ); + public void processGFNIMovement(CameraMovement movement) { + this.gfni.triggerSections(this::scheduleSort, movement); } public void markGraphDirty() { @@ -491,10 +492,10 @@ public int getVisibleChunkCount() { return sections; } - public void scheduleSort(ChunkSectionPos pos) { + public boolean scheduleSort(long sectionPos, boolean isAngleTrigger) { // TODO: Does this need to invalidate the section cache? - RenderSection section = this.sectionByPosition.get(pos.asLong()); + RenderSection section = this.sectionByPosition.get(sectionPos); if (section != null) { var pendingUpdate = ChunkUpdateType.SORT; @@ -504,8 +505,13 @@ public void scheduleSort(ChunkSectionPos pos) { pendingUpdate = ChunkUpdateType.getPromotionUpdateType(section.getPendingUpdate(), pendingUpdate); if (pendingUpdate != null) { section.setPendingUpdate(pendingUpdate); + return section.prepareTrigger(isAngleTrigger); } + } else { + // remove unloaded sections from triggering + return true; } + return false; } public void scheduleRebuild(int x, int y, int z, boolean important) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java index f8e5995999..11bee64e26 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java @@ -17,7 +17,7 @@ public void deleteAfterUpload() { super.deleteAfterUpload(); // delete translucent data if it's not persisted for dynamic sorting - if (this.translucentData != null && !this.translucentData.getSortType().needsPlaneTrigger) { + if (this.translucentData != null && !this.translucentData.getSortType().needsTrigger) { this.translucentData.delete(); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java index 804d4d0f6f..b1d514f5c0 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java @@ -34,7 +34,7 @@ import java.util.Map; -import org.joml.Vector3fc; +import org.joml.Vector3dc; /** * Rebuilds all the meshes of a chunk for each given render pass with non-occluded blocks. The result is then uploaded @@ -46,7 +46,7 @@ public class ChunkBuilderMeshingTask extends ChunkBuilderTask { private final ChunkRenderContext renderContext; - public ChunkBuilderMeshingTask(RenderSection render, int buildTime, Vector3fc cameraPos, ChunkRenderContext renderContext) { + public ChunkBuilderMeshingTask(RenderSection render, int buildTime, Vector3dc cameraPos, ChunkRenderContext renderContext) { super(render, buildTime, cameraPos); this.renderContext = renderContext; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java index 795933bac2..5d447a557c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.render.chunk.compile.tasks; -import org.joml.Vector3fc; +import org.joml.Vector3dc; import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildContext; @@ -8,14 +8,13 @@ import me.jellysquid.mods.sodium.client.util.task.CancellationToken; public class ChunkBuilderSortingTask extends ChunkBuilderTask { - public ChunkBuilderSortingTask(RenderSection render, int frame, Vector3fc absoluteCameraPos) { + public ChunkBuilderSortingTask(RenderSection render, int frame, Vector3dc absoluteCameraPos) { super(render, frame, absoluteCameraPos); } @Override public ChunkSortOutput execute(ChunkBuildContext context, CancellationToken cancellationToken) { - this.render.getTranslucentData().sort(this.cameraPos); - + this.render.getTranslucentData().sortOnTrigger(this.cameraPos); return new ChunkSortOutput(this.render, this.submitTime, this.render.getTranslucentData()); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderTask.java index 9a0116d4ee..78f0bfc7af 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderTask.java @@ -1,5 +1,6 @@ package me.jellysquid.mods.sodium.client.render.chunk.compile.tasks; +import org.joml.Vector3dc; import org.joml.Vector3f; import org.joml.Vector3fc; @@ -23,13 +24,20 @@ public abstract class ChunkBuilderTask { protected final int submitTime; protected final Vector3fc cameraPos; - public ChunkBuilderTask(RenderSection render, int time, Vector3fc absoluteCameraPos) { + /** + * Constructs a new build task for the given chunk and converts the absolute camera position to a relative position. While the absolute position is stored as a double vector, the relative position is stored as a float vector. + * + * @param render The chunk to build + * @param time The frame in which this task was created + * @param absoluteCameraPos The absolute position of the camera + */ + public ChunkBuilderTask(RenderSection render, int time, Vector3dc absoluteCameraPos) { this.render = render; this.submitTime = time; this.cameraPos = new Vector3f( - absoluteCameraPos.x() - (float) render.getOriginX(), - absoluteCameraPos.y() - (float) render.getOriginY(), - absoluteCameraPos.z() - (float) render.getOriginZ()); + (float) (absoluteCameraPos.x() - (double) render.getOriginX()), + (float) (absoluteCameraPos.y() - (double) render.getOriginY()), + (float) (absoluteCameraPos.z() - (double) render.getOriginZ())); } /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/CameraMovement.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/CameraMovement.java new file mode 100644 index 0000000000..0aa85d5096 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/CameraMovement.java @@ -0,0 +1,6 @@ +package me.jellysquid.mods.sodium.client.render.chunk.gfni; + +import org.joml.Vector3dc; + +public record CameraMovement(Vector3dc lastCamera, Vector3dc currentCamera) { +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java index 56af6ec9a6..8c848f1a74 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java @@ -103,6 +103,7 @@ private static int[] distanceSortIndexes(TQuad[] quads, Vector3fc cameraPos) { keys[i] = cameraPos.distanceSquared(quads[i].center()); } + // TODO: use sort algorithm other than merge sort return MergeSort.mergeSort(keys); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java index 387e083a6c..16fe48a1c5 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java @@ -1,7 +1,10 @@ package me.jellysquid.mods.sodium.client.render.chunk.gfni; import java.nio.IntBuffer; +import java.util.Collection; +import java.util.concurrent.ConcurrentLinkedDeque; +import org.apache.commons.lang3.tuple.Pair; import org.joml.Vector3fc; import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; @@ -13,6 +16,11 @@ public class DynamicData extends MixedDirectionData { private final TQuad[] quads; + boolean GFNITrigger = true; + boolean angleTrigger = false; + boolean turnAngleTriggerOn = false; + boolean turnGFNITriggerOff = false; + private boolean pendingTriggerIsAngle; private TranslucentGeometryCollector collector; private Object2ReferenceOpenHashMap distancesByNormal; @@ -31,22 +39,115 @@ public SortType getSortType() { return SortType.DYNAMIC_ALL; } + private static final Collection> sortTimingData = new ConcurrentLinkedDeque<>(); + + private static void updateTimingData(int quadCount, long sortTime) { + sortTimingData.add(Pair.of(quadCount, sortTime)); + if (sortTimingData.size() > 3000) { + synchronized (sortTimingData) { + if (sortTimingData.size() <= 3000) { + return; + } + var totalQuads = sortTimingData.stream().mapToLong(Pair::getLeft).sum(); + var totalTime = sortTimingData.stream().mapToLong(Pair::getRight).sum(); + var averageTime = totalTime / (double) sortTimingData.size(); + var averageQuads = totalQuads / (double) sortTimingData.size(); + System.out.println("Average sort time: " + averageTime + "ms for " + averageQuads + " quads"); + + // print whole data as csv + var builder = new StringBuilder(); + builder.append("\nquads,time\n"); + for (var pair : sortTimingData) { + builder.append(pair.getLeft()).append(",").append(pair.getRight()).append(";"); + } + System.out.println(builder.toString()); + + sortTimingData.clear(); + } + } + } + + private long sortStart; + + void startSortTimer() { + this.sortStart = System.nanoTime(); + } + + void endSortTimer() { + // var sortTime = System.nanoTime() - this.sortStart; + // if (this instanceof PresentTranslucentData present) { + // updateTimingData(present.getQuadLength(), sortTime); + // } + } + + @Override + public boolean prepareTrigger(boolean isAngleTrigger) { + // if an angle trigger was scheduled but isn't needed, return true to signal + // removal from angle triggering + if (isAngleTrigger && !this.angleTrigger) { + return true; + } + + this.pendingTriggerIsAngle = isAngleTrigger; + return false; + } + @Override - public void sort(Vector3fc cameraPos) { + public void sortOnTrigger(Vector3fc cameraPos) { + this.sortWithTiming(cameraPos, this.pendingTriggerIsAngle); + } + + private void sortWithTiming(Vector3fc cameraPos, boolean isAngleTrigger) { + this.startSortTimer(); + this.sort(cameraPos, isAngleTrigger); + this.endSortTimer(); + } + + private void sort(Vector3fc cameraPos, boolean isAngleTrigger) { + // uses a topo sort or a distance sort depending on what is enabled IntBuffer indexBuffer = this.buffer.getDirectBuffer().asIntBuffer(); - if (!ComplexSorting.topoSortDepthFirstCyclic(indexBuffer, this.quads, this.distancesByNormal, cameraPos)) { - // if a camera position is given, no cycle should be possible - // throw new IllegalStateException("Failed to sort at" + this.sectionPos); - System.out.println("Failed to sort at " + this.sectionPos); + if (this.GFNITrigger && !isAngleTrigger) { + if (ComplexSorting.topoSortDepthFirstCyclic(indexBuffer, this.quads, this.distancesByNormal, cameraPos)) { + // disable distance sorting because topo sort seems to be possible. + // removal from angle triggering happens automatically by setting this to false. + this.angleTrigger = false; + return; + } else { + // topo sort failure, the topo sort algorithm doesn't work on all cases + System.out.println("Failed to sort at " + this.sectionPos); + + // TODO: implement different give-up heuristic. this gives up after the second + // failure. + if (this.angleTrigger) { + // turn off if currently on and signal change + if (this.GFNITrigger) { + this.GFNITrigger = false; + this.turnGFNITriggerOff = true; + } + } + if (!this.angleTrigger) { + this.angleTrigger = true; + this.turnAngleTriggerOn = true; + } + } } + if (this.angleTrigger) { + indexBuffer.rewind(); + ComplexSorting.distanceSortDirect(indexBuffer, this.quads, cameraPos); + return; + } + } + + public boolean hasTriggerChanges() { + return this.turnAngleTriggerOn || this.turnGFNITriggerOff; } TranslucentGeometryCollector getCollector() { return this.collector; } - void finishIntegration() { + void deleteCollector() { this.collector = null; } @@ -83,7 +184,7 @@ static DynamicData fromMesh(BuiltSectionMeshParts translucentMesh, var dynamicData = new DynamicData(sectionPos, buffer, range, quads, collector, distancesByNormal); - dynamicData.sort(cameraPos); + dynamicData.sortWithTiming(cameraPos, false); return dynamicData; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java index 2daae4b351..1618025963 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java @@ -1,10 +1,13 @@ package me.jellysquid.mods.sodium.client.render.chunk.gfni; import java.util.List; -import java.util.function.Consumer; +import java.util.function.BiFunction; +import org.joml.Vector3d; +import org.joml.Vector3dc; import org.joml.Vector3fc; +import it.unimi.dsi.fastutil.doubles.Double2ObjectAVLTreeMap; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; @@ -29,6 +32,13 @@ * that. Would simplify the ComplexSorting code so that it doesn't need to deal * with the existence of error margins (epsilons in the trigger distances and * the centers). + * - Groups of quads that form convex shapes in a single plane without holes can + * be sorted as one "quad". Their internal sorting can be arbitrary. Detecting + * and grouping/ungrouping them might prove difficult. Finding all quad groups + * is hard but finding one quad group at a time per direction is doable during + * building. Using the extents calculated for aligned quads, continuity can be + * easily tested and then convexity confirmed. How to deal with groups of quads + * that are only convex if a few of the quads are ignored? * * @author douira */ @@ -48,12 +58,29 @@ public class GFNI { */ private Object2ReferenceOpenHashMap normalLists = new Object2ReferenceOpenHashMap<>(50); + /** + * A tree map of the directly (angle-based) triggered sections, indexed by their + * minimum required camera movement. When the given camera movement is exceeded, + * they are tested for triggering the angle-condition. + * + * The accumulated distance is monotonically increasing and is never reset. This + * only becomes a problem when the camera moves more than 10^15 blocks in total. + * There will be precision issues at around 10^10 maybe, but it's still not a + * concern. + */ + private Double2ObjectAVLTreeMap angleTriggerSections = new Double2ObjectAVLTreeMap<>(); + private double accumulatedDistance = 0; + /** * To avoid generating a collection of the triggered sections, this callback is * used to process the triggered sections directly as they are queried from the - * normal lists' interval trees. + * normal lists' interval trees. The callback is given the section coordinates, + * and a boolean indicating if the trigger was an angle-based trigger. In the + * case of an angle trigger, it turns true if the section should be removed from + * future triggering (when the translucent data no longer hast the corresponding + * flag set) */ - private Consumer triggerSectionCallback; + private BiFunction triggerSectionCallback; /** * A set of all the sections that were triggered the last time something was @@ -76,6 +103,16 @@ public class GFNI { */ private final int[] sortTypeCounters = new int[SortType.values().length]; + private void decrementSortTypeCounter(TranslucentData oldData) { + if (oldData != null) { + this.sortTypeCounters[oldData.getSortType().ordinal()]--; + } + } + + private void incrementSortTypeCounter(TranslucentData newData) { + this.sortTypeCounters[newData.getSortType().ordinal()]++; + } + /** * Triggers the sections that the given camera movement crosses face planes of. * @@ -87,17 +124,14 @@ public class GFNI { * @param cameraY the camera y position after the movement * @param cameraZ the camera z position after the movement */ - public void triggerSections( - Consumer triggerSectionCallback, - double lastCameraX, double lastCameraY, double lastCameraZ, - double cameraX, double cameraY, double cameraZ) { + public void triggerSections(BiFunction triggerSectionCallback, + CameraMovement movement) { triggeredSections.clear(); triggeredNormals.clear(); this.triggerSectionCallback = triggerSectionCallback; - for (var normalList : this.normalLists.values()) { - normalList.processMovement(this, lastCameraX, lastCameraY, lastCameraZ, cameraX, cameraY, cameraZ); - } + processGFNITriggers(movement); + processAngleTriggers(movement); var newTriggeredSectionsCount = this.triggeredSections.size(); var newTriggeredNormalCount = this.triggeredNormals.size(); @@ -119,41 +153,150 @@ public void triggerSections( triggerSectionCallback = null; } - void triggerSection(ChunkSectionPos section, int collectorKey) { - this.triggeredSections.add(section.asLong()); - this.triggeredNormals.add(collectorKey); + private void processGFNITriggers(CameraMovement movement) { + for (var normalList : this.normalLists.values()) { + normalList.processMovement(this, movement); + } + } + + /** + * Degrees of movement from last sort position before the section is sorted + * again. TODO: put in a setting somewhere? or just determine what works best + */ + private static final double TRIGGER_ANGLE = Math.toRadians(5); + private static final double TRIGGER_ANGLE_COS = Math.cos(TRIGGER_ANGLE); + private static final double SECTION_CENTER_DIST = Math.sqrt(3 * (16 / 2) * (16 / 2)); - // by simply setting a chunk update type on the section, it naturally only gets - // updated once the section becomes visible. - // by definition, all sections in GFNI have SortType.DYNAMIC - this.triggerSectionCallback.accept(section); + private class AngleSortData { + ChunkSectionPos sectionPos; + + /** + * Absolute camera position at the time of the last sort. + */ + Vector3dc sortCameraPos; + + AngleSortData(ChunkSectionPos sectionPos, Vector3dc sortCameraPos) { + this.sectionPos = sectionPos; + this.sortCameraPos = sortCameraPos; + } } - private void removeSectionFromList(NormalList normalList, long chunkSectionLongPos) { - normalList.removeSection(chunkSectionLongPos); - if (normalList.isEmpty()) { - this.normalLists.remove(normalList.getNormal()); + // TODO: use faster code for this + private static double angleCos(double ax, double ay, double az, double bx, double by, double bz) { + double length1Squared = Math.fma(ax, ax, Math.fma(ay, ay, az * az)); + double length2Squared = Math.fma(bx, bx, Math.fma(by,by, bz * bz)); + double dot = Math.fma(ax, bx, Math.fma(ay, by, az * bz)); + return dot / Math.sqrt(length1Squared * length2Squared); + } + + private void processAngleTriggers(CameraMovement movement) { + var lastCamera = movement.lastCamera(); + var camera = movement.currentCamera(); + double distance = camera.distance(lastCamera); + this.accumulatedDistance += distance; + + // iterate all elements with a key of at most accumulatedDistance + var head = this.angleTriggerSections.headMap(this.accumulatedDistance); + for (var entry : head.double2ObjectEntrySet()) { + this.angleTriggerSections.remove(entry.getDoubleKey()); + var data = entry.getValue(); + var sectionPos = data.sectionPos; + var sortCameraPos = data.sortCameraPos; + var sectionCenter = new Vector3d( + sectionPos.getMinX() + 8, sectionPos.getMinY() + 8, sectionPos.getMinZ() + 8); + + // check if the angle since the last sort exceeds the threshold + var angleCos = angleCos( + sectionCenter.x() - sortCameraPos.x(), + sectionCenter.y() - sortCameraPos.y(), + sectionCenter.z() - sortCameraPos.z(), + sectionCenter.x() - camera.x(), + sectionCenter.y() - camera.y(), + sectionCenter.z() - camera.z()); + var remainingAngle = TRIGGER_ANGLE; + var addBack = true; + + // compare angles inverted because cosine flips it + if (angleCos <= TRIGGER_ANGLE_COS) { + // angle exceeded, trigger the section + if (this.triggerSectionAngle(sectionPos)) { + // section was marked as removed from angle trigger + addBack = false; + } + data.sortCameraPos = camera; + sortCameraPos = camera; + } else { + remainingAngle -= Math.acos(angleCos); + } + + if (addBack) { + insertAngleTrigger(data, remainingAngle); + } } } - private void decrementSortTypeCounter(TranslucentData oldTranslucentData) { - if (oldTranslucentData != null) { - this.sortTypeCounters[oldTranslucentData.getSortType().ordinal()]--; + private void insertAngleTrigger(AngleSortData data, double remainingAngle) { + var sectionPos = data.sectionPos; + var sortCameraPos = data.sortCameraPos; + + // re-insert with new minimum required camera movement + var dx = sectionPos.getMinX() + 8 - sortCameraPos.x(); + var dy = sectionPos.getMinY() + 8 - sortCameraPos.y(); + var dz = sectionPos.getMinZ() + 8 - sortCameraPos.z(); + var centerMinDistance = Math.tan(remainingAngle) + * (Math.sqrt(dx * dx + dy * dy + dz * dz) - SECTION_CENTER_DIST); + if (centerMinDistance <= 0) { + // too close to section, TODO: sort more often/differently + // throw new NotImplementedException(); + return; } + + this.angleTriggerSections.put(centerMinDistance + this.accumulatedDistance, data); + } + + void triggerSectionGFNI(long sectionPos, int collectorKey) { + this.triggeredNormals.add(collectorKey); + this.triggeredSections.add(sectionPos); + this.triggerSectionCallback.apply(sectionPos, false); + } + + private boolean triggerSectionAngle(ChunkSectionPos sectionPos) { + var sectionPosLong = sectionPos.asLong(); + if (this.triggerSectionCallback.apply(sectionPosLong, true)) { + return true; + } else { + this.triggeredSections.add(sectionPosLong); + return false; + } + } + + public void applyTriggerChanges(DynamicData data, ChunkSectionPos pos, Vector3dc cameraPos) { + if (data.turnAngleTriggerOn) { + enableAngleTriggering(data, pos, cameraPos); + } + if (data.turnGFNITriggerOff) { + disableGFNITriggering(data, pos.asLong()); + } + } + + private void enableAngleTriggering(DynamicData data, ChunkSectionPos section, Vector3dc cameraPos) { + insertAngleTrigger(new AngleSortData(section, cameraPos), TRIGGER_ANGLE); } /** * Removes a section from GFNI. This removes all its face planes. * - * @param oldTranslucentData the data of the section to remove - * @param chunkSectionLongPos the section to remove + * This doesn't remove sections from angle triggering since that would require + * another data structure to keep track of the inverse mapping from section to + * key. Instead, sections that shouldn't be angle triggered anymore are marked + * and then not re-added to the angle trigger tree. + * + * @param oldData the data of the section to remove + * @param sectionPos the section to remove */ - public void removeSection(TranslucentData oldTranslucentData, long chunkSectionLongPos) { - for (var normalList : this.normalLists.values()) { - removeSectionFromList(normalList, chunkSectionLongPos); - } - - decrementSortTypeCounter(oldTranslucentData); + public void removeSection(TranslucentData oldData, long sectionPos) { + disableGFNITriggering(oldData, sectionPos); + decrementSortTypeCounter(oldData); } private void addSectionInNewNormalLists(DynamicData dynamicData, AccumulationGroup accGroup) { @@ -166,32 +309,21 @@ private void addSectionInNewNormalLists(DynamicData dynamicData, AccumulationGro } } - /** - * Integrates the data from a geometry collector into GFNI. The geometry - * collector - * contains the translucent face planes of a single section. This method may - * also remove the section if it has become irrelevant. - * - * @param builder the geometry collector to integrate - * @return the sort type that the geometry collector's relevance heuristic - * determined - */ - public void integrateTranslucentData(TranslucentData oldTranslucentData, TranslucentData translucentData) { - long chunkSectionLongPos = translucentData.sectionPos.asLong(); - - // remove the section if the data doesn't need to trigger on face planes - // TODO: only do the heuristic and topo sort if the hashes are different? - SortType sortType = translucentData.getSortType(); - this.sortTypeCounters[sortType.ordinal()]++; - if (!sortType.needsPlaneTrigger) { - removeSection(oldTranslucentData, chunkSectionLongPos); - return; + private void removeSectionFromList(NormalList normalList, long sectionPos) { + normalList.removeSection(sectionPos); + if (normalList.isEmpty()) { + this.normalLists.remove(normalList.getNormal()); } + } - decrementSortTypeCounter(oldTranslucentData); + private void disableGFNITriggering(TranslucentData oldData, long sectionPos) { + for (var normalList : this.normalLists.values()) { + removeSectionFromList(normalList, sectionPos); + } + } - var dynamicData = (DynamicData) translucentData; - var collector = dynamicData.getCollector(); + private void initiallyEnableGFNITriggering(DynamicData data, long sectionPos) { + var collector = data.getCollector(); // go through all normal lists and check against the normals that the group // builder has. if the normal list has data for the section, but the group @@ -199,14 +331,14 @@ public void integrateTranslucentData(TranslucentData oldTranslucentData, Translu for (var normalList : this.normalLists.values()) { // check if the geometry collector includes data for this normal. var accGroup = collector.getGroupForNormal(normalList); - if (normalList.hasSection(chunkSectionLongPos)) { + if (normalList.hasSection(sectionPos)) { if (accGroup == null) { - removeSectionFromList(normalList, chunkSectionLongPos); + removeSectionFromList(normalList, sectionPos); } else { - normalList.updateSection(accGroup, chunkSectionLongPos); + normalList.updateSection(accGroup, sectionPos); } } else if (accGroup != null) { - normalList.addSection(accGroup, chunkSectionLongPos); + normalList.addSection(accGroup, sectionPos); } } @@ -217,17 +349,52 @@ public void integrateTranslucentData(TranslucentData oldTranslucentData, Translu if (collector.axisAlignedDistances != null) { for (var accGroup : collector.axisAlignedDistances) { if (accGroup != null) { - addSectionInNewNormalLists(dynamicData, accGroup); + addSectionInNewNormalLists(data, accGroup); } } } if (collector.unalignedDistances != null) { for (var accGroup : collector.unalignedDistances.values()) { - addSectionInNewNormalLists(dynamicData, accGroup); + addSectionInNewNormalLists(data, accGroup); } } - dynamicData.finishIntegration(); + data.deleteCollector(); + } + + /** + * Integrates the data from a geometry collector into GFNI. The geometry + * collector + * contains the translucent face planes of a single section. This method may + * also remove the section if it has become irrelevant. + * + * @param builder the geometry collector to integrate + * @return the sort type that the geometry collector's relevance heuristic + * determined + */ + public void integrateTranslucentData(TranslucentData oldData, TranslucentData newData, Vector3dc cameraPos) { + long sectionPos = newData.sectionPos.asLong(); + + incrementSortTypeCounter(newData); + + // remove the section if the data doesn't need to trigger on face planes + // TODO: only do the heuristic and topo sort if the hashes are different? + if (newData instanceof DynamicData dynamicData) { + decrementSortTypeCounter(oldData); + if (dynamicData.GFNITrigger) { + initiallyEnableGFNITriggering(dynamicData, sectionPos); + } else { + // remove the collector since this section is never going to get gfni triggering + // (there's no option to add sections to GFNI later currently) + dynamicData.deleteCollector(); + } + if (dynamicData.angleTrigger) { + enableAngleTriggering(dynamicData, newData.sectionPos, cameraPos); + } + } else { + removeSection(oldData, sectionPos); + return; + } } public void addDebugStrings(List list) { @@ -237,6 +404,7 @@ public void addDebugStrings(List list) { list.add("N=" + this.sortTypeCounters[SortType.NONE.ordinal()] + " SNR=" + this.sortTypeCounters[SortType.STATIC_NORMAL_RELATIVE.ordinal()] + " STA=" + this.sortTypeCounters[SortType.STATIC_TOPO_ACYCLIC.ordinal()] - + " DYN=" + this.sortTypeCounters[SortType.DYNAMIC_ALL.ordinal()]); + + " DYN=" + this.sortTypeCounters[SortType.DYNAMIC_ALL.ordinal()] + + " ANG=" + this.angleTriggerSections.size()); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java index bd86a8ab25..2a7e94872f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java @@ -3,7 +3,6 @@ import com.lodborg.intervaltree.DoubleInterval; import it.unimi.dsi.fastutil.doubles.DoubleArrays; -import net.minecraft.util.math.ChunkSectionPos; /** * A group represents a set of face planes of the same normal within a section. @@ -15,7 +14,7 @@ class Group { /** * The section this group is for */ - ChunkSectionPos sectionPos; + long sectionPos; /** * A sorted list of all the face plane distances in this group. Relative to the @@ -42,7 +41,7 @@ class Group { } void replaceWith(AccumulationGroup accGroup) { - this.sectionPos = accGroup.sectionPos; + this.sectionPos = accGroup.sectionPos.asLong(); this.distances = accGroup.distances; this.relDistanceHash = accGroup.relDistanceHash; this.facePlaneDistances = accGroup.facePlaneDistances; @@ -80,7 +79,7 @@ void triggerRange(GFNI gfni, double start, double end, int collectorKey) { if (start < this.distances.getEnd() && end > this.distances.getStart() && queryRange(this.facePlaneDistances, start - this.baseDistance, end - this.baseDistance)) { - gfni.triggerSection(this.sectionPos, collectorKey); + gfni.triggerSectionGFNI(this.sectionPos, collectorKey); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java index 88b3c316f5..9e3e099667 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java @@ -86,11 +86,10 @@ int getCollectorKey() { return collectorKey; } - void processMovement(GFNI gfni, double lastCameraX, double lastCameraY, double lastCameraZ, - double cameraX, double cameraY, double cameraZ) { + void processMovement(GFNI gfni, CameraMovement movement) { // calculate the distance range of the movement with respect to the normal - double start = this.normal.dot(lastCameraX, lastCameraY, lastCameraZ); - double end = this.normal.dot(cameraX, cameraY, cameraZ); + double start = this.normal.dot(movement.lastCamera()); + double end = this.normal.dot(movement.currentCamera()); // stop if the movement is reverse with regards to the normal // since this means it's moving against the normal @@ -137,30 +136,30 @@ private void addGroupInterval(Group group) { groups.add(group); } - boolean hasSection(long chunkSectionLongPos) { - return this.groupsBySection.containsKey(chunkSectionLongPos); + boolean hasSection(long sectionPos) { + return this.groupsBySection.containsKey(sectionPos); } boolean isEmpty() { return this.groupsBySection.isEmpty(); } - void addSection(AccumulationGroup accGroup, long chunkSectionLongPos) { + void addSection(AccumulationGroup accGroup, long sectionPos) { var group = new Group(accGroup); - this.groupsBySection.put(chunkSectionLongPos, group); + this.groupsBySection.put(sectionPos, group); addGroupInterval(group); } - void removeSection(long chunkSectionLongPos) { - Group group = this.groupsBySection.remove(chunkSectionLongPos); + void removeSection(long sectionPos) { + Group group = this.groupsBySection.remove(sectionPos); if (group != null) { removeGroupInterval(group); } } - void updateSection(AccumulationGroup accGroup, long chunkSectionLongPos) { - Group group = this.groupsBySection.get(chunkSectionLongPos); + void updateSection(AccumulationGroup accGroup, long sectionPos) { + Group group = this.groupsBySection.get(sectionPos); // only update on changes to translucent geometry if (group.equalsAccGroup(accGroup)) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/SortType.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/SortType.java index 5d6eba8697..eb938f4cbc 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/SortType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/SortType.java @@ -10,7 +10,7 @@ public enum SortType { /** * No sorting is required and the sort order doesn't matter. */ - NONE(false, false, false, false), + NONE(false, false, false), /** * There is only one sort order. No active sorting is required, but an initial @@ -21,14 +21,14 @@ public enum SortType { * changes, remove this note and adjust StaticTranslucentData and anything that * reads from it to handle UNASSIGNED quads. */ - STATIC_NORMAL_RELATIVE(true, false, false, false), + STATIC_NORMAL_RELATIVE(true, false, false), /** * There is only one sort order and not active sorting is required, but * determining the static sort order involves doing a toplogical sort of the * quads. */ - STATIC_TOPO_ACYCLIC(true, true, false, false), + STATIC_TOPO_ACYCLIC(true, true, false), /** * There is more than one sort order but instead of sorting one each plane @@ -42,21 +42,18 @@ public enum SortType { * There are multiple sort orders. Sorting is required every time GFNI triggers * this section. */ - DYNAMIC_ALL(true, true, true, true); + DYNAMIC_ALL(true, true, true); public final boolean needsIndexBuffer; public final boolean needsDirectionMixing; - public final boolean needsPlaneTrigger; - public final boolean needsDynamicSort; + public final boolean needsTrigger; private SortType( boolean needsIndexBuffer, boolean needsDirectionMixing, - boolean needsPlaneTrigger, - boolean needsDynamicSort) { + boolean needsTrigger) { this.needsIndexBuffer = needsIndexBuffer; this.needsDirectionMixing = needsDirectionMixing; - this.needsPlaneTrigger = needsPlaneTrigger; - this.needsDynamicSort = needsDynamicSort; + this.needsTrigger = needsTrigger; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java index 7d4ee367cc..d94048a82d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java @@ -29,15 +29,23 @@ public abstract class TranslucentData { public void delete() { } - public void sort(Vector3fc cameraPos) { - // noop sorting when this is called on non-dynamic data. - // this can happen when the section is rebuilt as non-dynamic after it's been - // scheduled for sorting + public void sortOnTrigger(Vector3fc cameraPos) { + // no-op for other translucent data than dynamic } - public void timedSort(Vector3fc cameraPos) { - // TODO: collect and analyze timing data, actually call this method instead of - // sort + /** + * Prepares the translucent data for triggering of the given type. This is run + * on the main thread before a sort task is scheduled. If true is returned, the + * sort task will not be scheduled and it will be removed from angle triggering. + * Returning true if isAngleTrigger is false is a no-op. + * + * @param isAngleTrigger Whether the trigger is an angle trigger + * @return True if the sort task should not be scheduled and the section should + * be removed from angle triggering + */ + public boolean prepareTrigger(boolean isAngleTrigger) { + // no-op for other translucent data than dynamic + return false; } static int vertexCountToIndexBytes(int vertexCount) { From 00e5756073ec0dcde0ce04ea8ead15356c91082c Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 20 Oct 2023 02:21:35 +0200 Subject: [PATCH 090/256] use 20 degrees as a reasonable sorting threshold, doesn't seem to break things --- .../sodium/client/render/chunk/gfni/GFNI.java | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java index 1618025963..0e3e83cead 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java @@ -161,9 +161,9 @@ private void processGFNITriggers(CameraMovement movement) { /** * Degrees of movement from last sort position before the section is sorted - * again. TODO: put in a setting somewhere? or just determine what works best + * again. */ - private static final double TRIGGER_ANGLE = Math.toRadians(5); + private static final double TRIGGER_ANGLE = Math.toRadians(20); private static final double TRIGGER_ANGLE_COS = Math.cos(TRIGGER_ANGLE); private static final double SECTION_CENTER_DIST = Math.sqrt(3 * (16 / 2) * (16 / 2)); @@ -190,8 +190,8 @@ private static double angleCos(double ax, double ay, double az, double bx, doubl } private void processAngleTriggers(CameraMovement movement) { - var lastCamera = movement.lastCamera(); - var camera = movement.currentCamera(); + Vector3dc lastCamera = movement.lastCamera(); + Vector3dc camera = movement.currentCamera(); double distance = camera.distance(lastCamera); this.accumulatedDistance += distance; @@ -200,20 +200,20 @@ private void processAngleTriggers(CameraMovement movement) { for (var entry : head.double2ObjectEntrySet()) { this.angleTriggerSections.remove(entry.getDoubleKey()); var data = entry.getValue(); - var sectionPos = data.sectionPos; - var sortCameraPos = data.sortCameraPos; - var sectionCenter = new Vector3d( + ChunkSectionPos sectionPos = data.sectionPos; + Vector3dc sortCameraPos = data.sortCameraPos; + Vector3dc sectionCenter = new Vector3d( sectionPos.getMinX() + 8, sectionPos.getMinY() + 8, sectionPos.getMinZ() + 8); // check if the angle since the last sort exceeds the threshold - var angleCos = angleCos( + double angleCos = angleCos( sectionCenter.x() - sortCameraPos.x(), sectionCenter.y() - sortCameraPos.y(), sectionCenter.z() - sortCameraPos.z(), sectionCenter.x() - camera.x(), sectionCenter.y() - camera.y(), sectionCenter.z() - camera.z()); - var remainingAngle = TRIGGER_ANGLE; + double remainingAngle = TRIGGER_ANGLE; var addBack = true; // compare angles inverted because cosine flips it @@ -236,14 +236,14 @@ private void processAngleTriggers(CameraMovement movement) { } private void insertAngleTrigger(AngleSortData data, double remainingAngle) { - var sectionPos = data.sectionPos; - var sortCameraPos = data.sortCameraPos; + ChunkSectionPos sectionPos = data.sectionPos; + Vector3dc sortCameraPos = data.sortCameraPos; // re-insert with new minimum required camera movement - var dx = sectionPos.getMinX() + 8 - sortCameraPos.x(); - var dy = sectionPos.getMinY() + 8 - sortCameraPos.y(); - var dz = sectionPos.getMinZ() + 8 - sortCameraPos.z(); - var centerMinDistance = Math.tan(remainingAngle) + double dx = sectionPos.getMinX() + 8 - sortCameraPos.x(); + double dy = sectionPos.getMinY() + 8 - sortCameraPos.y(); + double dz = sectionPos.getMinZ() + 8 - sortCameraPos.z(); + double centerMinDistance = Math.tan(remainingAngle) * (Math.sqrt(dx * dx + dy * dy + dz * dz) - SECTION_CENTER_DIST); if (centerMinDistance <= 0) { // too close to section, TODO: sort more often/differently From 7c9ed4884655641295a5fb6751af26757bf06cb1 Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 21 Oct 2023 05:24:02 +0200 Subject: [PATCH 091/256] combine vertex and index buffer storage management, WIP since broken atm --- .../render/chunk/DefaultChunkRenderer.java | 36 ++++++----- .../render/chunk/RenderSectionManager.java | 2 +- .../chunk/data/SectionRenderDataStorage.java | 59 ++++++++++++++++--- .../chunk/data/SectionRenderDataUnsafe.java | 12 +++- .../render/chunk/region/RenderRegion.java | 59 ++++--------------- .../chunk/region/RenderRegionManager.java | 28 +++++---- 6 files changed, 108 insertions(+), 88 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java index 16c8aeae61..0651aba5dc 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java @@ -65,16 +65,12 @@ public void render(ChunkRenderMatrices matrices, var region = renderList.getRegion(); var storage = region.getStorage(renderPass); - SectionRenderDataStorage indexDataStorage = null; - if (isTranslucent) { - indexDataStorage = region.getTranslucentStorage(); - } if (storage == null) { continue; } - fillCommandBuffer(this.batch, region, storage, indexDataStorage, renderList, camera, renderPass, useBlockFaceCulling); + fillCommandBuffer(this.batch, region, storage, renderList, camera, renderPass, useBlockFaceCulling); if (this.batch.isEmpty()) { continue; @@ -98,7 +94,6 @@ public void render(ChunkRenderMatrices matrices, private static void fillCommandBuffer(MultiDrawBatch batch, RenderRegion renderRegion, SectionRenderDataStorage renderDataStorage, - SectionRenderDataStorage indexDataStorage, ChunkRenderList renderList, CameraTransform camera, TerrainRenderPass pass, @@ -123,11 +118,6 @@ private static void fillCommandBuffer(MultiDrawBatch batch, int chunkZ = originZ + LocalSectionIndex.unpackZ(sectionIndex); long pMeshData = renderDataStorage.getDataPointer(sectionIndex); - long pIndexData = -1; - if (indexDataStorage != null) { - pIndexData = indexDataStorage.getDataPointer(sectionIndex); - } - int slices; if (useBlockFaceCulling) { @@ -139,24 +129,32 @@ private static void fillCommandBuffer(MultiDrawBatch batch, slices &= SectionRenderDataUnsafe.getSliceMask(pMeshData); if (slices != 0) { - addDrawCommands(batch, pMeshData, slices, pIndexData); + addDrawCommands(batch, pMeshData, slices); } } } @SuppressWarnings("IntegerMultiplicationImplicitCastToLong") - private static void addDrawCommands(MultiDrawBatch batch, long pMeshData, int mask, long pIndexData) { + private static void addDrawCommands(MultiDrawBatch batch, long pMeshData, int mask) { final var pElementPointer = batch.pElementPointer; final var pBaseVertex = batch.pBaseVertex; final var pElementCount = batch.pElementCount; int size = batch.size; + int indexDataOffset = SectionRenderDataUnsafe.getIndexOffset(pMeshData); for (int facing = 0; facing < ModelQuadFacing.COUNT; facing++) { MemoryUtil.memPutInt(pBaseVertex + (size << 2), SectionRenderDataUnsafe.getVertexOffset(pMeshData, facing)); - MemoryUtil.memPutInt(pElementCount + (size << 2), SectionRenderDataUnsafe.getElementCount(pMeshData, facing)); - if (pIndexData != -1) { - MemoryUtil.memPutAddress(pElementPointer + (size << 3), SectionRenderDataUnsafe.getVertexOffset(pIndexData, facing) << 2); + var elementCount = SectionRenderDataUnsafe.getElementCount(pMeshData, facing); + MemoryUtil.memPutInt(pElementCount + (size << 2), elementCount); + + // zero check for when we're not rendering any translucent data + // TODO: unclear if the offset can naturally be zero sometimes + if (indexDataOffset != 0) { + // * 4 to convert to bytes (the buffer contains ints) + // the section render data storage for the indices stores the offset in indices (also called elements) + MemoryUtil.memPutAddress(pElementPointer + (size << 3), indexDataOffset << 2); + indexDataOffset += elementCount; } else { MemoryUtil.memPutAddress(pElementPointer + (size << 3), 0); } @@ -256,7 +254,7 @@ private GlTessellation prepareIndexedTessellation(CommandList commandList, Rende private GlTessellation createRegionTessellation(CommandList commandList, RenderRegion.DeviceResources resources) { return commandList.createTessellation(GlPrimitiveType.TRIANGLES, new TessellationBinding[] { - TessellationBinding.forVertexBuffer(resources.getVertexBuffer(), new GlVertexAttributeBinding[] { + TessellationBinding.forVertexBuffer(resources.getBuffer(), new GlVertexAttributeBinding[] { new GlVertexAttributeBinding(ChunkShaderBindingPoints.ATTRIBUTE_PACKED_DATA, this.vertexFormat.getAttribute(ChunkMeshAttribute.VERTEX_DATA)) }), @@ -266,11 +264,11 @@ private GlTessellation createRegionTessellation(CommandList commandList, RenderR private GlTessellation createIndexedRegionTessellation(CommandList commandList, RenderRegion.DeviceResources resources) { return commandList.createTessellation(GlPrimitiveType.TRIANGLES, new TessellationBinding[] { - TessellationBinding.forVertexBuffer(resources.getVertexBuffer(), new GlVertexAttributeBinding[] { + TessellationBinding.forVertexBuffer(resources.getBuffer(), new GlVertexAttributeBinding[] { new GlVertexAttributeBinding(ChunkShaderBindingPoints.ATTRIBUTE_PACKED_DATA, this.vertexFormat.getAttribute(ChunkMeshAttribute.VERTEX_DATA)) }), - TessellationBinding.forElementBuffer(resources.getIndexBuffer()) + TessellationBinding.forElementBuffer(resources.getBuffer()) // the indices are stored next to the vertices }); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index 1e368b9f9b..4cd5b78a9b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -608,7 +608,7 @@ public Collection getDebugStrings() { continue; } - var buffer = resources.getGeometryArena(); + var buffer = resources.getArena(); deviceUsed += buffer.getDeviceUsedMemory(); deviceAllocated += buffer.getDeviceAllocatedMemory(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java index 409502a752..e2791a76df 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java @@ -8,18 +8,20 @@ import java.util.Arrays; public class SectionRenderDataStorage { - private final GlBufferSegment[] allocations = new GlBufferSegment[RenderRegion.REGION_SIZE]; + private final GlBufferSegment[] allocations; private final long pMeshDataArray; private final boolean storesIndices; public SectionRenderDataStorage(boolean storesIndices) { + var allocationCount = RenderRegion.REGION_SIZE * (storesIndices ? 2 : 1); + this.allocations = new GlBufferSegment[allocationCount]; this.pMeshDataArray = SectionRenderDataUnsafe.allocateHeap(RenderRegion.REGION_SIZE); this.storesIndices = storesIndices; } - public void setMeshes(int localSectionIndex, - GlBufferSegment allocation, VertexRange[] ranges) { + public void setVertexData(int localSectionIndex, + GlBufferSegment allocation, VertexRange[] ranges) { if (this.allocations[localSectionIndex] != null) { this.allocations[localSectionIndex].delete(); this.allocations[localSectionIndex] = null; @@ -43,20 +45,37 @@ public void setMeshes(int localSectionIndex, } SectionRenderDataUnsafe.setVertexOffset(pMeshData, facingIndex, vertexOffset); - var elementCount = (vertexCount >> 2) * 6; - SectionRenderDataUnsafe.setElementCount(pMeshData, facingIndex, elementCount); + SectionRenderDataUnsafe.setElementCount(pMeshData, facingIndex, (vertexCount >> 2) * 6); if (vertexCount > 0) { sliceMask |= 1 << facingIndex; } - vertexOffset += this.storesIndices ? elementCount : vertexCount; + vertexOffset += vertexCount; } SectionRenderDataUnsafe.setSliceMask(pMeshData, sliceMask); } - public void removeMeshes(int localSectionIndex) { + public void setIndexData(int localSectionIndex, GlBufferSegment allocation) { + if (!this.storesIndices) { + throw new IllegalStateException("Cannot set index data when storesIndices is false"); + } + + var indexAllocationIndex = localSectionIndex + RenderRegion.REGION_SIZE; + if (this.allocations[indexAllocationIndex] != null) { + this.allocations[indexAllocationIndex].delete(); + this.allocations[indexAllocationIndex] = null; + } + + this.allocations[indexAllocationIndex] = allocation; + + var pMeshData = this.getDataPointer(localSectionIndex); + + SectionRenderDataUnsafe.setIndexOffset(pMeshData, allocation.getOffset()); + } + + public void removeVertexData(int localSectionIndex) { if (this.allocations[localSectionIndex] == null) { return; } @@ -64,9 +83,25 @@ public void removeMeshes(int localSectionIndex) { this.allocations[localSectionIndex].delete(); this.allocations[localSectionIndex] = null; + // also clear index allocation + if (this.storesIndices) { + removeIndexData(localSectionIndex); + } + SectionRenderDataUnsafe.clear(this.getDataPointer(localSectionIndex)); } + public void removeIndexData(int localSectionIndex) { + if (!this.storesIndices) { + throw new IllegalStateException("Cannot remove index data when storesIndices is false"); + } + var indexAllocationIndex = localSectionIndex + RenderRegion.REGION_SIZE; + if (this.allocations[indexAllocationIndex] != null) { + this.allocations[indexAllocationIndex].delete(); + this.allocations[indexAllocationIndex] = null; + } + } + public void onBufferResized() { for (int sectionIndex = 0; sectionIndex < RenderRegion.REGION_SIZE; sectionIndex++) { this.updateMeshes(sectionIndex); @@ -87,8 +122,14 @@ private void updateMeshes(int sectionIndex) { SectionRenderDataUnsafe.setVertexOffset(data, facing, offset); var count = SectionRenderDataUnsafe.getElementCount(data, facing); - // TODO: fix this when storesIndices is true, it currently just explodes - offset += this.storesIndices ? count : (count / 6) * 4; // convert elements back into vertices + offset += (count / 6) * 4; // convert elements back into vertices + } + + if (this.storesIndices) { + var indexAllocation = this.allocations[sectionIndex + RenderRegion.REGION_SIZE]; + if (indexAllocation != null) { + SectionRenderDataUnsafe.setIndexOffset(data, indexAllocation.getOffset()); + } } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataUnsafe.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataUnsafe.java index f536aeaad2..6300fe1571 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataUnsafe.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataUnsafe.java @@ -16,8 +16,9 @@ // three times slower than the most naive solution in literally any other language that LLVM can compile. // the structure is roughly as follows: -// struct SectionRenderData { // 64 bytes +// struct SectionRenderData { // 68 bytes // mask: u32, +// index_offset: u32 // ranges: [VertexRange; 7] // } // struct VertexRange { // 8 bytes @@ -26,6 +27,7 @@ // } public class SectionRenderDataUnsafe { private static final long OFFSET_SLICE_MASK = 0; + private static final long OFFSET_SLICE_INDEX_OFFSETS = 4; private static final long OFFSET_SLICE_RANGES = 8; private static final long STRIDE = 64; @@ -54,6 +56,14 @@ public static int getSliceMask(long ptr) { return MemoryUtil.memGetInt(ptr + OFFSET_SLICE_MASK); } + public static void setIndexOffset(long ptr, int value) { + MemoryUtil.memPutInt(ptr + OFFSET_SLICE_INDEX_OFFSETS, value); + } + + public static int getIndexOffset(long ptr) { + return MemoryUtil.memGetInt(ptr + OFFSET_SLICE_INDEX_OFFSETS); + } + public static void setVertexOffset(long ptr, int facing, int value) { MemoryUtil.memPutInt(ptr + OFFSET_SLICE_RANGES + (facing * 8L) + 0L, value); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java index 7ecc1c49ae..d709a14c59 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java @@ -8,8 +8,8 @@ import me.jellysquid.mods.sodium.client.gl.tessellation.GlTessellation; import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; import me.jellysquid.mods.sodium.client.render.chunk.data.SectionRenderDataStorage; -import me.jellysquid.mods.sodium.client.render.chunk.gfni.TranslucentData; import me.jellysquid.mods.sodium.client.render.chunk.lists.ChunkRenderList; +import me.jellysquid.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses; import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkMeshFormats; import me.jellysquid.mods.sodium.client.util.MathUtil; @@ -49,7 +49,6 @@ public class RenderRegion { private int sectionCount; private final Map sectionRenderData = new Reference2ReferenceOpenHashMap<>(); - private SectionRenderDataStorage translucentIndexData = null; private DeviceResources resources; public RenderRegion(int x, int y, int z, StagingBuffer stagingBuffer) { @@ -93,9 +92,6 @@ public void delete(CommandList commandList) { for (var storage : this.sectionRenderData.values()) { storage.delete(); } - if (this.translucentIndexData != null) { - this.translucentIndexData.delete(); - } this.sectionRenderData.clear(); @@ -115,28 +111,17 @@ public SectionRenderDataStorage getStorage(TerrainRenderPass pass) { return this.sectionRenderData.get(pass); } - public SectionRenderDataStorage getTranslucentStorage() { - return this.translucentIndexData; - } - public SectionRenderDataStorage createStorage(TerrainRenderPass pass) { var storage = this.sectionRenderData.get(pass); if (storage == null) { - this.sectionRenderData.put(pass, storage = new SectionRenderDataStorage(false)); + this.sectionRenderData.put(pass, storage = new SectionRenderDataStorage( + pass == DefaultTerrainRenderPasses.TRANSLUCENT)); } return storage; } - public SectionRenderDataStorage createTranslucentStorage() { - if (this.translucentIndexData == null) { - return this.translucentIndexData = new SectionRenderDataStorage(true); - } - - return this.translucentIndexData; - } - public void refresh(CommandList commandList) { if (this.resources != null) { this.resources.deleteTessellations(commandList); @@ -152,9 +137,7 @@ public void refreshTranslucent(CommandList commandList) { this.resources.deleteIndexedTessellation(commandList); } - if (this.translucentIndexData != null) { - this.translucentIndexData.onBufferResized(); - } + this.sectionRenderData.get(DefaultTerrainRenderPasses.TRANSLUCENT).onBufferResized(); } public void addSection(RenderSection section) { @@ -180,10 +163,7 @@ public void removeSection(RenderSection section) { } for (var storage : this.sectionRenderData.values()) { - storage.removeMeshes(sectionIndex); - } - if (this.translucentIndexData != null) { - this.translucentIndexData.removeMeshes(sectionIndex); + storage.removeVertexData(sectionIndex); } this.sections[sectionIndex] = null; @@ -218,17 +198,13 @@ public ChunkRenderList getRenderList() { } public static class DeviceResources { - private final GlBufferArena geometryArena; - private final GlBufferArena indexArena; + private final GlBufferArena arena; private GlTessellation tessellation; private GlTessellation indexedTessellation; public DeviceResources(CommandList commandList, StagingBuffer stagingBuffer) { int stride = ChunkMeshFormats.COMPACT.getVertexFormat().getStride(); - this.geometryArena = new GlBufferArena(commandList, REGION_SIZE * 756, stride, stagingBuffer); - - // TODO: what size should this be intially? Should this be using the same staging buffer? - this.indexArena = new GlBufferArena(commandList, REGION_SIZE * 756, TranslucentData.BYTES_PER_INDEX, stagingBuffer); + this.arena = new GlBufferArena(commandList, REGION_SIZE * 756, stride, stagingBuffer); } public void updateTessellation(CommandList commandList, GlTessellation tessellation) { @@ -269,31 +245,22 @@ public void deleteIndexedTessellation(CommandList commandList) { } } - public GlBuffer getVertexBuffer() { - return this.geometryArena.getBufferObject(); - } - - public GlBuffer getIndexBuffer() { - return this.indexArena.getBufferObject(); + public GlBuffer getBuffer() { + return this.arena.getBufferObject(); } public void delete(CommandList commandList) { this.deleteTessellations(commandList); this.deleteIndexedTessellation(commandList); - this.geometryArena.delete(commandList); - this.indexArena.delete(commandList); - } - - public GlBufferArena getGeometryArena() { - return this.geometryArena; + this.arena.delete(commandList); } - public GlBufferArena getIndexArena() { - return this.indexArena; + public GlBufferArena getArena() { + return this.arena; } public boolean shouldDelete() { - return this.geometryArena.isEmpty() && this.indexArena.isEmpty(); // TODO: correct? + return this.arena.isEmpty(); } } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java index d0ee7b6144..6c8ecf1f0a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java @@ -69,7 +69,7 @@ private void uploadResults(CommandList commandList, RenderRegion region, Collect var storage = region.getStorage(pass); if (storage != null) { - storage.removeMeshes(renderSectionIndex); + storage.removeVertexData(renderSectionIndex); } BuiltSectionMeshParts mesh = chunkBuildOutput.getMesh(pass); @@ -82,13 +82,18 @@ private void uploadResults(CommandList commandList, RenderRegion region, Collect } if (result instanceof ChunkSortOutput chunkSortOutput) { - var translucentStorage = region.getTranslucentStorage(); - if (translucentStorage != null) { - translucentStorage.removeMeshes(renderSectionIndex); + var storage = region.getStorage(DefaultTerrainRenderPasses.TRANSLUCENT); + if (storage != null) { + storage.removeIndexData(renderSectionIndex); } var translucentData = chunkSortOutput.translucentData; if (translucentData != null && translucentData instanceof PresentTranslucentData presentTranslucentData) { + // TODO: debug this, seems to sometimes happen when flying around with spectator mode + // maybe related to setting all sections to angle triggering mode? + if (presentTranslucentData.buffer == null) { + throw new IllegalStateException("Translucent data buffer is null"); + } indexUploads.add(new PendingSectionIndexBufferUpload(result.render, presentTranslucentData, new PendingUpload(presentTranslucentData.buffer))); } @@ -103,8 +108,8 @@ private void uploadResults(CommandList commandList, RenderRegion region, Collect var resources = region.createResources(commandList); if (!uploads.isEmpty()) { - var geometryArena = resources.getGeometryArena(); - boolean bufferChanged = geometryArena.upload(commandList, uploads.stream() + var arena = resources.getArena(); + boolean bufferChanged = arena.upload(commandList, uploads.stream() .map(upload -> upload.vertexUpload)); // If any of the buffers changed, the tessellation will need to be updated @@ -116,14 +121,14 @@ private void uploadResults(CommandList commandList, RenderRegion region, Collect // Collect the upload results for (PendingSectionMeshUpload upload : uploads) { var storage = region.createStorage(upload.pass); - storage.setMeshes(upload.section.getSectionIndex(), + storage.setVertexData(upload.section.getSectionIndex(), upload.vertexUpload.getResult(), upload.meshData.getVertexRanges()); } } if (!indexUploads.isEmpty()) { - var indexArena = resources.getIndexArena(); - boolean bufferChanged = indexArena.upload(commandList, indexUploads.stream() + var arena = resources.getArena(); + boolean bufferChanged = arena.upload(commandList, indexUploads.stream() .map(upload -> upload.indexBufferUpload)); if (bufferChanged) { @@ -131,9 +136,8 @@ private void uploadResults(CommandList commandList, RenderRegion region, Collect } for (PendingSectionIndexBufferUpload upload : indexUploads) { - var storage = region.createTranslucentStorage(); - storage.setMeshes(upload.section.getSectionIndex(), - upload.indexBufferUpload.getResult(), upload.translucentData.getVertexRanges()); + var storage = region.createStorage(DefaultTerrainRenderPasses.TRANSLUCENT); + storage.setIndexData(upload.section.getSectionIndex(), upload.indexBufferUpload.getResult()); } } } From 470890a53f1326bcb40569980a0b760abb677b5b Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 21 Oct 2023 19:38:41 +0200 Subject: [PATCH 092/256] use neg y facing for water inside face if it's actually aligned --- .../client/render/chunk/compile/pipeline/FluidRenderer.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java index f4fabb53b7..4a362939ac 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java @@ -230,8 +230,11 @@ public void render(WorldSlice world, FluidState fluidState, BlockPos blockPos, B this.writeQuad(meshBuilder, collector, material, offset, quad, facing, false); if (fluidState.canFlowTo(world, this.scratchPos.set(posX, posY + 1, posZ))) { + boolean aligned = northEastHeight == northWestHeight + && northWestHeight == southEastHeight + && southEastHeight == southWestHeight; this.writeQuad(meshBuilder, collector, material, offset, quad, - ModelQuadFacing.UNASSIGNED, true); + aligned ? ModelQuadFacing.NEG_Y : ModelQuadFacing.UNASSIGNED, true); } From bb71f22fd409de5e1831500902eeb2d8894392e4 Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 21 Oct 2023 19:41:30 +0200 Subject: [PATCH 093/256] use separate buffer arenas for geometry and indices because their strides are different --- .../render/chunk/DefaultChunkRenderer.java | 8 ++-- .../render/chunk/RenderSectionManager.java | 2 +- .../chunk/data/SectionRenderDataStorage.java | 14 +++++++ .../sodium/client/render/chunk/gfni/GFNI.java | 9 ++++- .../render/chunk/region/RenderRegion.java | 38 +++++++++++++------ .../chunk/region/RenderRegionManager.java | 8 ++-- 6 files changed, 59 insertions(+), 20 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java index 0651aba5dc..7c02550934 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java @@ -154,6 +154,8 @@ private static void addDrawCommands(MultiDrawBatch batch, long pMeshData, int ma // * 4 to convert to bytes (the buffer contains ints) // the section render data storage for the indices stores the offset in indices (also called elements) MemoryUtil.memPutAddress(pElementPointer + (size << 3), indexDataOffset << 2); + + // adding the number of elements works because the index data has one index per element (which are the indices) indexDataOffset += elementCount; } else { MemoryUtil.memPutAddress(pElementPointer + (size << 3), 0); @@ -254,7 +256,7 @@ private GlTessellation prepareIndexedTessellation(CommandList commandList, Rende private GlTessellation createRegionTessellation(CommandList commandList, RenderRegion.DeviceResources resources) { return commandList.createTessellation(GlPrimitiveType.TRIANGLES, new TessellationBinding[] { - TessellationBinding.forVertexBuffer(resources.getBuffer(), new GlVertexAttributeBinding[] { + TessellationBinding.forVertexBuffer(resources.getGeometryBuffer(), new GlVertexAttributeBinding[] { new GlVertexAttributeBinding(ChunkShaderBindingPoints.ATTRIBUTE_PACKED_DATA, this.vertexFormat.getAttribute(ChunkMeshAttribute.VERTEX_DATA)) }), @@ -264,11 +266,11 @@ private GlTessellation createRegionTessellation(CommandList commandList, RenderR private GlTessellation createIndexedRegionTessellation(CommandList commandList, RenderRegion.DeviceResources resources) { return commandList.createTessellation(GlPrimitiveType.TRIANGLES, new TessellationBinding[] { - TessellationBinding.forVertexBuffer(resources.getBuffer(), new GlVertexAttributeBinding[] { + TessellationBinding.forVertexBuffer(resources.getGeometryBuffer(), new GlVertexAttributeBinding[] { new GlVertexAttributeBinding(ChunkShaderBindingPoints.ATTRIBUTE_PACKED_DATA, this.vertexFormat.getAttribute(ChunkMeshAttribute.VERTEX_DATA)) }), - TessellationBinding.forElementBuffer(resources.getBuffer()) // the indices are stored next to the vertices + TessellationBinding.forElementBuffer(resources.getIndexBuffer()) }); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index 4cd5b78a9b..1e368b9f9b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -608,7 +608,7 @@ public Collection getDebugStrings() { continue; } - var buffer = resources.getArena(); + var buffer = resources.getGeometryArena(); deviceUsed += buffer.getDeviceUsedMemory(); deviceAllocated += buffer.getDeviceAllocatedMemory(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java index e2791a76df..e829f402c0 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java @@ -55,6 +55,9 @@ public void setVertexData(int localSectionIndex, } SectionRenderDataUnsafe.setSliceMask(pMeshData, sliceMask); + + // reset index offset to make sure it never renders with wrong index data + SectionRenderDataUnsafe.setIndexOffset(pMeshData, 0); } public void setIndexData(int localSectionIndex, GlBufferSegment allocation) { @@ -124,8 +127,19 @@ private void updateMeshes(int sectionIndex) { var count = SectionRenderDataUnsafe.getElementCount(data, facing); offset += (count / 6) * 4; // convert elements back into vertices } + } + + public void onIndexBufferResized() { + if (this.storesIndices) { + for (int sectionIndex = 0; sectionIndex < RenderRegion.REGION_SIZE; sectionIndex++) { + this.updateIndexes(sectionIndex); + } + } + } + private void updateIndexes(int sectionIndex) { if (this.storesIndices) { + var data = this.getDataPointer(sectionIndex); var indexAllocation = this.allocations[sectionIndex + RenderRegion.REGION_SIZE]; if (indexAllocation != null) { SectionRenderDataUnsafe.setIndexOffset(data, indexAllocation.getOffset()); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java index 0e3e83cead..9e9e7ee1ae 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java @@ -39,6 +39,13 @@ * building. Using the extents calculated for aligned quads, continuity can be * easily tested and then convexity confirmed. How to deal with groups of quads * that are only convex if a few of the quads are ignored? + * - Movement prediction and preemptive task scheduling to avoid needing to + * perform blocking sorts of close sections. Maybe not an issue? Might reduce + * stutter in high fps situations. However, high complexity with regards to + * processing the results of preemptive sorts. + * - Does fluid renderer sometimes produce aligned faces that it doesn't + * classify as such? they could be detected and then correctly assigned in the + * fluid renderer directly. * * @author douira */ @@ -184,7 +191,7 @@ private class AngleSortData { // TODO: use faster code for this private static double angleCos(double ax, double ay, double az, double bx, double by, double bz) { double length1Squared = Math.fma(ax, ax, Math.fma(ay, ay, az * az)); - double length2Squared = Math.fma(bx, bx, Math.fma(by,by, bz * bz)); + double length2Squared = Math.fma(bx, bx, Math.fma(by, by, bz * bz)); double dot = Math.fma(ax, bx, Math.fma(ay, by, az * bz)); return dot / Math.sqrt(length1Squared * length2Squared); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java index d709a14c59..b33bec7c8a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java @@ -122,9 +122,10 @@ public SectionRenderDataStorage createStorage(TerrainRenderPass pass) { return storage; } - public void refresh(CommandList commandList) { + public void refreshTesselation(CommandList commandList) { if (this.resources != null) { this.resources.deleteTessellations(commandList); + this.resources.deleteIndexedTessellation(commandList); } for (var storage : this.sectionRenderData.values()) { @@ -132,12 +133,12 @@ public void refresh(CommandList commandList) { } } - public void refreshTranslucent(CommandList commandList) { + public void refreshIndexedTesselation(CommandList commandList) { if (this.resources != null) { this.resources.deleteIndexedTessellation(commandList); } - this.sectionRenderData.get(DefaultTerrainRenderPasses.TRANSLUCENT).onBufferResized(); + this.sectionRenderData.get(DefaultTerrainRenderPasses.TRANSLUCENT).onIndexBufferResized(); } public void addSection(RenderSection section) { @@ -198,13 +199,19 @@ public ChunkRenderList getRenderList() { } public static class DeviceResources { - private final GlBufferArena arena; + private final GlBufferArena geometryArena; + private final GlBufferArena indexArena; private GlTessellation tessellation; private GlTessellation indexedTessellation; public DeviceResources(CommandList commandList, StagingBuffer stagingBuffer) { int stride = ChunkMeshFormats.COMPACT.getVertexFormat().getStride(); - this.arena = new GlBufferArena(commandList, REGION_SIZE * 756, stride, stagingBuffer); + + // the magic number 756 for the initial size is arbitrary, it was made up. + var initialVertices = 756; + this.geometryArena = new GlBufferArena(commandList, REGION_SIZE * initialVertices, stride, stagingBuffer); + var initialIndices = (initialVertices / 4) * 6; + this.indexArena = new GlBufferArena(commandList, REGION_SIZE * initialIndices, Integer.BYTES, stagingBuffer); } public void updateTessellation(CommandList commandList, GlTessellation tessellation) { @@ -245,22 +252,31 @@ public void deleteIndexedTessellation(CommandList commandList) { } } - public GlBuffer getBuffer() { - return this.arena.getBufferObject(); + public GlBuffer getGeometryBuffer() { + return this.geometryArena.getBufferObject(); + } + + public GlBuffer getIndexBuffer() { + return this.indexArena.getBufferObject(); } public void delete(CommandList commandList) { this.deleteTessellations(commandList); this.deleteIndexedTessellation(commandList); - this.arena.delete(commandList); + this.geometryArena.delete(commandList); + this.indexArena.delete(commandList); + } + + public GlBufferArena getGeometryArena() { + return this.geometryArena; } - public GlBufferArena getArena() { - return this.arena; + public GlBufferArena getIndexArena() { + return this.indexArena; } public boolean shouldDelete() { - return this.arena.isEmpty(); + return this.geometryArena.isEmpty() && this.indexArena.isEmpty(); } } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java index 6c8ecf1f0a..cb61df42d1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java @@ -108,14 +108,14 @@ private void uploadResults(CommandList commandList, RenderRegion region, Collect var resources = region.createResources(commandList); if (!uploads.isEmpty()) { - var arena = resources.getArena(); + var arena = resources.getGeometryArena(); boolean bufferChanged = arena.upload(commandList, uploads.stream() .map(upload -> upload.vertexUpload)); // If any of the buffers changed, the tessellation will need to be updated // Once invalidated the tessellation will be re-created on the next attempted use if (bufferChanged) { - region.refresh(commandList); + region.refreshTesselation(commandList); } // Collect the upload results @@ -127,12 +127,12 @@ private void uploadResults(CommandList commandList, RenderRegion region, Collect } if (!indexUploads.isEmpty()) { - var arena = resources.getArena(); + var arena = resources.getIndexArena(); boolean bufferChanged = arena.upload(commandList, indexUploads.stream() .map(upload -> upload.indexBufferUpload)); if (bufferChanged) { - region.refreshTranslucent(commandList); + region.refreshIndexedTesselation(commandList); } for (PendingSectionIndexBufferUpload upload : indexUploads) { From 8e7baef4fd84c84b206cb166355edb9b5704b046 Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 21 Oct 2023 20:05:49 +0200 Subject: [PATCH 094/256] documentation comments --- .../render/chunk/DefaultChunkRenderer.java | 13 +++++++++++++ .../chunk/compile/pipeline/FluidRenderer.java | 4 ++++ .../chunk/data/SectionRenderDataStorage.java | 16 ++++++++++++++++ .../render/chunk/lists/SortedRenderLists.java | 5 +++++ .../chunk/lists/VisibleChunkCollector.java | 4 ++++ .../client/render/chunk/region/RenderRegion.java | 8 ++++++++ 6 files changed, 50 insertions(+) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java index 7c02550934..52a77bc4dd 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java @@ -41,6 +41,11 @@ public DefaultChunkRenderer(RenderDevice device, ChunkVertexType vertexType) { this.sharedIndexBuffer = new SharedQuadIndexBuffer(device.createCommandList(), SharedQuadIndexBuffer.IndexType.INTEGER); } + /** + * Renders the terrain for a particular render pass. Each region is rendered + * with one draw call. The command buffer for each draw command is filled by + * iterating the sections and adding the draw commands for each section. + */ @Override public void render(ChunkRenderMatrices matrices, CommandList commandList, @@ -134,6 +139,14 @@ private static void fillCommandBuffer(MultiDrawBatch batch, } } + /** + * Add the draw command into the multi draw batch of the current region for one + * section. The section's mesh data is given as a pointer into the render data + * storage's allocated memory. It goes through each direction and writes the + * offsets and lengths of the already uploaded vertex and index data. The multi + * draw batch provides pointers to arrays where each of the section's data is + * stored. The batch's size counts how many commands it contains. + */ @SuppressWarnings("IntegerMultiplicationImplicitCastToLong") private static void addDrawCommands(MultiDrawBatch batch, long pMeshData, int mask) { final var pElementPointer = batch.pElementPointer; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java index 4a362939ac..6bf9785042 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java @@ -42,6 +42,10 @@ import org.apache.commons.lang3.mutable.MutableFloat; import org.apache.commons.lang3.mutable.MutableInt; +/** + * The fluid renderer produces the quads for block of fluid. It generates inside + * and outside quads for each face of the block. + */ public class FluidRenderer { // TODO: allow this to be changed by vertex format // TODO: move fluid rendering to a separate render pass and control glPolygonOffset and glDepthFunc to fix this properly diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java index e829f402c0..2c2d94225b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java @@ -7,6 +7,22 @@ import java.util.Arrays; +/** + * The section render data storage stores the gl buffer segments of uploaded + * data on the gpu. There's one storage object per region. It stores information + * about vertex and optionally index buffer data. The array of buffer segment is + * indexed by the region-local section index. The data about the contents of + * buffer segments is stored in a natively allocated piece of memory referenced + * by {@code pMeshDataArray} and accessed through + * {@link SectionRenderDataUnsafe}. + * + * When the backing buffer (from the gl buffer arena) is resized, the storage + * object is notified and then it updates the changed offsets of the buffer + * segments. Since the index data's size and alignment directly corresponds to + * that of the vertex data except for the vertex/index scaling of two thirds, + * only an offset to the index data within the index data buffer arena is + * stored. + */ public class SectionRenderDataStorage { private final GlBufferSegment[] allocations; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/lists/SortedRenderLists.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/lists/SortedRenderLists.java index 7c28e941ab..152e5ea40a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/lists/SortedRenderLists.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/lists/SortedRenderLists.java @@ -5,6 +5,11 @@ import me.jellysquid.mods.sodium.client.util.iterator.ReversibleObjectArrayIterator; import me.jellysquid.mods.sodium.client.render.chunk.region.RenderRegion; +/** + * Stores one render list of sections per region, sorted by the order in which + * they were discovered in the BFS of the occlusion culler. It also generates + * render lists for sections of previously unseen regions. + */ public class SortedRenderLists implements ChunkRenderListIterable { private static final SortedRenderLists EMPTY = new SortedRenderLists(ObjectArrayList.of()); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/lists/VisibleChunkCollector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/lists/VisibleChunkCollector.java index d46fa7abf5..d5a11ee4e1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/lists/VisibleChunkCollector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/lists/VisibleChunkCollector.java @@ -9,6 +9,10 @@ import java.util.Queue; import java.util.function.Consumer; +/** + * The visible chunk collector is passed to the occlusion graph search culler to + * collect the visible chunks. + */ public class VisibleChunkCollector implements Consumer { private final SortedRenderLists.Builder sortedRenderLists; private final EnumMap> sortedRebuildLists; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java index b33bec7c8a..f2776bdc93 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java @@ -204,6 +204,14 @@ public static class DeviceResources { private GlTessellation tessellation; private GlTessellation indexedTessellation; + /** + * The buffer arenas return offsets in terms of how many stride units big things + * are. This means that if the stride is the length of a vertex, the buffer + * arena works with vertices and returns vertex offsets. The arena working with + * indices has as stride of four corresponding to the length of an integer. The + * two can't easily be combined because integers and vertices require different + * amounts of data which makes the returned offsets incompatible. + */ public DeviceResources(CommandList commandList, StagingBuffer stagingBuffer) { int stride = ChunkMeshFormats.COMPACT.getVertexFormat().getStride(); From 0cf0783afa363ee94852993144e1d1b8be5f6a4b Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 21 Oct 2023 21:27:59 +0200 Subject: [PATCH 095/256] implement better give-up heuristic for dynamic sort --- .../client/render/chunk/gfni/DynamicData.java | 102 +++++++----------- 1 file changed, 39 insertions(+), 63 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java index 16fe48a1c5..e5ff0f3839 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java @@ -1,10 +1,7 @@ package me.jellysquid.mods.sodium.client.render.chunk.gfni; import java.nio.IntBuffer; -import java.util.Collection; -import java.util.concurrent.ConcurrentLinkedDeque; -import org.apache.commons.lang3.tuple.Pair; import org.joml.Vector3fc; import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; @@ -24,6 +21,9 @@ public class DynamicData extends MixedDirectionData { private TranslucentGeometryCollector collector; private Object2ReferenceOpenHashMap distancesByNormal; + private static final int MAX_TOPO_SORT_QUADS = 1000; + private static final int MAX_TOPO_SORT_TIME_NS = 750000; + DynamicData(ChunkSectionPos sectionPos, NativeBuffer buffer, VertexRange range, TQuad[] quads, TranslucentGeometryCollector collector, @@ -39,47 +39,6 @@ public SortType getSortType() { return SortType.DYNAMIC_ALL; } - private static final Collection> sortTimingData = new ConcurrentLinkedDeque<>(); - - private static void updateTimingData(int quadCount, long sortTime) { - sortTimingData.add(Pair.of(quadCount, sortTime)); - if (sortTimingData.size() > 3000) { - synchronized (sortTimingData) { - if (sortTimingData.size() <= 3000) { - return; - } - var totalQuads = sortTimingData.stream().mapToLong(Pair::getLeft).sum(); - var totalTime = sortTimingData.stream().mapToLong(Pair::getRight).sum(); - var averageTime = totalTime / (double) sortTimingData.size(); - var averageQuads = totalQuads / (double) sortTimingData.size(); - System.out.println("Average sort time: " + averageTime + "ms for " + averageQuads + " quads"); - - // print whole data as csv - var builder = new StringBuilder(); - builder.append("\nquads,time\n"); - for (var pair : sortTimingData) { - builder.append(pair.getLeft()).append(",").append(pair.getRight()).append(";"); - } - System.out.println(builder.toString()); - - sortTimingData.clear(); - } - } - } - - private long sortStart; - - void startSortTimer() { - this.sortStart = System.nanoTime(); - } - - void endSortTimer() { - // var sortTime = System.nanoTime() - this.sortStart; - // if (this instanceof PresentTranslucentData present) { - // updateTimingData(present.getQuadLength(), sortTime); - // } - } - @Override public boolean prepareTrigger(boolean isAngleTrigger) { // if an angle trigger was scheduled but isn't needed, return true to signal @@ -94,42 +53,59 @@ public boolean prepareTrigger(boolean isAngleTrigger) { @Override public void sortOnTrigger(Vector3fc cameraPos) { - this.sortWithTiming(cameraPos, this.pendingTriggerIsAngle); + this.sort(cameraPos, this.pendingTriggerIsAngle); + } + + private void turnGFNITriggerOff() { + if (this.GFNITrigger) { + this.GFNITrigger = false; + this.turnGFNITriggerOff = true; + } } - private void sortWithTiming(Vector3fc cameraPos, boolean isAngleTrigger) { - this.startSortTimer(); - this.sort(cameraPos, isAngleTrigger); - this.endSortTimer(); + private void turnAngleTriggerOn() { + if (!this.angleTrigger) { + this.angleTrigger = true; + this.turnAngleTriggerOn = true; + } } private void sort(Vector3fc cameraPos, boolean isAngleTrigger) { // uses a topo sort or a distance sort depending on what is enabled IntBuffer indexBuffer = this.buffer.getDirectBuffer().asIntBuffer(); + if (this.quads.length > MAX_TOPO_SORT_QUADS) { + turnGFNITriggerOff(); + turnAngleTriggerOn(); + } + if (this.GFNITrigger && !isAngleTrigger) { - if (ComplexSorting.topoSortDepthFirstCyclic(indexBuffer, this.quads, this.distancesByNormal, cameraPos)) { + var sortStart = System.nanoTime(); + + var result = ComplexSorting.topoSortDepthFirstCyclic( + indexBuffer, this.quads, this.distancesByNormal, cameraPos); + + var sortTime = System.nanoTime() - sortStart; + if (sortTime > MAX_TOPO_SORT_TIME_NS) { + turnGFNITriggerOff(); + turnAngleTriggerOn(); + } + + if (result) { // disable distance sorting because topo sort seems to be possible. // removal from angle triggering happens automatically by setting this to false. this.angleTrigger = false; return; } else { // topo sort failure, the topo sort algorithm doesn't work on all cases - System.out.println("Failed to sort at " + this.sectionPos); - // TODO: implement different give-up heuristic. this gives up after the second - // failure. + // gives up after the second failure. it keeps GFNI triggering with topo sort on + // while the angle triggering is also active to maybe get a topo sort success + // from a different angle. if (this.angleTrigger) { - // turn off if currently on and signal change - if (this.GFNITrigger) { - this.GFNITrigger = false; - this.turnGFNITriggerOff = true; - } - } - if (!this.angleTrigger) { - this.angleTrigger = true; - this.turnAngleTriggerOn = true; + turnGFNITriggerOff(); } + turnAngleTriggerOn(); } } if (this.angleTrigger) { @@ -184,7 +160,7 @@ static DynamicData fromMesh(BuiltSectionMeshParts translucentMesh, var dynamicData = new DynamicData(sectionPos, buffer, range, quads, collector, distancesByNormal); - dynamicData.sortWithTiming(cameraPos, false); + dynamicData.sort(cameraPos, false); return dynamicData; } From 2c058dd06e9ff3fa3c5745b15719767e019b40a3 Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 21 Oct 2023 23:49:22 +0200 Subject: [PATCH 096/256] fix quad visibility geometry --- .../render/chunk/gfni/ComplexSorting.java | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java index 8c848f1a74..632a15c8d6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java @@ -112,18 +112,17 @@ public static void distanceSortDirect(IntBuffer indexBuffer, TQuad[] quads, Vect TranslucentData.writeQuadVertexIndexes(indexBuffer, indexes); } - private static boolean orthoExtentWithinHalfspace(TQuad halfspace, TQuad otherQuad) { - var halfspaceDirection = halfspace.facing().ordinal(); - var otherQuadOppositeDirection = halfspace.facing().getOpposite().ordinal(); - var sign = halfspace.facing().getSign(); + private static boolean orthogonalQuadVisibleThrough(TQuad halfspace, TQuad otherQuad) { + var hd = halfspace.facing().ordinal(); + var hdOpposite = halfspace.facing().getOpposite().ordinal(); + var od = otherQuad.facing().ordinal(); + var hSign = halfspace.facing().getSign(); + var otherSign = otherQuad.facing().getSign(); - return sign * halfspace.extents()[halfspaceDirection] - QUERY_EPSILON > sign * otherQuad.extents()[otherQuadOppositeDirection]; - } - - private static boolean orthogonalQuadVisibleThrough(TQuad quad, TQuad otherQuad) { // A: test that the other quad has an extent within this quad's halfspace - // B: test that this quad has an extent outside the other quad's halfspace - return orthoExtentWithinHalfspace(quad, otherQuad) && !orthoExtentWithinHalfspace(otherQuad, quad); + return hSign * halfspace.extents()[hd] - QUERY_EPSILON > hSign * otherQuad.extents()[hdOpposite] + // B: test that this quad is not fully within the other quad's halfspace + && !(otherSign * otherQuad.extents()[od] - QUERY_EPSILON >= otherSign * halfspace.extents()[od]); } /** From f74eb8ae1570e3edefc14eefc1a07926e6b89a30 Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 21 Oct 2023 23:50:03 +0200 Subject: [PATCH 097/256] better give up heuristic --- .../client/render/chunk/gfni/DynamicData.java | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java index e5ff0f3839..5995871afc 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java @@ -17,12 +17,15 @@ public class DynamicData extends MixedDirectionData { boolean angleTrigger = false; boolean turnAngleTriggerOn = false; boolean turnGFNITriggerOff = false; + private int consecutiveTopoSortFailures = 0; private boolean pendingTriggerIsAngle; private TranslucentGeometryCollector collector; private Object2ReferenceOpenHashMap distancesByNormal; private static final int MAX_TOPO_SORT_QUADS = 1000; - private static final int MAX_TOPO_SORT_TIME_NS = 750000; + private static final int MAX_TOPO_SORT_TIME_NS = 1_000_000; + private static final int MAX_FAILING_TOPO_SORT_TIME_NS = 750_000; + private static final int MAX_TOPO_SORT_PATIENT_TIME_NS = 250_000; DynamicData(ChunkSectionPos sectionPos, NativeBuffer buffer, VertexRange range, TQuad[] quads, @@ -86,7 +89,12 @@ private void sort(Vector3fc cameraPos, boolean isAngleTrigger) { indexBuffer, this.quads, this.distancesByNormal, cameraPos); var sortTime = System.nanoTime() - sortStart; - if (sortTime > MAX_TOPO_SORT_TIME_NS) { + + // if we've already failed, there's reduced patience for sorting since the + // probability of failure and wasted compute time is higher + if (sortTime > (this.consecutiveTopoSortFailures > 0 + ? MAX_FAILING_TOPO_SORT_TIME_NS + : MAX_TOPO_SORT_TIME_NS)) { turnGFNITriggerOff(); turnAngleTriggerOn(); } @@ -95,14 +103,16 @@ private void sort(Vector3fc cameraPos, boolean isAngleTrigger) { // disable distance sorting because topo sort seems to be possible. // removal from angle triggering happens automatically by setting this to false. this.angleTrigger = false; + this.consecutiveTopoSortFailures = 0; return; } else { // topo sort failure, the topo sort algorithm doesn't work on all cases - // gives up after the second failure. it keeps GFNI triggering with topo sort on - // while the angle triggering is also active to maybe get a topo sort success - // from a different angle. - if (this.angleTrigger) { + // gives up after a certain number of failures. it keeps GFNI triggering with + // topo sort on while the angle triggering is also active to maybe get a topo + // sort success from a different angle. + this.consecutiveTopoSortFailures++; + if (this.consecutiveTopoSortFailures >= (sortTime <= MAX_TOPO_SORT_PATIENT_TIME_NS ? 5 : 2)) { turnGFNITriggerOff(); } turnAngleTriggerOn(); From e099aa856f5d0fc4326099c9ffed670239d1cb4f Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 21 Oct 2023 23:50:17 +0200 Subject: [PATCH 098/256] fix not clearing trigger changes --- .../mods/sodium/client/render/chunk/gfni/DynamicData.java | 5 +++++ .../mods/sodium/client/render/chunk/gfni/GFNI.java | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java index 5995871afc..2b90e34407 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java @@ -125,6 +125,11 @@ private void sort(Vector3fc cameraPos, boolean isAngleTrigger) { } } + public void clearTriggerChanges() { + this.turnAngleTriggerOn = false; + this.turnGFNITriggerOff = false; + } + public boolean hasTriggerChanges() { return this.turnAngleTriggerOn || this.turnGFNITriggerOff; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java index 9e9e7ee1ae..57b097ad28 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java @@ -284,6 +284,7 @@ public void applyTriggerChanges(DynamicData data, ChunkSectionPos pos, Vector3dc if (data.turnGFNITriggerOff) { disableGFNITriggering(data, pos.asLong()); } + data.clearTriggerChanges(); } private void enableAngleTriggering(DynamicData data, ChunkSectionPos section, Vector3dc cameraPos) { @@ -412,6 +413,6 @@ public void addDebugStrings(List list) { + " SNR=" + this.sortTypeCounters[SortType.STATIC_NORMAL_RELATIVE.ordinal()] + " STA=" + this.sortTypeCounters[SortType.STATIC_TOPO_ACYCLIC.ordinal()] + " DYN=" + this.sortTypeCounters[SortType.DYNAMIC_ALL.ordinal()] - + " ANG=" + this.angleTriggerSections.size()); + + " (ANG=" + this.angleTriggerSections.size() + ")"); } } From 8c53247dc604af76379a5795fd85a6e1026bdf28 Mon Sep 17 00:00:00 2001 From: douira Date: Sun, 22 Oct 2023 03:53:40 +0200 Subject: [PATCH 099/256] update notes --- .../mods/sodium/client/render/chunk/gfni/GFNI.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java index 57b097ad28..5c52d9d25f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java @@ -25,9 +25,6 @@ * may result in many sections suddenly needing sorting when the camera moves. * Maybe it's better to schedule them to be sorted gradually even if not * visible, if there are idle threads. - * - sort only up to a certain number of quads to limit rebuild time to some - * fixed value. determine how many that is by observing timings. - * - implement angle-based triggering for difficult or large sections * - De-epsilon all the geometry by snapping to multiples of 0.005 or sth like * that. Would simplify the ComplexSorting code so that it doesn't need to deal * with the existence of error margins (epsilons in the trigger distances and @@ -46,6 +43,9 @@ * - Does fluid renderer sometimes produce aligned faces that it doesn't * classify as such? they could be detected and then correctly assigned in the * fluid renderer directly. + * - Check that separators still work on aligned geomtry. It seems that a lot of + * things are not topo sortable after the most recent fix to the quad visibility + * check. * * @author douira */ From 6a1047ebe7d4a3512d2f3a1f8d6dad0be54d9b29 Mon Sep 17 00:00:00 2001 From: douira Date: Thu, 26 Oct 2023 15:02:04 +0200 Subject: [PATCH 100/256] use a new position vector every time --- .../mods/sodium/client/render/SodiumWorldRenderer.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index 325d851b7a..3f1403cadb 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -183,7 +183,6 @@ public void setupTerrain(Camera camera, this.renderSectionManager.markGraphDirty(); } - this.lastCameraPitch = pitch; this.lastCameraYaw = yaw; this.lastFogDistance = fogDistance; @@ -203,13 +202,10 @@ public void setupTerrain(Camera camera, } if (cameraLocationChanged) { - profiler.swap("gfni_query"); + profiler.swap("translucent_triggering"); - this.renderSectionManager.processGFNIMovement( - new CameraMovement(lastCameraPos, new Vector3d(pos.x, pos.y, pos.z))); - this.lastCameraPos.x = pos.x; - this.lastCameraPos.y = pos.y; - this.lastCameraPos.z = pos.z; + this.renderSectionManager.processGFNIMovement(new CameraMovement(lastCameraPos, pos)); + this.lastCameraPos = new Vector3d(pos); } if (updateChunksImmediately) { From 1099eb9b91a24e53e23c8aab877e9f802c72f3db Mon Sep 17 00:00:00 2001 From: douira Date: Thu, 26 Oct 2023 15:05:50 +0200 Subject: [PATCH 101/256] fix direct triggering and rename from angle triggering, add distance based direct triggering for close sections, simplify section triggering to avoid return value WIP: see GFNI doc comment --- .../client/render/chunk/RenderSection.java | 9 +- .../render/chunk/RenderSectionManager.java | 8 +- .../client/render/chunk/gfni/DynamicData.java | 54 ++-- .../sodium/client/render/chunk/gfni/GFNI.java | 280 ++++++++++++------ .../render/chunk/gfni/TranslucentData.java | 9 +- .../gfni/TranslucentGeometryCollector.java | 15 +- 6 files changed, 229 insertions(+), 146 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java index 74dc44b321..d31ed4ea6e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java @@ -344,11 +344,10 @@ public void setPendingUpdate(@Nullable ChunkUpdateType type) { this.pendingUpdateType = type; } - public boolean prepareTrigger(boolean isAngleTrigger) { - if (this.translucentData != null) { - return this.translucentData.prepareTrigger(isAngleTrigger); - } - return false; + public void prepareTrigger(boolean isAngleTrigger) { + + this.translucentData.prepareTrigger(isAngleTrigger); + } public int getLastUploadFrame() { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index 1e368b9f9b..7ad3b8728d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -492,7 +492,7 @@ public int getVisibleChunkCount() { return sections; } - public boolean scheduleSort(long sectionPos, boolean isAngleTrigger) { + public void scheduleSort(long sectionPos, boolean isAngleTrigger) { // TODO: Does this need to invalidate the section cache? RenderSection section = this.sectionByPosition.get(sectionPos); @@ -505,13 +505,9 @@ public boolean scheduleSort(long sectionPos, boolean isAngleTrigger) { pendingUpdate = ChunkUpdateType.getPromotionUpdateType(section.getPendingUpdate(), pendingUpdate); if (pendingUpdate != null) { section.setPendingUpdate(pendingUpdate); - return section.prepareTrigger(isAngleTrigger); + section.prepareTrigger(isAngleTrigger); } - } else { - // remove unloaded sections from triggering - return true; } - return false; } public void scheduleRebuild(int x, int y, int z, boolean important) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java index 2b90e34407..fab86241bc 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java @@ -14,9 +14,11 @@ public class DynamicData extends MixedDirectionData { private final TQuad[] quads; boolean GFNITrigger = true; - boolean angleTrigger = false; - boolean turnAngleTriggerOn = false; + boolean directTrigger = false; boolean turnGFNITriggerOff = false; + boolean turnDirectTriggerOn = false; + boolean turnDirectTriggerOff = false; + double directTriggerKey = -1; private int consecutiveTopoSortFailures = 0; private boolean pendingTriggerIsAngle; private TranslucentGeometryCollector collector; @@ -26,6 +28,8 @@ public class DynamicData extends MixedDirectionData { private static final int MAX_TOPO_SORT_TIME_NS = 1_000_000; private static final int MAX_FAILING_TOPO_SORT_TIME_NS = 750_000; private static final int MAX_TOPO_SORT_PATIENT_TIME_NS = 250_000; + private static final int PATIENT_TOPO_ATTEMPTS = 5; + private static final int REGULAR_TOPO_ATTEMPTS = 2; DynamicData(ChunkSectionPos sectionPos, NativeBuffer buffer, VertexRange range, TQuad[] quads, @@ -43,15 +47,8 @@ public SortType getSortType() { } @Override - public boolean prepareTrigger(boolean isAngleTrigger) { - // if an angle trigger was scheduled but isn't needed, return true to signal - // removal from angle triggering - if (isAngleTrigger && !this.angleTrigger) { - return true; - } - + public void prepareTrigger(boolean isAngleTrigger) { this.pendingTriggerIsAngle = isAngleTrigger; - return false; } @Override @@ -66,20 +63,31 @@ private void turnGFNITriggerOff() { } } - private void turnAngleTriggerOn() { - if (!this.angleTrigger) { - this.angleTrigger = true; - this.turnAngleTriggerOn = true; + private void turnDirectTriggerOn() { + if (!this.directTrigger) { + this.directTrigger = true; + this.turnDirectTriggerOn = true; } } + private void turnDirectTriggerOff() { + if (this.directTrigger) { + this.directTrigger = false; + this.turnDirectTriggerOff = true; + } + } + + private static int getAttemptsForTime(long ns) { + return ns <= MAX_TOPO_SORT_PATIENT_TIME_NS ? PATIENT_TOPO_ATTEMPTS : REGULAR_TOPO_ATTEMPTS; + } + private void sort(Vector3fc cameraPos, boolean isAngleTrigger) { // uses a topo sort or a distance sort depending on what is enabled IntBuffer indexBuffer = this.buffer.getDirectBuffer().asIntBuffer(); if (this.quads.length > MAX_TOPO_SORT_QUADS) { turnGFNITriggerOff(); - turnAngleTriggerOn(); + turnDirectTriggerOn(); } if (this.GFNITrigger && !isAngleTrigger) { @@ -96,13 +104,12 @@ private void sort(Vector3fc cameraPos, boolean isAngleTrigger) { ? MAX_FAILING_TOPO_SORT_TIME_NS : MAX_TOPO_SORT_TIME_NS)) { turnGFNITriggerOff(); - turnAngleTriggerOn(); + turnDirectTriggerOn(); } if (result) { // disable distance sorting because topo sort seems to be possible. - // removal from angle triggering happens automatically by setting this to false. - this.angleTrigger = false; + turnDirectTriggerOff(); this.consecutiveTopoSortFailures = 0; return; } else { @@ -112,13 +119,13 @@ private void sort(Vector3fc cameraPos, boolean isAngleTrigger) { // topo sort on while the angle triggering is also active to maybe get a topo // sort success from a different angle. this.consecutiveTopoSortFailures++; - if (this.consecutiveTopoSortFailures >= (sortTime <= MAX_TOPO_SORT_PATIENT_TIME_NS ? 5 : 2)) { + if (this.consecutiveTopoSortFailures >= getAttemptsForTime(sortTime)) { turnGFNITriggerOff(); } - turnAngleTriggerOn(); + turnDirectTriggerOn(); } } - if (this.angleTrigger) { + if (this.directTrigger) { indexBuffer.rewind(); ComplexSorting.distanceSortDirect(indexBuffer, this.quads, cameraPos); return; @@ -126,12 +133,13 @@ private void sort(Vector3fc cameraPos, boolean isAngleTrigger) { } public void clearTriggerChanges() { - this.turnAngleTriggerOn = false; this.turnGFNITriggerOff = false; + this.turnDirectTriggerOn = false; + this.turnDirectTriggerOff = false; } public boolean hasTriggerChanges() { - return this.turnAngleTriggerOn || this.turnGFNITriggerOff; + return this.turnGFNITriggerOff || this.turnDirectTriggerOn || this.turnDirectTriggerOff; } TranslucentGeometryCollector getCollector() { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java index 5c52d9d25f..37436d236d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java @@ -1,13 +1,13 @@ package me.jellysquid.mods.sodium.client.render.chunk.gfni; import java.util.List; -import java.util.function.BiFunction; +import java.util.function.BiConsumer; import org.joml.Vector3d; import org.joml.Vector3dc; import org.joml.Vector3fc; -import it.unimi.dsi.fastutil.doubles.Double2ObjectAVLTreeMap; +import it.unimi.dsi.fastutil.doubles.Double2ObjectRBTreeMap; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; @@ -46,6 +46,14 @@ * - Check that separators still work on aligned geomtry. It seems that a lot of * things are not topo sortable after the most recent fix to the quad visibility * check. + * - figure out why when the player moves at high speed there end up being more + * direct trigger entries than sections with the dynamic sort type, even if + * everything is set to only direct trigger and not GFNI trigger. (the numbers + * should be the same, somehow they're not being bookkept correctly) + * - determine the right distance for angle/distance triggering. It seems just + * the diagonal of a section is too small, angle triggering is broken at close + * distances. + * - separate this class into GFNI and direct triggering? * * @author douira */ @@ -66,28 +74,25 @@ public class GFNI { private Object2ReferenceOpenHashMap normalLists = new Object2ReferenceOpenHashMap<>(50); /** - * A tree map of the directly (angle-based) triggered sections, indexed by their + * A tree map of the directly triggered sections, indexed by their * minimum required camera movement. When the given camera movement is exceeded, - * they are tested for triggering the angle-condition. + * they are tested for triggering the angle or distance condition. * * The accumulated distance is monotonically increasing and is never reset. This * only becomes a problem when the camera moves more than 10^15 blocks in total. * There will be precision issues at around 10^10 maybe, but it's still not a * concern. */ - private Double2ObjectAVLTreeMap angleTriggerSections = new Double2ObjectAVLTreeMap<>(); + private Double2ObjectRBTreeMap directTriggerSections = new Double2ObjectRBTreeMap<>(); private double accumulatedDistance = 0; /** * To avoid generating a collection of the triggered sections, this callback is * used to process the triggered sections directly as they are queried from the * normal lists' interval trees. The callback is given the section coordinates, - * and a boolean indicating if the trigger was an angle-based trigger. In the - * case of an angle trigger, it turns true if the section should be removed from - * future triggering (when the translucent data no longer hast the corresponding - * flag set) + * and a boolean indicating if the trigger was an direct trigger. */ - private BiFunction triggerSectionCallback; + private BiConsumer triggerSectionCallback; /** * A set of all the sections that were triggered the last time something was @@ -131,14 +136,13 @@ private void incrementSortTypeCounter(TranslucentData newData) { * @param cameraY the camera y position after the movement * @param cameraZ the camera z position after the movement */ - public void triggerSections(BiFunction triggerSectionCallback, - CameraMovement movement) { + public void triggerSections(BiConsumer triggerSectionCallback, CameraMovement movement) { triggeredSections.clear(); triggeredNormals.clear(); this.triggerSectionCallback = triggerSectionCallback; processGFNITriggers(movement); - processAngleTriggers(movement); + processDirectTriggers(movement); var newTriggeredSectionsCount = this.triggeredSections.size(); var newTriggeredNormalCount = this.triggeredNormals.size(); @@ -166,25 +170,75 @@ private void processGFNITriggers(CameraMovement movement) { } } + /** + * The factor by which the trigger distance and angle are multiplied to get a + * smaller threshold that is used for the actual trigger check but not the + * remaining distance calculation. This prevents curved movements from taking + * sections out of the tree and re-inserting without triggering many times near + * the actual trigger distance. It cuts the repeating unsuccessful trigger + * attempts off early. + */ + private static final double EARLY_TRIGGER_FACTOR = 0.9; + /** * Degrees of movement from last sort position before the section is sorted * again. */ private static final double TRIGGER_ANGLE = Math.toRadians(20); - private static final double TRIGGER_ANGLE_COS = Math.cos(TRIGGER_ANGLE); - private static final double SECTION_CENTER_DIST = Math.sqrt(3 * (16 / 2) * (16 / 2)); + private static final double EARLY_TRIGGER_ANGLE_COS = Math.cos(TRIGGER_ANGLE * EARLY_TRIGGER_FACTOR); + private static final double SECTION_CENTER_DIST_SQUARED = 40 * 3 * Math.pow(16 / 2, 2); + private static final double SECTION_CENTER_DIST = Math.sqrt(SECTION_CENTER_DIST_SQUARED); + + /** + * How far the player must travel in blocks from the last position at which a + * section was sorted for it to be sorted again, if direct distance triggering + * is used (for close sections). + */ + private static final double DIRECT_TRIGGER_DISTANCE = 1; + private static final double EARLY_DIRECT_TRIGGER_DISTANCE_SQUARED = Math + .pow(DIRECT_TRIGGER_DISTANCE * EARLY_TRIGGER_FACTOR, 2); - private class AngleSortData { - ChunkSectionPos sectionPos; + private class DirectTriggerData { + final ChunkSectionPos sectionPos; + private Vector3dc sectionCenter; + final DynamicData dynamicData; /** - * Absolute camera position at the time of the last sort. + * Absolute camera position at the time of the last trigger. */ - Vector3dc sortCameraPos; + Vector3dc triggerCameraPos; - AngleSortData(ChunkSectionPos sectionPos, Vector3dc sortCameraPos) { + DirectTriggerData(DynamicData dynamicData, ChunkSectionPos sectionPos, Vector3dc triggerCameraPos) { + this.dynamicData = dynamicData; this.sectionPos = sectionPos; - this.sortCameraPos = sortCameraPos; + this.triggerCameraPos = triggerCameraPos; + } + + Vector3dc getSectionCenter() { + if (this.sectionCenter == null) { + this.sectionCenter = new Vector3d( + sectionPos.getMinX() + 8, + sectionPos.getMinY() + 8, + sectionPos.getMinZ() + 8); + } + return this.sectionCenter; + } + + /** + * Returns the distance between the sort camera pos and the center of the + * section. + */ + double getSectionCenterTriggerCameraDist() { + return Math.sqrt(getSectionCenterDistSquared(this.triggerCameraPos)); + } + + double getSectionCenterDistSquared(Vector3dc vector) { + Vector3dc sectionCenter = getSectionCenter(); + return sectionCenter.distanceSquared(vector); + } + + boolean isAngleTriggering(Vector3dc vector) { + return getSectionCenterDistSquared(vector) > SECTION_CENTER_DIST_SQUARED; } } @@ -196,114 +250,152 @@ private static double angleCos(double ax, double ay, double az, double bx, doubl return dot / Math.sqrt(length1Squared * length2Squared); } - private void processAngleTriggers(CameraMovement movement) { + private void processDirectTriggers(CameraMovement movement) { Vector3dc lastCamera = movement.lastCamera(); Vector3dc camera = movement.currentCamera(); - double distance = camera.distance(lastCamera); - this.accumulatedDistance += distance; + this.accumulatedDistance += lastCamera.distance(camera); // iterate all elements with a key of at most accumulatedDistance - var head = this.angleTriggerSections.headMap(this.accumulatedDistance); + var head = this.directTriggerSections.headMap(this.accumulatedDistance); for (var entry : head.double2ObjectEntrySet()) { - this.angleTriggerSections.remove(entry.getDoubleKey()); - var data = entry.getValue(); - ChunkSectionPos sectionPos = data.sectionPos; - Vector3dc sortCameraPos = data.sortCameraPos; - Vector3dc sectionCenter = new Vector3d( - sectionPos.getMinX() + 8, sectionPos.getMinY() + 8, sectionPos.getMinZ() + 8); - - // check if the angle since the last sort exceeds the threshold - double angleCos = angleCos( - sectionCenter.x() - sortCameraPos.x(), - sectionCenter.y() - sortCameraPos.y(), - sectionCenter.z() - sortCameraPos.z(), - sectionCenter.x() - camera.x(), - sectionCenter.y() - camera.y(), - sectionCenter.z() - camera.z()); - double remainingAngle = TRIGGER_ANGLE; - var addBack = true; - - // compare angles inverted because cosine flips it - if (angleCos <= TRIGGER_ANGLE_COS) { - // angle exceeded, trigger the section - if (this.triggerSectionAngle(sectionPos)) { - // section was marked as removed from angle trigger - addBack = false; + this.directTriggerSections.remove(entry.getDoubleKey()); + DirectTriggerData data = entry.getValue(); + + boolean isAngle = data.isAngleTriggering(camera); + if (isAngle) { + double remainingAngle = TRIGGER_ANGLE; + + // check if the angle since the last sort exceeds the threshold + Vector3dc sectionCenter = data.getSectionCenter(); + double angleCos = angleCos( + sectionCenter.x() - data.triggerCameraPos.x(), + sectionCenter.y() - data.triggerCameraPos.y(), + sectionCenter.z() - data.triggerCameraPos.z(), + sectionCenter.x() - camera.x(), + sectionCenter.y() - camera.y(), + sectionCenter.z() - camera.z()); + + // compare angles inverted because cosine flips it + if (angleCos <= EARLY_TRIGGER_ANGLE_COS) { + this.triggerSectionDirect(data.sectionPos); + data.triggerCameraPos = camera; + } else { + remainingAngle -= Math.acos(angleCos); } - data.sortCameraPos = camera; - sortCameraPos = camera; + + insertDirectAngleTrigger(data, camera, remainingAngle); } else { - remainingAngle -= Math.acos(angleCos); - } + double remainingDistance = DIRECT_TRIGGER_DISTANCE; + double lastTriggerCurrentCameraDistSquared = data.triggerCameraPos.distanceSquared(camera); - if (addBack) { - insertAngleTrigger(data, remainingAngle); + if (lastTriggerCurrentCameraDistSquared >= EARLY_DIRECT_TRIGGER_DISTANCE_SQUARED) { + this.triggerSectionDirect(data.sectionPos); + data.triggerCameraPos = camera; + } else { + remainingDistance -= Math.sqrt(lastTriggerCurrentCameraDistSquared); + } + + insertDirectDistanceTrigger(data, camera, remainingDistance); } } } - private void insertAngleTrigger(AngleSortData data, double remainingAngle) { - ChunkSectionPos sectionPos = data.sectionPos; - Vector3dc sortCameraPos = data.sortCameraPos; - - // re-insert with new minimum required camera movement - double dx = sectionPos.getMinX() + 8 - sortCameraPos.x(); - double dy = sectionPos.getMinY() + 8 - sortCameraPos.y(); - double dz = sectionPos.getMinZ() + 8 - sortCameraPos.z(); - double centerMinDistance = Math.tan(remainingAngle) - * (Math.sqrt(dx * dx + dy * dy + dz * dz) - SECTION_CENTER_DIST); - if (centerMinDistance <= 0) { - // too close to section, TODO: sort more often/differently - // throw new NotImplementedException(); + private void insertDirectAngleTrigger(DirectTriggerData data, Vector3dc cameraPos, double remainingAngle) { + double triggerCameraSectionCenterDist = data.getSectionCenterTriggerCameraDist(); + double centerMinDistance = Math.tan(remainingAngle) * (triggerCameraSectionCenterDist - SECTION_CENTER_DIST); + insertJitteredTrigger(this.accumulatedDistance + centerMinDistance, data); + } + + private void insertDirectDistanceTrigger(DirectTriggerData data, Vector3dc cameraPos, double remainingDistance) { + insertJitteredTrigger(this.accumulatedDistance + remainingDistance, data); + } + + // jitters the double values to never overwrite the same key. abuses that + // doubles have more precision than we need to make them a kind of hash table + private double lastJittered = -1; + private double lastJitterResult = -1; + + private void insertJitteredTrigger(double key, DirectTriggerData data) { + // attempt insert without jittering + if (this.directTriggerSections.putIfAbsent(key, data) == null) { + data.dynamicData.directTriggerKey = key; return; } - this.angleTriggerSections.put(centerMinDistance + this.accumulatedDistance, data); + // if this is the same key as last time, skip all the identical keys that have + // already been jittered + if (this.lastJittered == key) { + key = this.lastJitterResult; + } else { + this.lastJittered = key; + } + + // Go to the next lower double to avoid collisions in the map. This slightly + // changes the key but doesn't significantly change its value. Subtraction is + // necessary to avoid delaying a trigger for too long. It's ok if it's too early + // though. This approach brings with it the disadvantages of linear probing but + // bad cases are unlikely to happen so it's fine. + do { + key = Math.nextDown(key); + } while (this.directTriggerSections.putIfAbsent(key, data) != null); + data.dynamicData.directTriggerKey = key; + this.lastJitterResult = key; } void triggerSectionGFNI(long sectionPos, int collectorKey) { this.triggeredNormals.add(collectorKey); this.triggeredSections.add(sectionPos); - this.triggerSectionCallback.apply(sectionPos, false); + this.triggerSectionCallback.accept(sectionPos, false); } - private boolean triggerSectionAngle(ChunkSectionPos sectionPos) { + private void triggerSectionDirect(ChunkSectionPos sectionPos) { var sectionPosLong = sectionPos.asLong(); - if (this.triggerSectionCallback.apply(sectionPosLong, true)) { - return true; - } else { - this.triggeredSections.add(sectionPosLong); - return false; - } + this.triggerSectionCallback.accept(sectionPosLong, true); + this.triggeredSections.add(sectionPosLong); } public void applyTriggerChanges(DynamicData data, ChunkSectionPos pos, Vector3dc cameraPos) { - if (data.turnAngleTriggerOn) { - enableAngleTriggering(data, pos, cameraPos); - } if (data.turnGFNITriggerOff) { disableGFNITriggering(data, pos.asLong()); } + if (data.turnDirectTriggerOn) { + enableDirectTriggering(data, pos, cameraPos); + } + if (data.turnDirectTriggerOff) { + disableDirectTriggering(data); + } data.clearTriggerChanges(); } - private void enableAngleTriggering(DynamicData data, ChunkSectionPos section, Vector3dc cameraPos) { - insertAngleTrigger(new AngleSortData(section, cameraPos), TRIGGER_ANGLE); + private void enableDirectTriggering(DynamicData data, ChunkSectionPos section, Vector3dc cameraPos) { + var newData = new DirectTriggerData(data, section, cameraPos); + if (newData.isAngleTriggering(cameraPos)) { + insertDirectAngleTrigger(newData, cameraPos, TRIGGER_ANGLE); + } else { + insertDirectDistanceTrigger(newData, cameraPos, DIRECT_TRIGGER_DISTANCE); + } + } + + private void disableDirectTriggering(TranslucentData data) { + if (data instanceof DynamicData dynamicData) { + var key = dynamicData.directTriggerKey; + if (key != -1) { + this.directTriggerSections.remove(key); + dynamicData.directTriggerKey = -1; + } + } } /** - * Removes a section from GFNI. This removes all its face planes. - * - * This doesn't remove sections from angle triggering since that would require - * another data structure to keep track of the inverse mapping from section to - * key. Instead, sections that shouldn't be angle triggered anymore are marked - * and then not re-added to the angle trigger tree. + * Removes a section from direct and GFNI triggering. This removes all its face + * planes. * * @param oldData the data of the section to remove * @param sectionPos the section to remove */ public void removeSection(TranslucentData oldData, long sectionPos) { disableGFNITriggering(oldData, sectionPos); + disableDirectTriggering(oldData); decrementSortTypeCounter(oldData); } @@ -372,9 +464,8 @@ private void initiallyEnableGFNITriggering(DynamicData data, long sectionPos) { /** * Integrates the data from a geometry collector into GFNI. The geometry - * collector - * contains the translucent face planes of a single section. This method may - * also remove the section if it has become irrelevant. + * collector contains the translucent face planes of a single section. This + * method may also remove the section if it has become irrelevant. * * @param builder the geometry collector to integrate * @return the sort type that the geometry collector's relevance heuristic @@ -388,6 +479,7 @@ public void integrateTranslucentData(TranslucentData oldData, TranslucentData ne // remove the section if the data doesn't need to trigger on face planes // TODO: only do the heuristic and topo sort if the hashes are different? if (newData instanceof DynamicData dynamicData) { + disableDirectTriggering(oldData); decrementSortTypeCounter(oldData); if (dynamicData.GFNITrigger) { initiallyEnableGFNITriggering(dynamicData, sectionPos); @@ -396,8 +488,8 @@ public void integrateTranslucentData(TranslucentData oldData, TranslucentData ne // (there's no option to add sections to GFNI later currently) dynamicData.deleteCollector(); } - if (dynamicData.angleTrigger) { - enableAngleTriggering(dynamicData, newData.sectionPos, cameraPos); + if (dynamicData.directTrigger) { + enableDirectTriggering(dynamicData, newData.sectionPos, cameraPos); } } else { removeSection(oldData, sectionPos); @@ -413,6 +505,6 @@ public void addDebugStrings(List list) { + " SNR=" + this.sortTypeCounters[SortType.STATIC_NORMAL_RELATIVE.ordinal()] + " STA=" + this.sortTypeCounters[SortType.STATIC_TOPO_ACYCLIC.ordinal()] + " DYN=" + this.sortTypeCounters[SortType.DYNAMIC_ALL.ordinal()] - + " (ANG=" + this.angleTriggerSections.size() + ")"); + + " (DIR=" + this.directTriggerSections.size() + ")"); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java index d94048a82d..c8198c0b19 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java @@ -35,17 +35,12 @@ public void sortOnTrigger(Vector3fc cameraPos) { /** * Prepares the translucent data for triggering of the given type. This is run - * on the main thread before a sort task is scheduled. If true is returned, the - * sort task will not be scheduled and it will be removed from angle triggering. - * Returning true if isAngleTrigger is false is a no-op. + * on the main thread before a sort task is scheduled. * * @param isAngleTrigger Whether the trigger is an angle trigger - * @return True if the sort task should not be scheduled and the section should - * be removed from angle triggering */ - public boolean prepareTrigger(boolean isAngleTrigger) { + public void prepareTrigger(boolean isAngleTrigger) { // no-op for other translucent data than dynamic - return false; } static int vertexCountToIndexBytes(int vertexCount) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java index 1014f26797..007575299d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java @@ -19,21 +19,14 @@ * determines the best sort type for the section and constructs various types of * translucent data objects that then perform sorting and get registered with * GFNI for triggering. - * - * TODO: can use a bunch more optimizations, this is a prototype. - * TODO list: - * - use continuous arrays for the quad centers and quad storage - * - use more accurate normals for unaligned topo sort? do we do topo sort on - * unaligned faces at all? - * - bail early during rendering if we decide not to topo sort, then we don't - * need to gather all of the data - * - detail how the graph construction and the topo sort works in the GFNI doc + * + * TODO: + * - use continuous arrays for the quad centers and quad storage if necessary + * - use more accurate normals for unaligned topo sort? * - optionally add a way to attempt full acyclic topo sort even if the * heuristic doesn't expect it to be possible. The caveat is that this costs * doing it once without invisible quad exclusion and once with if the first * attempt fails. - * - disable translucent data collection when setting is set to OFF to prevent - * overhead if no sorting is wanted. */ public class TranslucentGeometryCollector { AccumulationGroup[] axisAlignedDistances; From 37d7ee5b318a87e72d4564868b8997c2c01d2f02 Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 27 Oct 2023 17:06:24 +0200 Subject: [PATCH 102/256] rename is angle trigger to direct trigger --- .../sodium/client/render/chunk/DefaultChunkRenderer.java | 1 + .../mods/sodium/client/render/chunk/RenderSection.java | 7 ++----- .../sodium/client/render/chunk/RenderSectionManager.java | 4 ++-- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java index 52a77bc4dd..c41ec330c5 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java @@ -166,6 +166,7 @@ private static void addDrawCommands(MultiDrawBatch batch, long pMeshData, int ma if (indexDataOffset != 0) { // * 4 to convert to bytes (the buffer contains ints) // the section render data storage for the indices stores the offset in indices (also called elements) + // the << 3 is * 8 to convert to 8 byte offsets MemoryUtil.memPutAddress(pElementPointer + (size << 3), indexDataOffset << 2); // adding the number of elements works because the index data has one index per element (which are the indices) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java index d31ed4ea6e..85cb4f38b4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java @@ -51,7 +51,6 @@ public class RenderSection { @Nullable private TranslucentData translucentData; // TODO: is this the right category? - // Pending Update State @Nullable private CancellationToken taskCancellationToken = null; @@ -344,10 +343,8 @@ public void setPendingUpdate(@Nullable ChunkUpdateType type) { this.pendingUpdateType = type; } - public void prepareTrigger(boolean isAngleTrigger) { - - this.translucentData.prepareTrigger(isAngleTrigger); - + public void prepareTrigger(boolean isDirectTrigger) { + this.translucentData.prepareTrigger(isDirectTrigger); } public int getLastUploadFrame() { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index 7ad3b8728d..ba1f08b6e2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -492,7 +492,7 @@ public int getVisibleChunkCount() { return sections; } - public void scheduleSort(long sectionPos, boolean isAngleTrigger) { + public void scheduleSort(long sectionPos, boolean isDirectTrigger) { // TODO: Does this need to invalidate the section cache? RenderSection section = this.sectionByPosition.get(sectionPos); @@ -505,7 +505,7 @@ public void scheduleSort(long sectionPos, boolean isAngleTrigger) { pendingUpdate = ChunkUpdateType.getPromotionUpdateType(section.getPendingUpdate(), pendingUpdate); if (pendingUpdate != null) { section.setPendingUpdate(pendingUpdate); - section.prepareTrigger(isAngleTrigger); + section.prepareTrigger(isDirectTrigger); } } } From 273ede45ede565a8fb902bb445379f12eda0a30d Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 27 Oct 2023 19:04:18 +0200 Subject: [PATCH 103/256] reduce amount of work done in geometry collection --- .../gfni/TranslucentGeometryCollector.java | 90 ++++++++++++++----- 1 file changed, 66 insertions(+), 24 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java index 007575299d..cb6fea582a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java @@ -61,35 +61,77 @@ public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] verti Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY }; + // keep track of distinct vertices to compute the center accurately for + // degenerate quads + float lastX = vertices[3].x; + float lastY = vertices[3].y; + float lastZ = vertices[3].z; + int uniqueQuads = 0; + + float minX = Float.POSITIVE_INFINITY; + float minY = Float.POSITIVE_INFINITY; + float minZ = Float.POSITIVE_INFINITY; + float maxX = Float.NEGATIVE_INFINITY; + float maxY = Float.NEGATIVE_INFINITY; + float maxZ = Float.NEGATIVE_INFINITY; + for (int i = 0; i < 4; i++) { - var x = vertices[i].x; - var y = vertices[i].y; - var z = vertices[i].z; - - if (facing != ModelQuadFacing.UNASSIGNED && this.unalignedDistances == null) { - minBounds.x = Math.min(minBounds.x, x); - minBounds.y = Math.min(minBounds.y, y); - minBounds.z = Math.min(minBounds.z, z); - - maxBounds.x = Math.max(maxBounds.x, x); - maxBounds.y = Math.max(maxBounds.y, y); - maxBounds.z = Math.max(maxBounds.z, z); + float x = vertices[i].x; + float y = vertices[i].y; + float z = vertices[i].z; + + // TODO: see if this is faster than using Math.min and Math.max + if (x < minX) { + minX = x; + } else if (x > maxX) { + maxX = x; + } + if (y < minY) { + minY = y; + } else if (y > maxY) { + maxY = y; + } + if (z < minZ) { + minZ = z; + } else if (z > maxZ) { + maxZ = z; } - extents[0] = Math.max(extents[0], x); - extents[1] = Math.max(extents[1], y); - extents[2] = Math.max(extents[2], z); - extents[3] = Math.min(extents[3], x); - extents[4] = Math.min(extents[4], y); - extents[5] = Math.min(extents[5], z); - - // TODO: can we also just use two vertices at opposite corners of the quad? - xSum += x; - ySum += y; - zSum += z; + if (x != lastX || y != lastY || z != lastZ) { + xSum += x; + ySum += y; + zSum += z; + uniqueQuads++; + } + if (i != 3) { + lastX = x; + lastY = y; + lastZ = z; + } } - var center = new Vector3f(xSum * 0.25f, ySum * 0.25f, zSum * 0.25f); + var invCount = 1.0f / uniqueQuads; + var center = new Vector3f(xSum * invCount, ySum * invCount, zSum * invCount); + + if (facing != ModelQuadFacing.UNASSIGNED && this.unalignedDistances == null) { + minBounds.x = Math.min(minBounds.x, minX); + minBounds.y = Math.min(minBounds.y, minY); + minBounds.z = Math.min(minBounds.z, minZ); + maxBounds.x = Math.max(maxBounds.x, maxX); + maxBounds.y = Math.max(maxBounds.y, maxY); + maxBounds.z = Math.max(maxBounds.z, maxZ); + } + + extents[0] = maxX; + extents[1] = maxY; + extents[2] = maxZ; + extents[3] = minX; + extents[4] = minY; + extents[5] = minZ; + + // TODO: does it make a difference if we compute the center as the average of + // the unique vertices or as the center of the extents? (the latter would be + // less work) // TODO: some of these things should probably only be computed on demand, and an // allocation of a Quad object should be avoided From f91474cf0236a6d8aa8cd353c43ffbd70dd3d0d4 Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 27 Oct 2023 19:08:41 +0200 Subject: [PATCH 104/256] more compact code --- .../gfni/TranslucentGeometryCollector.java | 64 ++++++++----------- 1 file changed, 27 insertions(+), 37 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java index cb6fea582a..d09862e695 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java @@ -55,11 +55,6 @@ public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] verti float ySum = 0; float zSum = 0; - // initialize extents to positive or negative infinity - // POS_X, POS_Y, POS_Z, NEG_X, NEG_Y, NEG_Z - float[] extents = new float[] { - Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY, - Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY }; // keep track of distinct vertices to compute the center accurately for // degenerate quads @@ -68,12 +63,12 @@ public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] verti float lastZ = vertices[3].z; int uniqueQuads = 0; - float minX = Float.POSITIVE_INFINITY; - float minY = Float.POSITIVE_INFINITY; - float minZ = Float.POSITIVE_INFINITY; - float maxX = Float.NEGATIVE_INFINITY; - float maxY = Float.NEGATIVE_INFINITY; - float maxZ = Float.NEGATIVE_INFINITY; + float negXExtent = Float.POSITIVE_INFINITY; + float negYExtent = Float.POSITIVE_INFINITY; + float negZExtent = Float.POSITIVE_INFINITY; + float posXExtent = Float.NEGATIVE_INFINITY; + float posYExtent = Float.NEGATIVE_INFINITY; + float posZExtent = Float.NEGATIVE_INFINITY; for (int i = 0; i < 4; i++) { float x = vertices[i].x; @@ -81,20 +76,20 @@ public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] verti float z = vertices[i].z; // TODO: see if this is faster than using Math.min and Math.max - if (x < minX) { - minX = x; - } else if (x > maxX) { - maxX = x; + if (x < negXExtent) { + negXExtent = x; + } else if (x > posXExtent) { + posXExtent = x; } - if (y < minY) { - minY = y; - } else if (y > maxY) { - maxY = y; + if (y < negYExtent) { + negYExtent = y; + } else if (y > posYExtent) { + posYExtent = y; } - if (z < minZ) { - minZ = z; - } else if (z > maxZ) { - maxZ = z; + if (z < negZExtent) { + negZExtent = z; + } else if (z > posZExtent) { + posZExtent = z; } if (x != lastX || y != lastY || z != lastZ) { @@ -110,24 +105,19 @@ public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] verti } } - var invCount = 1.0f / uniqueQuads; - var center = new Vector3f(xSum * invCount, ySum * invCount, zSum * invCount); + var center = new Vector3f(xSum / uniqueQuads, ySum / uniqueQuads, zSum / uniqueQuads); if (facing != ModelQuadFacing.UNASSIGNED && this.unalignedDistances == null) { - minBounds.x = Math.min(minBounds.x, minX); - minBounds.y = Math.min(minBounds.y, minY); - minBounds.z = Math.min(minBounds.z, minZ); - maxBounds.x = Math.max(maxBounds.x, maxX); - maxBounds.y = Math.max(maxBounds.y, maxY); - maxBounds.z = Math.max(maxBounds.z, maxZ); + minBounds.x = Math.min(minBounds.x, negXExtent); + minBounds.y = Math.min(minBounds.y, negYExtent); + minBounds.z = Math.min(minBounds.z, negZExtent); + maxBounds.x = Math.max(maxBounds.x, posXExtent); + maxBounds.y = Math.max(maxBounds.y, posYExtent); + maxBounds.z = Math.max(maxBounds.z, posZExtent); } - extents[0] = maxX; - extents[1] = maxY; - extents[2] = maxZ; - extents[3] = minX; - extents[4] = minY; - extents[5] = minZ; + // POS_X, POS_Y, POS_Z, NEG_X, NEG_Y, NEG_Z + float[] extents = new float[] { posXExtent, posYExtent, posZExtent, negXExtent, negYExtent, negZExtent }; // TODO: does it make a difference if we compute the center as the average of // the unique vertices or as the center of the extents? (the latter would be From 3fa6bd7d17968005a409add04292000f816eaf9b Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 27 Oct 2023 20:12:43 +0200 Subject: [PATCH 105/256] de-epsilon geometry for translucent sorting --- .../chunk/compile/pipeline/FluidRenderer.java | 4 +-- .../render/chunk/gfni/ComplexSorting.java | 8 ++--- .../sodium/client/render/chunk/gfni/GFNI.java | 4 --- .../gfni/TranslucentGeometryCollector.java | 29 +++++++++++++++++-- 4 files changed, 32 insertions(+), 13 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java index 6bf9785042..07ad402e38 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java @@ -47,9 +47,9 @@ * and outside quads for each face of the block. */ public class FluidRenderer { - // TODO: allow this to be changed by vertex format + // TODO: allow this to be changed by vertex format, WARNING: make sure TranslucentGeometryCollector knows about EPSILON // TODO: move fluid rendering to a separate render pass and control glPolygonOffset and glDepthFunc to fix this properly - private static final float EPSILON = 0.001f; + public static final float EPSILON = 0.001f; private final BlockPos.Mutable scratchPos = new BlockPos.Mutable(); private final MutableFloat scratchHeight = new MutableFloat(0); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java index 632a15c8d6..9151ca0c9e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java @@ -120,9 +120,9 @@ private static boolean orthogonalQuadVisibleThrough(TQuad halfspace, TQuad other var otherSign = otherQuad.facing().getSign(); // A: test that the other quad has an extent within this quad's halfspace - return hSign * halfspace.extents()[hd] - QUERY_EPSILON > hSign * otherQuad.extents()[hdOpposite] + return hSign * halfspace.extents()[hd] > hSign * otherQuad.extents()[hdOpposite] // B: test that this quad is not fully within the other quad's halfspace - && !(otherSign * otherQuad.extents()[od] - QUERY_EPSILON >= otherSign * halfspace.extents()[od]); + && !(otherSign * otherQuad.extents()[od] >= otherSign * halfspace.extents()[od]); } /** @@ -331,15 +331,13 @@ public static boolean topoSortAlignedScanningCyclic(IntBuffer indexBuffer, TQuad return true; } - private static final float QUERY_EPSILON = 0.0011f; - private static boolean testSeparatorRange(Object2ReferenceOpenHashMap distancesByNormal, Vector3fc normal, float start, float end) { var distances = distancesByNormal.get(normal); if (distances == null) { return false; } - return Group.queryRange(distances, start - QUERY_EPSILON, end + QUERY_EPSILON); + return Group.queryRange(distances, start, end); } private static boolean visibilityWithSeparator(TQuad quadA, TQuad quadB, diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java index 37436d236d..7f1d6a9705 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java @@ -25,10 +25,6 @@ * may result in many sections suddenly needing sorting when the camera moves. * Maybe it's better to schedule them to be sorted gradually even if not * visible, if there are idle threads. - * - De-epsilon all the geometry by snapping to multiples of 0.005 or sth like - * that. Would simplify the ComplexSorting code so that it doesn't need to deal - * with the existence of error margins (epsilons in the trigger distances and - * the centers). * - Groups of quads that form convex shapes in a single plane without holes can * be sorted as one "quad". Their internal sorting can be arbitrary. Detecting * and grouping/ungrouping them might prove difficult. Finding all quad groups diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java index d09862e695..fdb0f96e21 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java @@ -9,6 +9,7 @@ import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions.SortBehavior; import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.FluidRenderer; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexEncoder; import net.minecraft.util.math.ChunkSectionPos; @@ -50,12 +51,26 @@ public TranslucentGeometryCollector(ChunkSectionPos sectionPos) { this.sectionPos = sectionPos; } + private static final float INV_QUANTIZE_EPSILON = 256f; + private static final float QUANTIZE_EPSILON = 1f / INV_QUANTIZE_EPSILON; + + static { + // ensure it fits with the fluid renderer epsilon and that it's a power-of-two fraction + var targetEpsilon = FluidRenderer.EPSILON * 2.1f; + if (QUANTIZE_EPSILON <= targetEpsilon && Integer.bitCount((int) INV_QUANTIZE_EPSILON) == 1) { + throw new RuntimeException("epsilon is invalid: " + QUANTIZE_EPSILON); + } + } + + private static float quantizeEpsilon(float value) { + return (float) Math.floor(value * INV_QUANTIZE_EPSILON + 0.5) * QUANTIZE_EPSILON; + } + public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] vertices, ModelQuadFacing facing) { float xSum = 0; float ySum = 0; float zSum = 0; - // keep track of distinct vertices to compute the center accurately for // degenerate quads float lastX = vertices[3].x; @@ -105,7 +120,17 @@ public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] verti } } - var center = new Vector3f(xSum / uniqueQuads, ySum / uniqueQuads, zSum / uniqueQuads); + var centerX = quantizeEpsilon(xSum / uniqueQuads); + var centerY = quantizeEpsilon(ySum / uniqueQuads); + var centerZ = quantizeEpsilon(zSum / uniqueQuads); + var center = new Vector3f(centerX, centerY, centerZ); + + negXExtent = quantizeEpsilon(negXExtent); + negYExtent = quantizeEpsilon(negYExtent); + negZExtent = quantizeEpsilon(negZExtent); + posXExtent = quantizeEpsilon(posXExtent); + posYExtent = quantizeEpsilon(posYExtent); + posZExtent = quantizeEpsilon(posZExtent); if (facing != ModelQuadFacing.UNASSIGNED && this.unalignedDistances == null) { minBounds.x = Math.min(minBounds.x, negXExtent); From efc122a4a94df5a421dac62ef2419caab01c86a1 Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 28 Oct 2023 04:01:14 +0200 Subject: [PATCH 106/256] don't bother removing null data from gfni --- .../mods/sodium/client/render/chunk/gfni/GFNI.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java index 7f1d6a9705..e5b45e9f9a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java @@ -352,7 +352,7 @@ private void triggerSectionDirect(ChunkSectionPos sectionPos) { public void applyTriggerChanges(DynamicData data, ChunkSectionPos pos, Vector3dc cameraPos) { if (data.turnGFNITriggerOff) { - disableGFNITriggering(data, pos.asLong()); + disableGFNITriggering(pos.asLong()); } if (data.turnDirectTriggerOn) { enableDirectTriggering(data, pos, cameraPos); @@ -390,7 +390,10 @@ private void disableDirectTriggering(TranslucentData data) { * @param sectionPos the section to remove */ public void removeSection(TranslucentData oldData, long sectionPos) { - disableGFNITriggering(oldData, sectionPos); + if (oldData == null) { + return; + } + disableGFNITriggering(sectionPos); disableDirectTriggering(oldData); decrementSortTypeCounter(oldData); } @@ -412,7 +415,7 @@ private void removeSectionFromList(NormalList normalList, long sectionPos) { } } - private void disableGFNITriggering(TranslucentData oldData, long sectionPos) { + private void disableGFNITriggering(long sectionPos) { for (var normalList : this.normalLists.values()) { removeSectionFromList(normalList, sectionPos); } From 96c0b19b35b3e95b75ae582bd51db2cf8ffacbd8 Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 28 Oct 2023 04:36:21 +0200 Subject: [PATCH 107/256] delete job task outputs if they're discarded in output filtering --- .../client/render/chunk/RenderSectionManager.java | 8 +++++++- .../client/render/chunk/compile/BuilderTaskOutput.java | 10 +++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index ba1f08b6e2..040389242b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -306,7 +306,7 @@ public void uploadChunks() { this.processChunkBuildResults(results); for (var result : results) { - result.deleteAfterUpload(); + result.deleteAfterUploadSafe(); } // TODO: only needed if the tasks actually changed the visibility (sort tasks @@ -361,7 +361,10 @@ private static List filterChunkBuildResults(ArrayList(); for (var output : outputs) { + // when outdated or duplicate outputs are thrown out, make sure to delete their + // buffers to avoid memory leaks if (output.render.isDisposed() || output.render.getLastUploadFrame() > output.submitTime) { + output.deleteFully(); continue; } @@ -370,6 +373,9 @@ private static List filterChunkBuildResults(ArrayList Date: Sat, 28 Oct 2023 04:41:50 +0200 Subject: [PATCH 108/256] better info message when section fails to sort --- .../client/render/chunk/gfni/StaticTopoAcyclicData.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java index 5c104be708..5c5ab5dd7e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java @@ -5,6 +5,10 @@ import me.jellysquid.mods.sodium.client.util.NativeBuffer; import net.minecraft.util.math.ChunkSectionPos; +/** + * TODO: figure out why it sometimes breaks and how to fix it (if the heuristic + * thinks there can't be a cycle, why does this not work?) + */ public class StaticTopoAcyclicData extends MixedDirectionData { StaticTopoAcyclicData(ChunkSectionPos sectionPos, NativeBuffer buffer, VertexRange range) { super(sectionPos, buffer, range); @@ -22,7 +26,7 @@ static StaticTopoAcyclicData fromMesh(BuiltSectionMeshParts translucentMesh, var indexBuffer = buffer.getDirectBuffer().asIntBuffer(); if (!ComplexSorting.topoSortDepthFirstCyclic(indexBuffer, quads, null, null)) { - System.out.println("Failed to sort topo static because there was a cycle"); + System.out.println("Failed to sort topo static because there was a cycle at " + sectionPos + "! Please report this alongside the seed and coordinates of the chunk."); } return new StaticTopoAcyclicData(sectionPos, buffer, range); From d75cb68a50ce457cc593ded37dd1641c184630e6 Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 28 Oct 2023 17:42:29 +0200 Subject: [PATCH 109/256] refactor chunk build outputs to fix flaw in logic, thanks to cortex for debugging this --- .../client/render/chunk/RenderSection.java | 3 ++ .../render/chunk/RenderSectionManager.java | 29 +++++++------- .../chunk/compile/ChunkBuildOutput.java | 40 +++++++++++++++---- .../render/chunk/compile/ChunkSortOutput.java | 31 ++++++-------- .../chunk/compile/OutputWithIndexData.java | 7 ++++ .../tasks/ChunkBuilderSortingTask.java | 16 +++++++- .../sodium/client/render/chunk/gfni/GFNI.java | 23 ++++++----- .../chunk/region/RenderRegionManager.java | 20 ++++++---- 8 files changed, 109 insertions(+), 60 deletions(-) create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/OutputWithIndexData.java diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java index 85cb4f38b4..9391bbba79 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java @@ -117,6 +117,9 @@ public TranslucentData getTranslucentData() { } public void setTranslucentData(TranslucentData translucentData) { + if (translucentData == null) { + throw new IllegalArgumentException("new translucentData cannot be null"); + } if (this.translucentData != null && this.translucentData != translucentData) { this.translucentData.delete(); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index 040389242b..d1ae017c45 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -22,7 +22,6 @@ import me.jellysquid.mods.sodium.client.render.chunk.compile.tasks.ChunkBuilderTask; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionInfo; import me.jellysquid.mods.sodium.client.render.chunk.gfni.CameraMovement; -import me.jellysquid.mods.sodium.client.render.chunk.gfni.DynamicData; import me.jellysquid.mods.sodium.client.render.chunk.gfni.GFNI; import me.jellysquid.mods.sodium.client.render.chunk.gfni.TranslucentData; import me.jellysquid.mods.sodium.client.render.chunk.lists.ChunkRenderList; @@ -211,6 +210,10 @@ public void onSectionRemoved(int x, int y, int z) { return; } + if (section.getTranslucentData() != null) { + this.gfni.removeSection(section.getTranslucentData(), sectionPos); + } + RenderRegion region = section.getRegion(); if (region != null) { @@ -222,8 +225,6 @@ public void onSectionRemoved(int x, int y, int z) { section.delete(); - this.gfni.removeSection(section.getTranslucentData(), sectionPos); - this.needsGraphUpdate = true; } @@ -326,13 +327,12 @@ private void processChunkBuildResults(ArrayList results) { this.updateSectionInfo(result.render, chunkBuildOutput.info); if (chunkBuildOutput.translucentData != null) { this.gfni.integrateTranslucentData(oldData, chunkBuildOutput.translucentData, this.cameraPosition); + + // a rebuild always generates new translucent data which means applyTriggerChanges isn't necessary + result.render.setTranslucentData(chunkBuildOutput.translucentData); } - } - if (result instanceof ChunkSortOutput chunkSortOutput && chunkSortOutput.translucentData != null) { - result.render.setTranslucentData(chunkSortOutput.translucentData); - if (chunkSortOutput.translucentData instanceof DynamicData dynamicData && dynamicData.hasTriggerChanges()) { - this.gfni.applyTriggerChanges(dynamicData, result.render.getPosition(), this.cameraPosition); - } + } else if (result instanceof ChunkSortOutput chunkSortOutput && chunkSortOutput.dynamicData.hasTriggerChanges()) { + this.gfni.applyTriggerChanges(chunkSortOutput.dynamicData, result.render.getPosition(), this.cameraPosition); } var job = result.render.getTaskCancellationToken(); @@ -346,8 +346,6 @@ private void processChunkBuildResults(ArrayList results) { } private void updateSectionInfo(RenderSection render, BuiltSectionInfo info) { - // TODO: make this work with translucent data and figure out a nice way to use - // BuilderTaskOutput render.setInfo(info); if (info == null || ArrayUtils.isEmpty(info.globalBlockEntities)) { @@ -417,10 +415,11 @@ private void submitSectionTasks(ChunkJobCollector collector, ChunkUpdateType typ section.setTaskCancellationToken(job); } else { - // TODO: why does this exist and where is this data read? is null translucent - // data ok? + // if the section is empty, doesn't exist or no sort task needs to be created + // for non-dynamic data, submit this null-task to set the built flag on the + // render section var result = ChunkJobResult.successfully(new ChunkBuildOutput( - section, frame, null, + section, frame, null, BuiltSectionInfo.EMPTY, Collections.emptyMap())); this.buildResults.add(result); @@ -443,7 +442,7 @@ private void submitSectionTasks(ChunkJobCollector collector, ChunkUpdateType typ } public ChunkBuilderSortingTask createSortTask(RenderSection render, int frame) { - return new ChunkBuilderSortingTask(render, frame, this.cameraPosition); + return ChunkBuilderSortingTask.createTask(render, frame, this.cameraPosition); } public void processGFNIMovement(CameraMovement movement) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java index 5f1bdf6ac2..690d56df6a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java @@ -3,25 +3,29 @@ import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; +import me.jellysquid.mods.sodium.client.render.chunk.gfni.PresentTranslucentData; import me.jellysquid.mods.sodium.client.render.chunk.gfni.TranslucentData; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionInfo; import java.util.Map; /** - * The result of a chunk rebuild task which contains any and all data that needs to be processed or uploaded on - * the main thread. If a task is cancelled after finishing its work and not before the result is processed, the result - * will instead be discarded. + * The result of a chunk rebuild task which contains any and all data that needs + * to be processed or uploaded on the main thread. If a task is cancelled after + * finishing its work and not before the result is processed, the result will + * instead be discarded. */ -public class ChunkBuildOutput extends ChunkSortOutput { +public class ChunkBuildOutput extends BuilderTaskOutput implements OutputWithIndexData { public final BuiltSectionInfo info; - + public final TranslucentData translucentData; public final Map meshes; - public ChunkBuildOutput(RenderSection render, int buildTime, TranslucentData translucentData, BuiltSectionInfo info, Map meshes) { - super(render, buildTime, translucentData); + public ChunkBuildOutput(RenderSection render, int buildTime, TranslucentData translucentData, BuiltSectionInfo info, + Map meshes) { + super(render, buildTime); this.info = info; + this.translucentData = translucentData; this.meshes = meshes; } @@ -29,11 +33,33 @@ public BuiltSectionMeshParts getMesh(TerrainRenderPass pass) { return this.meshes.get(pass); } + @Override + public PresentTranslucentData getTranslucentData() { + if (this.translucentData instanceof PresentTranslucentData present) { + return present; + } + return null; + } + @Override public void deleteAfterUpload() { super.deleteAfterUpload(); + + // delete translucent data if it's not persisted for dynamic sorting + if (this.translucentData != null && !this.translucentData.getSortType().needsTrigger) { + this.translucentData.delete(); + } + for (BuiltSectionMeshParts data : this.meshes.values()) { data.getVertexData().free(); } } + + @Override + public void deleteFully() { + super.deleteFully(); + if (this.translucentData != null) { + this.translucentData.delete(); + } + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java index 11bee64e26..a83265134b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java @@ -1,32 +1,25 @@ package me.jellysquid.mods.sodium.client.render.chunk.compile; import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; -import me.jellysquid.mods.sodium.client.render.chunk.gfni.TranslucentData; +import me.jellysquid.mods.sodium.client.render.chunk.gfni.DynamicData; +import me.jellysquid.mods.sodium.client.render.chunk.gfni.PresentTranslucentData; -public class ChunkSortOutput extends BuilderTaskOutput { - public final TranslucentData translucentData; +public class ChunkSortOutput extends BuilderTaskOutput implements OutputWithIndexData { + public final DynamicData dynamicData; - public ChunkSortOutput(RenderSection render, int buildTime, TranslucentData translucentData) { + public ChunkSortOutput(RenderSection render, int buildTime, DynamicData dynamicData) { super(render, buildTime); - this.translucentData = translucentData; + this.dynamicData = dynamicData; } @Override - public void deleteAfterUpload() { - super.deleteAfterUpload(); - - // delete translucent data if it's not persisted for dynamic sorting - if (this.translucentData != null && !this.translucentData.getSortType().needsTrigger) { - this.translucentData.delete(); - } + public PresentTranslucentData getTranslucentData() { + return this.dynamicData; } - @Override - public void deleteFully() { - super.deleteFully(); - if (this.translucentData != null) { - this.translucentData.delete(); - } - } + // doesn't implement deletion because the task doesn't allocate any new buffers. + // the buffers used belong to the section and are deleted when it is deleted. + // buffers created during section building are deleted at section deletion or + // when the rebuild is cancelled. } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/OutputWithIndexData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/OutputWithIndexData.java new file mode 100644 index 0000000000..0c456df40e --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/OutputWithIndexData.java @@ -0,0 +1,7 @@ +package me.jellysquid.mods.sodium.client.render.chunk.compile; + +import me.jellysquid.mods.sodium.client.render.chunk.gfni.PresentTranslucentData; + +public interface OutputWithIndexData { + PresentTranslucentData getTranslucentData(); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java index 5d447a557c..93a393474c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java @@ -5,16 +5,28 @@ import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildContext; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkSortOutput; +import me.jellysquid.mods.sodium.client.render.chunk.gfni.DynamicData; import me.jellysquid.mods.sodium.client.util.task.CancellationToken; public class ChunkBuilderSortingTask extends ChunkBuilderTask { - public ChunkBuilderSortingTask(RenderSection render, int frame, Vector3dc absoluteCameraPos) { + private final DynamicData dynamicData; + + public ChunkBuilderSortingTask(RenderSection render, int frame, Vector3dc absoluteCameraPos, + DynamicData dynamicData) { super(render, frame, absoluteCameraPos); + this.dynamicData = dynamicData; } @Override public ChunkSortOutput execute(ChunkBuildContext context, CancellationToken cancellationToken) { this.render.getTranslucentData().sortOnTrigger(this.cameraPos); - return new ChunkSortOutput(this.render, this.submitTime, this.render.getTranslucentData()); + return new ChunkSortOutput(this.render, this.submitTime, this.dynamicData); + } + + public static ChunkBuilderSortingTask createTask(RenderSection render, int frame, Vector3dc absoluteCameraPos) { + if (render.getTranslucentData() instanceof DynamicData dynamicData) { + return new ChunkBuilderSortingTask(render, frame, absoluteCameraPos, dynamicData); + } + return null; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java index e5b45e9f9a..c66830637f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java @@ -476,7 +476,6 @@ public void integrateTranslucentData(TranslucentData oldData, TranslucentData ne incrementSortTypeCounter(newData); // remove the section if the data doesn't need to trigger on face planes - // TODO: only do the heuristic and topo sort if the hashes are different? if (newData instanceof DynamicData dynamicData) { disableDirectTriggering(oldData); decrementSortTypeCounter(oldData); @@ -490,6 +489,10 @@ public void integrateTranslucentData(TranslucentData oldData, TranslucentData ne if (dynamicData.directTrigger) { enableDirectTriggering(dynamicData, newData.sectionPos, cameraPos); } + + // clear trigger changes on data change because the current state of trigger + // types was just set + dynamicData.clearTriggerChanges(); } else { removeSection(oldData, sectionPos); return; @@ -497,13 +500,15 @@ public void integrateTranslucentData(TranslucentData oldData, TranslucentData ne } public void addDebugStrings(List list) { - list.add("GFNI NL=" + this.normalLists.size() - + " TrS=" + this.triggeredSectionCount - + " TrN=" + this.triggeredNormalCount); - list.add("N=" + this.sortTypeCounters[SortType.NONE.ordinal()] - + " SNR=" + this.sortTypeCounters[SortType.STATIC_NORMAL_RELATIVE.ordinal()] - + " STA=" + this.sortTypeCounters[SortType.STATIC_TOPO_ACYCLIC.ordinal()] - + " DYN=" + this.sortTypeCounters[SortType.DYNAMIC_ALL.ordinal()] - + " (DIR=" + this.directTriggerSections.size() + ")"); + list.add(String.format("GFNI NL=%02d TrS=%03d TrN=%02d", + this.normalLists.size(), + this.triggeredSectionCount, + this.triggeredNormalCount)); + list.add(String.format("N=%05d SNR=%05d STA=%03d DYN=%04d (DIR=%04d)", + this.sortTypeCounters[SortType.NONE.ordinal()], + this.sortTypeCounters[SortType.STATIC_NORMAL_RELATIVE.ordinal()], + this.sortTypeCounters[SortType.STATIC_TOPO_ACYCLIC.ordinal()], + this.sortTypeCounters[SortType.DYNAMIC_ALL.ordinal()], + this.directTriggerSections.size())); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java index cb61df42d1..998d99e2ee 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java @@ -13,7 +13,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; import me.jellysquid.mods.sodium.client.render.chunk.compile.BuilderTaskOutput; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildOutput; -import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkSortOutput; +import me.jellysquid.mods.sodium.client.render.chunk.compile.OutputWithIndexData; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; import me.jellysquid.mods.sodium.client.render.chunk.gfni.PresentTranslucentData; import me.jellysquid.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses; @@ -64,6 +64,10 @@ private void uploadResults(CommandList commandList, RenderRegion region, Collect for (BuilderTaskOutput result : results) { int renderSectionIndex = result.render.getSectionIndex(); + if (result.render.isDisposed()) { + throw new IllegalStateException("Render section is disposed"); + } + if (result instanceof ChunkBuildOutput chunkBuildOutput) { for (TerrainRenderPass pass : DefaultTerrainRenderPasses.ALL) { var storage = region.getStorage(pass); @@ -81,21 +85,21 @@ private void uploadResults(CommandList commandList, RenderRegion region, Collect } } - if (result instanceof ChunkSortOutput chunkSortOutput) { + if (result instanceof OutputWithIndexData indexDataOutput) { var storage = region.getStorage(DefaultTerrainRenderPasses.TRANSLUCENT); if (storage != null) { storage.removeIndexData(renderSectionIndex); } - var translucentData = chunkSortOutput.translucentData; - if (translucentData != null && translucentData instanceof PresentTranslucentData presentTranslucentData) { + var indexData = indexDataOutput.getTranslucentData(); + if (indexData != null) { // TODO: debug this, seems to sometimes happen when flying around with spectator mode - // maybe related to setting all sections to angle triggering mode? - if (presentTranslucentData.buffer == null) { + // even happens without all sections as direct triggering, maybe the data on the render section is being replaced before it gets here? + if (indexData.buffer == null) { throw new IllegalStateException("Translucent data buffer is null"); } - indexUploads.add(new PendingSectionIndexBufferUpload(result.render, presentTranslucentData, - new PendingUpload(presentTranslucentData.buffer))); + indexUploads.add(new PendingSectionIndexBufferUpload(result.render, indexData, + new PendingUpload(indexData.buffer))); } } } From 4338afb4015d80104cd966ddc4f88023f2f06beb Mon Sep 17 00:00:00 2001 From: douira Date: Sun, 29 Oct 2023 02:28:25 +0100 Subject: [PATCH 110/256] fix issues with sort failures by falling back to dynamic --- .../render/chunk/gfni/AnyOrderData.java | 6 ++- .../client/render/chunk/gfni/DynamicData.java | 6 ++- .../chunk/gfni/StaticNormalRelativeData.java | 5 +-- .../chunk/gfni/StaticTopoAcyclicData.java | 15 +++---- .../gfni/TranslucentGeometryCollector.java | 41 +++++++------------ 5 files changed, 32 insertions(+), 41 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AnyOrderData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AnyOrderData.java index 1297e8c72e..498d6534e5 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AnyOrderData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AnyOrderData.java @@ -26,8 +26,10 @@ public SortType getSortType() { } static AnyOrderData fromMesh(BuiltSectionMeshParts translucentMesh, - TQuad[] quads, ChunkSectionPos sectionPos) { - var buffer = PresentTranslucentData.nativeBufferForQuads(quads); + TQuad[] quads, ChunkSectionPos sectionPos, NativeBuffer buffer) { + if (buffer == null) { + buffer = PresentTranslucentData.nativeBufferForQuads(quads); + } var indexBuffer = buffer.getDirectBuffer().asIntBuffer(); var counter = 0; var lastFacing = quads[0].facing(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java index fab86241bc..2ee684c719 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java @@ -151,7 +151,7 @@ void deleteCollector() { } static DynamicData fromMesh(BuiltSectionMeshParts translucentMesh, - Vector3fc cameraPos, TQuad[] quads, ChunkSectionPos sectionPos, TranslucentGeometryCollector collector) { + Vector3fc cameraPos, TQuad[] quads, ChunkSectionPos sectionPos, TranslucentGeometryCollector collector, NativeBuffer buffer) { // prepare accumulation groups for GFNI integration and copy var size = 0; if (collector.axisAlignedDistances != null) { @@ -179,7 +179,9 @@ static DynamicData fromMesh(BuiltSectionMeshParts translucentMesh, } VertexRange range = TranslucentData.getUnassignedVertexRange(translucentMesh); - var buffer = new NativeBuffer(TranslucentData.quadCountToIndexBytes(quads.length)); + if (buffer == null) { + buffer = PresentTranslucentData.nativeBufferForQuads(quads); + } var dynamicData = new DynamicData(sectionPos, buffer, range, quads, collector, distancesByNormal); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java index 124bd7ce00..31683bde86 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java @@ -46,8 +46,7 @@ private static StaticNormalRelativeData fromDoubleUnaligned(BuiltSectionMeshPart keys[i] = quad.center().dot(quad.normal()); } - var buffer = new NativeBuffer(TranslucentData.vertexCountToIndexBytes( - ranges[ModelQuadFacing.UNASSIGNED.ordinal()].vertexCount())); + var buffer = PresentTranslucentData.nativeBufferForQuads(quads); IntBuffer bufferBuilder = buffer.getDirectBuffer().asIntBuffer(); TranslucentData.writeQuadVertexIndexes(bufferBuilder, MergeSort.mergeSort(keys)); @@ -77,7 +76,7 @@ private static StaticNormalRelativeData fromAligned(BuiltSectionMeshParts transl } } - var buffer = new NativeBuffer(TranslucentData.quadCountToIndexBytes(quads.length)); + var buffer = PresentTranslucentData.nativeBufferForQuads(quads); IntBuffer bufferBuilder = buffer.getDirectBuffer().asIntBuffer(); // in this case there can only be up to one unaligned normal. diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java index 5c5ab5dd7e..e4692f6eea 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java @@ -5,11 +5,9 @@ import me.jellysquid.mods.sodium.client.util.NativeBuffer; import net.minecraft.util.math.ChunkSectionPos; -/** - * TODO: figure out why it sometimes breaks and how to fix it (if the heuristic - * thinks there can't be a cycle, why does this not work?) - */ public class StaticTopoAcyclicData extends MixedDirectionData { + private static final int MAX_STATIC_TOPO_SORT_QUADS = 1000; + StaticTopoAcyclicData(ChunkSectionPos sectionPos, NativeBuffer buffer, VertexRange range) { super(sectionPos, buffer, range); } @@ -20,13 +18,16 @@ public SortType getSortType() { } static StaticTopoAcyclicData fromMesh(BuiltSectionMeshParts translucentMesh, - TQuad[] quads, ChunkSectionPos sectionPos) { + TQuad[] quads, ChunkSectionPos sectionPos, NativeBuffer buffer) { + if (quads.length > MAX_STATIC_TOPO_SORT_QUADS) { + return null; + } + VertexRange range = TranslucentData.getUnassignedVertexRange(translucentMesh); - var buffer = new NativeBuffer(TranslucentData.vertexCountToIndexBytes(range.vertexCount())); var indexBuffer = buffer.getDirectBuffer().asIntBuffer(); if (!ComplexSorting.topoSortDepthFirstCyclic(indexBuffer, quads, null, null)) { - System.out.println("Failed to sort topo static because there was a cycle at " + sectionPos + "! Please report this alongside the seed and coordinates of the chunk."); + return null; } return new StaticTopoAcyclicData(sectionPos, buffer, range); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java index fdb0f96e21..721200b876 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java @@ -12,6 +12,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.FluidRenderer; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexEncoder; +import me.jellysquid.mods.sodium.client.util.NativeBuffer; import net.minecraft.util.math.ChunkSectionPos; /** @@ -39,8 +40,6 @@ public class TranslucentGeometryCollector { private Vector3f minBounds = new Vector3f(16, 16, 16); private Vector3f maxBounds = new Vector3f(0, 0, 0); - private int unalignedQuadCount = 0; - @SuppressWarnings("unchecked") private ReferenceArrayList[] quadLists = new ReferenceArrayList[ModelQuadFacing.COUNT]; private TQuad[] quads; @@ -55,7 +54,8 @@ public TranslucentGeometryCollector(ChunkSectionPos sectionPos) { private static final float QUANTIZE_EPSILON = 1f / INV_QUANTIZE_EPSILON; static { - // ensure it fits with the fluid renderer epsilon and that it's a power-of-two fraction + // ensure it fits with the fluid renderer epsilon and that it's a power-of-two + // fraction var targetEpsilon = FluidRenderer.EPSILON * 2.1f; if (QUANTIZE_EPSILON <= targetEpsilon && Integer.bitCount((int) INV_QUANTIZE_EPSILON) == 1) { throw new RuntimeException("epsilon is invalid: " + QUANTIZE_EPSILON); @@ -182,7 +182,6 @@ public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] verti } quadList.add(new TQuad(facing, accGroup.normal, center, extents)); - this.unalignedQuadCount++; } else { if (this.axisAlignedDistances == null) { this.axisAlignedDistances = new AccumulationGroup[ModelQuadFacing.DIRECTIONS]; @@ -251,15 +250,8 @@ private static SortType filterSortType(SortType sortType) { * normal-relative distance. The ordering between the two normals is irrelevant * as they can't be seen through each other anyways. * - * E: If there are only three axis-aligned normals or only two normals if there - * is at least one unaligned normal, a static topological sort of the - * see-through graph is enough. The sort is performed on the see-through graph - * consisting of quads as nodes and edges between two quads if the one can be - * seen through the other. The see-through condition is not checked transitively - * which avoids needing to do complex projections of quads onto each other. A - * static sort exists if this graph is acyclic. In the aforementioned cases, the - * graph is known to be acyclic. It can also be acyclic if there are more - * normals, but this would require a search of the graph for cycles. + * E: If there are only three normals a static topological sort of the + * see-through graph is often possible. * * More heuristics can be performed here to conservatively determine if this * section could possibly have more than one translucent sort order. @@ -324,11 +316,6 @@ private SortType sortTypeHeuristic() { if (twoOpposingNormals || Integer.bitCount(this.alignedNormalBitmap) == 1) { return SortType.STATIC_NORMAL_RELATIVE; } - - // special case E - if (Integer.bitCount(this.alignedNormalBitmap) <= 3) { - return SortType.STATIC_TOPO_ACYCLIC; - } } else if (this.alignedNormalBitmap == 0) { if (this.unalignedDistances.size() == 1) { // special case D but for one unaligned normal @@ -348,7 +335,7 @@ private SortType sortTypeHeuristic() { // special case E if (Integer.bitCount(this.alignedNormalBitmap) - + (this.unalignedDistances == null ? 0 : this.unalignedDistances.size()) <= 2) { + + (this.unalignedDistances == null ? 0 : this.unalignedDistances.size()) <= 3) { return SortType.STATIC_TOPO_ACYCLIC; } @@ -385,7 +372,7 @@ public TranslucentData getTranslucentData(BuiltSectionMeshParts translucentMesh, } if (this.sortType == SortType.NONE) { - return AnyOrderData.fromMesh(translucentMesh, quads, sectionPos); + return AnyOrderData.fromMesh(translucentMesh, quads, sectionPos, null); } if (this.sortType == SortType.STATIC_NORMAL_RELATIVE) { @@ -394,24 +381,24 @@ public TranslucentData getTranslucentData(BuiltSectionMeshParts translucentMesh, // from this point on we know the estimated sort type requires direction mixing // (no backface culling) and all vertices are in the UNASSIGNED direction. + NativeBuffer buffer = PresentTranslucentData.nativeBufferForQuads(this.quads); if (this.sortType == SortType.STATIC_TOPO_ACYCLIC) { - if (this.unalignedQuadCount > 0) { - // TODO: implement topo sort with unaligned quads - this.sortType = SortType.DYNAMIC_ALL; - } else { - return StaticTopoAcyclicData.fromMesh(translucentMesh, this.quads, sectionPos); + var result = StaticTopoAcyclicData.fromMesh(translucentMesh, this.quads, sectionPos, buffer); + if (result != null) { + return result; } + this.sortType = SortType.DYNAMIC_ALL; } // filter the sort type with the user setting and re-evaluate this.sortType = filterSortType(this.sortType); if (this.sortType == SortType.NONE) { - return AnyOrderData.fromMesh(translucentMesh, quads, sectionPos); + return AnyOrderData.fromMesh(translucentMesh, quads, sectionPos, buffer); } if (this.sortType == SortType.DYNAMIC_ALL) { - return DynamicData.fromMesh(translucentMesh, cameraPos, quads, sectionPos, this); + return DynamicData.fromMesh(translucentMesh, cameraPos, quads, sectionPos, this, buffer); } throw new IllegalStateException("Unknown sort type: " + this.sortType); From ab21da01c715016f4e551d4304eac6facef965a7 Mon Sep 17 00:00:00 2001 From: douira Date: Sun, 5 Nov 2023 00:16:42 +0100 Subject: [PATCH 111/256] more consistent gfni statistics formatting --- .../jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java index c66830637f..c4af5a19ec 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java @@ -504,7 +504,7 @@ public void addDebugStrings(List list) { this.normalLists.size(), this.triggeredSectionCount, this.triggeredNormalCount)); - list.add(String.format("N=%05d SNR=%05d STA=%03d DYN=%04d (DIR=%04d)", + list.add(String.format("N=%05d SNR=%05d STA=%04d DYN=%04d (DIR=%04d)", this.sortTypeCounters[SortType.NONE.ordinal()], this.sortTypeCounters[SortType.STATIC_NORMAL_RELATIVE.ordinal()], this.sortTypeCounters[SortType.STATIC_TOPO_ACYCLIC.ordinal()], From b29284138c147d39ef8cc16e97073a0cec7d5131 Mon Sep 17 00:00:00 2001 From: douira Date: Sun, 5 Nov 2023 00:19:35 +0100 Subject: [PATCH 112/256] fix typo in contributing docs --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5122efbd4b..dd9166d7b5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,7 +11,7 @@ with some minor changes, as described below. - If you are using more than three levels of indentation, you should likely consider restructuring your code. - Branches which are only exceptionally or very rarely taken should remain concise. When this is not possible, prefer breaking out to a new method (where it makes sense) as this helps the compiler better optimize the code. -- Use `this` to qualify member and field access, as it avoids some ambiguity in certain contexts. +- Use `this` to qualify method and field access, as it avoids some ambiguity in certain contexts. We also provide these code styles as [EditorConfig](https://editorconfig.org/) files, which most Java IDEs will automatically detect and make use of. @@ -51,4 +51,4 @@ style guidelines. If you're adding new Mixin patches to the project, please ensure that you have created appropriate entries to disable them in the config file. Mixins should always be self-contained and grouped into "patch sets" which are easy to isolate, -and where that is not possible, they should be placed into the "core" package. \ No newline at end of file +and where that is not possible, they should be placed into the "core" package. From f7279a0bdc151652fe55b9ebdc3c422cc68960f6 Mon Sep 17 00:00:00 2001 From: douira Date: Sun, 5 Nov 2023 00:21:48 +0100 Subject: [PATCH 113/256] enable separate index and vertex data handling in SectionRenderDataStorage. reduces amount of generated and uploaded index data when sections are rebuilt without relevant changes to translucent geometry. --- .../tasks/ChunkBuilderMeshingTask.java | 3 +- .../chunk/data/SectionRenderDataStorage.java | 27 +++++--- .../render/chunk/gfni/AccumulationGroup.java | 2 +- .../client/render/chunk/gfni/DynamicData.java | 5 +- .../sodium/client/render/chunk/gfni/GFNI.java | 4 ++ .../chunk/gfni/PresentTranslucentData.java | 34 +++++++++- .../client/render/chunk/gfni/TQuad.java | 41 ++++++++++++ .../render/chunk/gfni/TranslucentData.java | 9 ++- .../gfni/TranslucentGeometryCollector.java | 62 +++++++++++++++++-- .../render/chunk/region/RenderRegion.java | 2 +- .../chunk/region/RenderRegionManager.java | 32 ++++++---- 11 files changed, 186 insertions(+), 35 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java index b1d514f5c0..ea4ae632bf 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java @@ -168,7 +168,8 @@ public ChunkBuildOutput execute(ChunkBuildContext buildContext, CancellationToke TranslucentData translucentData = null; if (collector != null) { - translucentData = collector.getTranslucentData(meshes.get(DefaultTerrainRenderPasses.TRANSLUCENT), cameraPos); + translucentData = collector.getTranslucentData( + render.getTranslucentData(), meshes.get(DefaultTerrainRenderPasses.TRANSLUCENT), cameraPos); } renderData.setOcclusionData(occluder.build()); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java index 2c2d94225b..98cf465a7b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java @@ -22,6 +22,9 @@ * that of the vertex data except for the vertex/index scaling of two thirds, * only an offset to the index data within the index data buffer arena is * stored. + * + * Index and vertex data storage can be managed separately since they may be + * updated independently of each other (in both directions). */ public class SectionRenderDataStorage { private final GlBufferSegment[] allocations; @@ -71,9 +74,6 @@ public void setVertexData(int localSectionIndex, } SectionRenderDataUnsafe.setSliceMask(pMeshData, sliceMask); - - // reset index offset to make sure it never renders with wrong index data - SectionRenderDataUnsafe.setIndexOffset(pMeshData, 0); } public void setIndexData(int localSectionIndex, GlBufferSegment allocation) { @@ -94,7 +94,18 @@ public void setIndexData(int localSectionIndex, GlBufferSegment allocation) { SectionRenderDataUnsafe.setIndexOffset(pMeshData, allocation.getOffset()); } + public void removeData(int localSectionIndex) { + this.removeVertexData(localSectionIndex, false); + if (this.storesIndices) { + removeIndexData(localSectionIndex); + } + } + public void removeVertexData(int localSectionIndex) { + this.removeVertexData(localSectionIndex, true); + } + + private void removeVertexData(int localSectionIndex, boolean retainIndexData) { if (this.allocations[localSectionIndex] == null) { return; } @@ -102,12 +113,10 @@ public void removeVertexData(int localSectionIndex) { this.allocations[localSectionIndex].delete(); this.allocations[localSectionIndex] = null; - // also clear index allocation - if (this.storesIndices) { - removeIndexData(localSectionIndex); - } - - SectionRenderDataUnsafe.clear(this.getDataPointer(localSectionIndex)); + var pMeshData = this.getDataPointer(localSectionIndex); + var indexOffset = SectionRenderDataUnsafe.getIndexOffset(pMeshData); + SectionRenderDataUnsafe.clear(pMeshData); + SectionRenderDataUnsafe.setIndexOffset(pMeshData, indexOffset); } public void removeIndexData(int localSectionIndex) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AccumulationGroup.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AccumulationGroup.java index 7d30148650..34708f6bce 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AccumulationGroup.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AccumulationGroup.java @@ -47,7 +47,7 @@ void prepareIntegration() { this.facePlaneDistances[i++] = relDistance; long distanceBits = Double.doubleToLongBits(relDistance); - this.relDistanceHash ^= distanceBits; + this.relDistanceHash ^= this.relDistanceHash * 31L + distanceBits; } // sort the array ascending diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java index 2ee684c719..97fe710160 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java @@ -82,8 +82,11 @@ private static int getAttemptsForTime(long ns) { } private void sort(Vector3fc cameraPos, boolean isAngleTrigger) { + // mark as not being reused to ensure the updated buffer is actually uploaded + this.unsetReuseUploadedData(); + // uses a topo sort or a distance sort depending on what is enabled - IntBuffer indexBuffer = this.buffer.getDirectBuffer().asIntBuffer(); + IntBuffer indexBuffer = this.getBuffer().getDirectBuffer().asIntBuffer(); if (this.quads.length > MAX_TOPO_SORT_QUADS) { turnGFNITriggerOff(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java index c4af5a19ec..c0fe8925db 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java @@ -471,6 +471,10 @@ private void initiallyEnableGFNITriggering(DynamicData data, long sectionPos) { * determined */ public void integrateTranslucentData(TranslucentData oldData, TranslucentData newData, Vector3dc cameraPos) { + if (oldData == newData) { + return; + } + long sectionPos = newData.sectionPos.asLong(); incrementSortTypeCounter(newData); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/PresentTranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/PresentTranslucentData.java index 1343f47b20..e0151df08c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/PresentTranslucentData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/PresentTranslucentData.java @@ -8,11 +8,15 @@ * Super class for translucent data that contains an actual buffer. */ public abstract class PresentTranslucentData extends TranslucentData { - public NativeBuffer buffer; + private NativeBuffer buffer; + private boolean reuseUploadedData; + private int quadHash; + private int length; PresentTranslucentData(ChunkSectionPos sectionPos, NativeBuffer buffer) { super(sectionPos); this.buffer = buffer; + this.length = TranslucentData.indexBytesToQuadCount(buffer.getLength()); } public abstract VertexRange[] getVertexRanges(); @@ -26,8 +30,32 @@ public void delete() { } } - public int getQuadLength() { - return this.buffer.getLength() / BYTES_PER_INDEX / VERTICES_PER_QUAD; + void setQuadHash(int hash) { + this.quadHash = hash; + } + + int getQuadHash() { + return this.quadHash; + } + + int getLength() { + return this.length; + } + + public NativeBuffer getBuffer() { + return this.buffer; + } + + public boolean isReusingUploadedData() { + return this.reuseUploadedData; + } + + void setReuseUploadedData() { + this.reuseUploadedData = true; + } + + void unsetReuseUploadedData() { + this.reuseUploadedData = false; } static NativeBuffer nativeBufferForQuads(TQuad[] quads) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TQuad.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TQuad.java index 55d8506574..e2c03a7953 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TQuad.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TQuad.java @@ -1,5 +1,7 @@ package me.jellysquid.mods.sodium.client.render.chunk.gfni; +import java.util.Arrays; + import org.joml.Vector3f; import org.joml.Vector3fc; @@ -8,6 +10,45 @@ /** * Represents a quad for the purposes of translucency sorting. Called TQuad to * avoid confusion with other quad classes. + * + * @implNote Autogenerated hashcode and equals methods to ensure the arrays are + * correctly compared.. */ record TQuad(ModelQuadFacing facing, Vector3fc normal, Vector3f center, float[] extents) { + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((facing == null) ? 0 : facing.hashCode()); + result = prime * result + ((normal == null) ? 0 : normal.hashCode()); + result = prime * result + ((center == null) ? 0 : center.hashCode()); + result = prime * result + Arrays.hashCode(extents); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + TQuad other = (TQuad) obj; + if (facing != other.facing) + return false; + if (normal == null) { + if (other.normal != null) + return false; + } else if (!normal.equals(other.normal)) + return false; + if (center == null) { + if (other.center != null) + return false; + } else if (!center.equals(other.center)) + return false; + if (!Arrays.equals(extents, other.extents)) + return false; + return true; + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java index c8198c0b19..7b424fb4dd 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java @@ -17,6 +17,7 @@ public abstract class TranslucentData { public static final int INDICES_PER_QUAD = 6; public static final int VERTICES_PER_QUAD = 4; public static final int BYTES_PER_INDEX = 4; + public static final int BYTES_PER_QUAD = INDICES_PER_QUAD * BYTES_PER_INDEX; public final ChunkSectionPos sectionPos; @@ -45,11 +46,15 @@ public void prepareTrigger(boolean isAngleTrigger) { static int vertexCountToIndexBytes(int vertexCount) { // convert vertex count to quads, and then to indices, and then to bytes - return vertexCount / VERTICES_PER_QUAD * INDICES_PER_QUAD * BYTES_PER_INDEX; + return vertexCount / VERTICES_PER_QUAD * BYTES_PER_QUAD; } static int quadCountToIndexBytes(int quadCount) { - return quadCount * INDICES_PER_QUAD * BYTES_PER_INDEX; + return quadCount * BYTES_PER_QUAD; + } + + static int indexBytesToQuadCount(int indexBytes) { + return indexBytes / BYTES_PER_QUAD; } static void putMappedQuadVertexIndexes(IntBuffer intBuffer, int quadIndex, int[] indexMapping) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java index 721200b876..5b5aef2aeb 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java @@ -14,6 +14,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexEncoder; import me.jellysquid.mods.sodium.client.util.NativeBuffer; import net.minecraft.util.math.ChunkSectionPos; +import java.util.Arrays; /** * The translucent geometry collector collects the data from the renderers and @@ -46,6 +47,9 @@ public class TranslucentGeometryCollector { private SortType sortType; + private boolean quadHashPresent = false; + private int quadHash = 0; + public TranslucentGeometryCollector(ChunkSectionPos sectionPos) { this.sectionPos = sectionPos; } @@ -365,12 +369,7 @@ public SortType finishRendering() { return this.sortType; } - public TranslucentData getTranslucentData(BuiltSectionMeshParts translucentMesh, Vector3fc cameraPos) { - // means there is no translucent geometry - if (translucentMesh == null) { - return new NoData(sectionPos); - } - + private TranslucentData getTranslucentDataNew(BuiltSectionMeshParts translucentMesh, Vector3fc cameraPos) { if (this.sortType == SortType.NONE) { return AnyOrderData.fromMesh(translucentMesh, quads, sectionPos, null); } @@ -404,6 +403,57 @@ public TranslucentData getTranslucentData(BuiltSectionMeshParts translucentMesh, throw new IllegalStateException("Unknown sort type: " + this.sortType); } + private int getQuadHash(TQuad[] quads) { + if (this.quadHashPresent) { + return this.quadHash; + } + + for (TQuad quad : quads) { + this.quadHash ^= this.quadHash * 31 + quad.hashCode(); + } + return this.quadHash; + } + + public TranslucentData getTranslucentData( + TranslucentData oldData, BuiltSectionMeshParts translucentMesh, Vector3fc cameraPos) { + // means there is no translucent geometry + if (translucentMesh == null) { + return new NoData(sectionPos); + } + + // re-use the original translucent data if it's the same. This reduces the + // amount of generated and uploaded index data when sections are rebuilt without + // relevant changes to translucent geometry. Rebuilds happen when any part of + // the section changes, including the here irrelevant cases of changes to opaque + // geometry or light levels. + if (oldData != null) { + // for the NONE sort type the ranges need to be the same, the actual geometry + // doesn't matter + if (this.sortType == SortType.NONE && oldData instanceof AnyOrderData oldAnyData + && oldAnyData.getLength() == this.quads.length + && Arrays.equals(oldAnyData.getVertexRanges(), translucentMesh.getVertexRanges())) { + oldAnyData.setReuseUploadedData(); + return oldAnyData; + } + + // for the other sort types the geometry needs to be the same (checked with + // length and hash) + if (oldData instanceof PresentTranslucentData oldPresentData) { + if (oldPresentData.getLength() == this.quads.length + && oldPresentData.getQuadHash() == getQuadHash(this.quads)) { + oldPresentData.setReuseUploadedData(); + return oldPresentData; + } + } + } + + var newData = getTranslucentDataNew(translucentMesh, cameraPos); + if (newData instanceof PresentTranslucentData presentData) { + presentData.setQuadHash(getQuadHash(this.quads)); + } + return newData; + } + AccumulationGroup getGroupForNormal(NormalList normalList) { int collectorKey = normalList.getCollectorKey(); if (collectorKey < 0xFF) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java index f2776bdc93..ebeaf039bb 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java @@ -164,7 +164,7 @@ public void removeSection(RenderSection section) { } for (var storage : this.sectionRenderData.values()) { - storage.removeVertexData(sectionIndex); + storage.removeData(sectionIndex); } this.sections[sectionIndex] = null; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java index 998d99e2ee..b86680b28d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java @@ -86,20 +86,30 @@ private void uploadResults(CommandList commandList, RenderRegion region, Collect } if (result instanceof OutputWithIndexData indexDataOutput) { - var storage = region.getStorage(DefaultTerrainRenderPasses.TRANSLUCENT); - if (storage != null) { - storage.removeIndexData(renderSectionIndex); - } - var indexData = indexDataOutput.getTranslucentData(); + boolean retainIndexData = false; if (indexData != null) { - // TODO: debug this, seems to sometimes happen when flying around with spectator mode - // even happens without all sections as direct triggering, maybe the data on the render section is being replaced before it gets here? - if (indexData.buffer == null) { - throw new IllegalStateException("Translucent data buffer is null"); + if (indexData.isReusingUploadedData()) { + retainIndexData = true; + } else { + var buffer = indexData.getBuffer(); + + // TODO: sometimes the buffer is null even when reuse isn't happening. maybe the data on the + // render section is being replaced before it gets here? + if (buffer == null) { + throw new IllegalStateException("Translucent data buffer is null"); + } + + indexUploads.add(new PendingSectionIndexBufferUpload(result.render, indexData, + new PendingUpload(buffer))); + } + } + + if (!retainIndexData) { + var storage = region.getStorage(DefaultTerrainRenderPasses.TRANSLUCENT); + if (storage != null) { + storage.removeIndexData(renderSectionIndex); } - indexUploads.add(new PendingSectionIndexBufferUpload(result.render, indexData, - new PendingUpload(indexData.buffer))); } } } From cc504961c5776c479098a6e6d47a7586d35cbf99 Mon Sep 17 00:00:00 2001 From: douira Date: Sun, 5 Nov 2023 00:41:21 +0100 Subject: [PATCH 114/256] fix the static topo sort heuristic to always attempt to sort small amounts of geometry depending on how many unique normals it has --- .../gfni/TranslucentGeometryCollector.java | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java index 5b5aef2aeb..620900de31 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java @@ -223,6 +223,13 @@ private static SortType filterSortType(SortType sortType) { return sortType; } + /** + * Array of how many quads a section can have with a given number of unique + * normals so that a static topo sort is attempted on it. -1 means the value is + * unused and doesn't make sense to give. + */ + private static int[] STATIC_TOPO_SORT_ATTEMPT_LIMITS = new int[] { -1, -1, 250, 100, 50, 30 }; + /** * Determines the sort type for the collected geometry from the section. It * determines a sort type, which is either no sorting, a static sort or a @@ -254,9 +261,6 @@ private static SortType filterSortType(SortType sortType) { * normal-relative distance. The ordering between the two normals is irrelevant * as they can't be seen through each other anyways. * - * E: If there are only three normals a static topological sort of the - * see-through graph is often possible. - * * More heuristics can be performed here to conservatively determine if this * section could possibly have more than one translucent sort order. * @@ -337,9 +341,12 @@ private SortType sortTypeHeuristic() { } } - // special case E - if (Integer.bitCount(this.alignedNormalBitmap) - + (this.unalignedDistances == null ? 0 : this.unalignedDistances.size()) <= 3) { + // use the given set of quad count limits to determine if a static topo sort + // should be attempted + var uniqueNormals = Integer.bitCount(this.alignedNormalBitmap) + + (this.unalignedDistances == null ? 0 : this.unalignedDistances.size()); + uniqueNormals = Math.max(Math.min(uniqueNormals, STATIC_TOPO_SORT_ATTEMPT_LIMITS.length - 1), 2); + if (this.quads.length <= STATIC_TOPO_SORT_ATTEMPT_LIMITS[uniqueNormals]) { return SortType.STATIC_TOPO_ACYCLIC; } From a5475c774d67dc21b52c0424b5a5972187d40f7c Mon Sep 17 00:00:00 2001 From: douira Date: Sun, 5 Nov 2023 04:09:22 +0100 Subject: [PATCH 115/256] use this. for instance method access --- .../client/model/quad/ModelQuadView.java | 2 +- .../chunk/compile/BuilderTaskOutput.java | 4 +- .../chunk/data/SectionRenderDataStorage.java | 2 +- .../client/render/chunk/gfni/DynamicData.java | 14 +++--- .../sodium/client/render/chunk/gfni/GFNI.java | 49 ++++++++++--------- .../client/render/chunk/gfni/Group.java | 2 +- .../client/render/chunk/gfni/NormalList.java | 8 +-- 7 files changed, 41 insertions(+), 40 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java index e30f5313de..8d4fa62e37 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java @@ -138,7 +138,7 @@ default int calculateNormals(boolean calculateUnitNormal) { // quantize the coordinates on the surface of the cube. // in each axis the number of values is 2 * QUANTIZATION_FACTOR + 1. // the total number of normals is the number of points on that cube's surface. - setGFNINormal( + this.setGFNINormal( (int) (normX * GFNI.QUANTIZATION_FACTOR), (int) (normY * GFNI.QUANTIZATION_FACTOR), (int) (normZ * GFNI.QUANTIZATION_FACTOR)); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/BuilderTaskOutput.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/BuilderTaskOutput.java index 25750ae384..02cb4a1236 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/BuilderTaskOutput.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/BuilderTaskOutput.java @@ -14,12 +14,12 @@ public BuilderTaskOutput(RenderSection render, int buildTime) { public void deleteFully() { this.fullyDeleted = true; - deleteAfterUpload(); + this.deleteAfterUpload(); } public void deleteAfterUploadSafe() { if (!this.fullyDeleted) { - deleteAfterUpload(); + this.deleteAfterUpload(); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java index 98cf465a7b..9134d7e28a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java @@ -97,7 +97,7 @@ public void setIndexData(int localSectionIndex, GlBufferSegment allocation) { public void removeData(int localSectionIndex) { this.removeVertexData(localSectionIndex, false); if (this.storesIndices) { - removeIndexData(localSectionIndex); + this.removeIndexData(localSectionIndex); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java index 97fe710160..ba4b999920 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java @@ -89,8 +89,8 @@ private void sort(Vector3fc cameraPos, boolean isAngleTrigger) { IntBuffer indexBuffer = this.getBuffer().getDirectBuffer().asIntBuffer(); if (this.quads.length > MAX_TOPO_SORT_QUADS) { - turnGFNITriggerOff(); - turnDirectTriggerOn(); + this.turnGFNITriggerOff(); + this.turnDirectTriggerOn(); } if (this.GFNITrigger && !isAngleTrigger) { @@ -106,13 +106,13 @@ private void sort(Vector3fc cameraPos, boolean isAngleTrigger) { if (sortTime > (this.consecutiveTopoSortFailures > 0 ? MAX_FAILING_TOPO_SORT_TIME_NS : MAX_TOPO_SORT_TIME_NS)) { - turnGFNITriggerOff(); - turnDirectTriggerOn(); + this.turnGFNITriggerOff(); + this.turnDirectTriggerOn(); } if (result) { // disable distance sorting because topo sort seems to be possible. - turnDirectTriggerOff(); + this.turnDirectTriggerOff(); this.consecutiveTopoSortFailures = 0; return; } else { @@ -123,9 +123,9 @@ private void sort(Vector3fc cameraPos, boolean isAngleTrigger) { // sort success from a different angle. this.consecutiveTopoSortFailures++; if (this.consecutiveTopoSortFailures >= getAttemptsForTime(sortTime)) { - turnGFNITriggerOff(); + this.turnGFNITriggerOff(); } - turnDirectTriggerOn(); + this.turnDirectTriggerOn(); } } if (this.directTrigger) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java index c0fe8925db..4626016e3d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java @@ -137,8 +137,8 @@ public void triggerSections(BiConsumer triggerSectionCallback, Ca triggeredNormals.clear(); this.triggerSectionCallback = triggerSectionCallback; - processGFNITriggers(movement); - processDirectTriggers(movement); + this.processGFNITriggers(movement); + this.processDirectTriggers(movement); var newTriggeredSectionsCount = this.triggeredSections.size(); var newTriggeredNormalCount = this.triggeredNormals.size(); @@ -279,7 +279,7 @@ private void processDirectTriggers(CameraMovement movement) { remainingAngle -= Math.acos(angleCos); } - insertDirectAngleTrigger(data, camera, remainingAngle); + this.insertDirectAngleTrigger(data, camera, remainingAngle); } else { double remainingDistance = DIRECT_TRIGGER_DISTANCE; double lastTriggerCurrentCameraDistSquared = data.triggerCameraPos.distanceSquared(camera); @@ -291,7 +291,7 @@ private void processDirectTriggers(CameraMovement movement) { remainingDistance -= Math.sqrt(lastTriggerCurrentCameraDistSquared); } - insertDirectDistanceTrigger(data, camera, remainingDistance); + this.insertDirectDistanceTrigger(data, camera, remainingDistance); } } } @@ -299,13 +299,14 @@ private void processDirectTriggers(CameraMovement movement) { private void insertDirectAngleTrigger(DirectTriggerData data, Vector3dc cameraPos, double remainingAngle) { double triggerCameraSectionCenterDist = data.getSectionCenterTriggerCameraDist(); double centerMinDistance = Math.tan(remainingAngle) * (triggerCameraSectionCenterDist - SECTION_CENTER_DIST); - insertJitteredTrigger(this.accumulatedDistance + centerMinDistance, data); + this.insertJitteredTrigger(this.accumulatedDistance + centerMinDistance, data); } private void insertDirectDistanceTrigger(DirectTriggerData data, Vector3dc cameraPos, double remainingDistance) { - insertJitteredTrigger(this.accumulatedDistance + remainingDistance, data); + this.insertJitteredTrigger(this.accumulatedDistance + remainingDistance, data); } + // TODO: instead of jittering use Tree where object is either a list or an individual record? // jitters the double values to never overwrite the same key. abuses that // doubles have more precision than we need to make them a kind of hash table private double lastJittered = -1; @@ -352,13 +353,13 @@ private void triggerSectionDirect(ChunkSectionPos sectionPos) { public void applyTriggerChanges(DynamicData data, ChunkSectionPos pos, Vector3dc cameraPos) { if (data.turnGFNITriggerOff) { - disableGFNITriggering(pos.asLong()); + this.disableGFNITriggering(pos.asLong()); } if (data.turnDirectTriggerOn) { - enableDirectTriggering(data, pos, cameraPos); + this.enableDirectTriggering(data, pos, cameraPos); } if (data.turnDirectTriggerOff) { - disableDirectTriggering(data); + this.disableDirectTriggering(data); } data.clearTriggerChanges(); } @@ -366,9 +367,9 @@ public void applyTriggerChanges(DynamicData data, ChunkSectionPos pos, Vector3dc private void enableDirectTriggering(DynamicData data, ChunkSectionPos section, Vector3dc cameraPos) { var newData = new DirectTriggerData(data, section, cameraPos); if (newData.isAngleTriggering(cameraPos)) { - insertDirectAngleTrigger(newData, cameraPos, TRIGGER_ANGLE); + this.insertDirectAngleTrigger(newData, cameraPos, TRIGGER_ANGLE); } else { - insertDirectDistanceTrigger(newData, cameraPos, DIRECT_TRIGGER_DISTANCE); + this.insertDirectDistanceTrigger(newData, cameraPos, DIRECT_TRIGGER_DISTANCE); } } @@ -393,9 +394,9 @@ public void removeSection(TranslucentData oldData, long sectionPos) { if (oldData == null) { return; } - disableGFNITriggering(sectionPos); - disableDirectTriggering(oldData); - decrementSortTypeCounter(oldData); + this.disableGFNITriggering(sectionPos); + this.disableDirectTriggering(oldData); + this.decrementSortTypeCounter(oldData); } private void addSectionInNewNormalLists(DynamicData dynamicData, AccumulationGroup accGroup) { @@ -417,7 +418,7 @@ private void removeSectionFromList(NormalList normalList, long sectionPos) { private void disableGFNITriggering(long sectionPos) { for (var normalList : this.normalLists.values()) { - removeSectionFromList(normalList, sectionPos); + this.removeSectionFromList(normalList, sectionPos); } } @@ -432,7 +433,7 @@ private void initiallyEnableGFNITriggering(DynamicData data, long sectionPos) { var accGroup = collector.getGroupForNormal(normalList); if (normalList.hasSection(sectionPos)) { if (accGroup == null) { - removeSectionFromList(normalList, sectionPos); + this.removeSectionFromList(normalList, sectionPos); } else { normalList.updateSection(accGroup, sectionPos); } @@ -448,13 +449,13 @@ private void initiallyEnableGFNITriggering(DynamicData data, long sectionPos) { if (collector.axisAlignedDistances != null) { for (var accGroup : collector.axisAlignedDistances) { if (accGroup != null) { - addSectionInNewNormalLists(data, accGroup); + this.addSectionInNewNormalLists(data, accGroup); } } } if (collector.unalignedDistances != null) { for (var accGroup : collector.unalignedDistances.values()) { - addSectionInNewNormalLists(data, accGroup); + this.addSectionInNewNormalLists(data, accGroup); } } @@ -477,28 +478,28 @@ public void integrateTranslucentData(TranslucentData oldData, TranslucentData ne long sectionPos = newData.sectionPos.asLong(); - incrementSortTypeCounter(newData); + this.incrementSortTypeCounter(newData); // remove the section if the data doesn't need to trigger on face planes if (newData instanceof DynamicData dynamicData) { - disableDirectTriggering(oldData); - decrementSortTypeCounter(oldData); + this.disableDirectTriggering(oldData); + this.decrementSortTypeCounter(oldData); if (dynamicData.GFNITrigger) { - initiallyEnableGFNITriggering(dynamicData, sectionPos); + this.initiallyEnableGFNITriggering(dynamicData, sectionPos); } else { // remove the collector since this section is never going to get gfni triggering // (there's no option to add sections to GFNI later currently) dynamicData.deleteCollector(); } if (dynamicData.directTrigger) { - enableDirectTriggering(dynamicData, newData.sectionPos, cameraPos); + this.enableDirectTriggering(dynamicData, newData.sectionPos, cameraPos); } // clear trigger changes on data change because the current state of trigger // types was just set dynamicData.clearTriggerChanges(); } else { - removeSection(oldData, sectionPos); + this.removeSection(oldData, sectionPos); return; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java index 2a7e94872f..355b3cff3f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java @@ -37,7 +37,7 @@ class Group { double baseDistance; Group(AccumulationGroup accGroup) { - replaceWith(accGroup); + this.replaceWith(accGroup); } void replaceWith(AccumulationGroup accGroup) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java index 9e3e099667..2702f5d465 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java @@ -148,13 +148,13 @@ void addSection(AccumulationGroup accGroup, long sectionPos) { var group = new Group(accGroup); this.groupsBySection.put(sectionPos, group); - addGroupInterval(group); + this.addGroupInterval(group); } void removeSection(long sectionPos) { Group group = this.groupsBySection.remove(sectionPos); if (group != null) { - removeGroupInterval(group); + this.removeGroupInterval(group); } } @@ -167,8 +167,8 @@ void updateSection(AccumulationGroup accGroup, long sectionPos) { return; } - removeGroupInterval(group); + this.removeGroupInterval(group); group.replaceWith(accGroup); - addGroupInterval(group); + this.addGroupInterval(group); } } From e571c36bc44c88ccaddd3e5b2eeafe81411113c7 Mon Sep 17 00:00:00 2001 From: douira Date: Sun, 5 Nov 2023 20:47:50 +0100 Subject: [PATCH 116/256] cleanup unused code --- .../render/chunk/gfni/ComplexSorting.java | 226 ------------------ 1 file changed, 226 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java index 9151ca0c9e..aacca0c14d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java @@ -4,7 +4,6 @@ import org.joml.Vector3fc; -import it.unimi.dsi.fastutil.ints.IntArrays; import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.util.collections.BitArray; @@ -37,66 +36,6 @@ private static boolean pointInsideHalfSpace(Vector3fc planeAnchor, Vector3fc pla return halfspace(planeAnchor, planeNormal, point) < 0; } - public static void distanceSortModified(IntBuffer indexBuffer, TQuad[] quads, Vector3fc cameraPos) { - int[] indexes = new int[quads.length]; - BitArray visible = new BitArray(quads.length); - float[] centerDist = new float[quads.length]; - for (int i = 0; i < indexes.length; i++) { - indexes[i] = i; - TQuad quad = quads[i]; - if (pointOutsideHalfspace(quad.center(), quad.normal(), cameraPos)) { - visible.set(i); - centerDist[i] = cameraPos.distanceSquared(quads[i].center()); - } - } - - IntArrays.quickSort(indexes, (a, b) -> { - // returning -1 results in the ordering a, b, returning 1 produces b, a - - boolean aVisible = visible.get(a); - boolean bVisible = visible.get(b); - - // compare only pairs where both are visible - if (aVisible && bVisible) { - var quadA = quads[a]; - var quadB = quads[b]; - var normalA = quadA.normal(); - var normalB = quadB.normal(); - - // this is a heuristic that attempts to reduce the sorting mistakes that happen - // when two parallel planes made up of many quads are seen from different - // angles. For quads with equal normals it sorts them only by their - // normal-relative distance to the camera. This eliminates some of wrong sorting - // that happens in tangent directions. - if (normalA.equals(normalB)) { - var centerA = quadA.center(); - var centerB = quadB.center(); - var cameraDistance = normalB.dot(cameraPos); - var result = Float.compare(Math.abs(cameraDistance - normalB.dot(centerB)), - Math.abs(cameraDistance - normalB.dot(centerA))); - if (result != 0) { - return result; - } - } - - return Float.compare(centerDist[b], centerDist[a]); - - } - - // put invisible quads last - if (aVisible) { - return -1; - } - if (bVisible) { - return 1; - } - - return 0; - }); - - TranslucentData.writeQuadVertexIndexes(indexBuffer, indexes); - } - private static int[] distanceSortIndexes(TQuad[] quads, Vector3fc cameraPos) { float[] keys = new float[quads.length]; for (int i = 0; i < quads.length; i++) { @@ -436,171 +375,6 @@ private static boolean quadVisibleThrough(TQuad quad, TQuad other, return result; } - /** - * Performs a topological sort but constructs the full forward graph without - * using a compression technique like - * {@link #topoSortAlignedScanningCyclic(IntBuffer, TQuad[], Vector3fc)} does. - * Only - * sort visible quads if a camera position is provided. - * - * @param indexBuffer the buffer to write the topo sort result to - * @param allQuads the quads to sort - * @param distancesByNormal a map of normals to sorted arrays of face plane - * distances, null to disable - * @param cameraPos the camera position, or null to disable the - * visibility check - * @return true if the quads were sorted, false if there was a cycle - */ - public static boolean topoSortLinkedListAcyclic( - IntBuffer indexBuffer, TQuad[] allQuads, - Object2ReferenceOpenHashMap distancesByNormal, - Vector3fc cameraPos) { - // TODO: quads visibility filter copy-pasted from topoSortAlignedAcyclic - // if enabled, check for visibility and produce a mapping of indices - TQuad[] quads = null; - int[] activeToRealIndex = null; - int activeQuads = 0; - if (cameraPos != null) { - // allocate the working quads and index map at the full size to avoid needing to - // iterate the quads again after checking visibility - quads = new TQuad[allQuads.length]; - activeToRealIndex = new int[allQuads.length]; - - for (int i = 0; i < allQuads.length; i++) { - TQuad quad = allQuads[i]; - if (pointOutsideHalfspace(quad.center(), quad.normal(), cameraPos)) { - activeToRealIndex[activeQuads] = i; - quads[activeQuads] = quad; - activeQuads++; - } else { - // write the invisible quads right away - TranslucentData.putQuadVertexIndexes(indexBuffer, i); - } - } - } else { - quads = allQuads; - activeQuads = allQuads.length; - } - - // special case for 0 or 1 quads because the algorithm below doesn't work for - // those cases (and it's just faster to skip it) - if (activeQuads == 0) { - return true; - } - if (activeQuads == 1) { - TranslucentData.putMappedQuadVertexIndexes(indexBuffer, 0, activeToRealIndex); - return true; - } - - // special case 2 quads for performance - if (activeQuads == 2) { - var a = 0; - var b = 1; - if (quadVisibleThrough(quads[a], quads[b], null, null)) { - a = 1; - b = 0; - } - TranslucentData.putMappedQuadVertexIndexes(indexBuffer, a, activeToRealIndex); - TranslucentData.putMappedQuadVertexIndexes(indexBuffer, b, activeToRealIndex); - return true; - } - - // int-based doubly linked list of active quad indexes - // TODO: put this linked list in a class - // TODO: sorting is sometimes wrong, see example in sandstone world - int[] next = new int[activeQuads]; - int[] prev = new int[activeQuads]; - int start = 0; - for (int i = 0; i < activeQuads - 1; i++) { - next[i] = i + 1; - prev[i + 1] = i; - } - next[activeQuads - 1] = -1; - prev[0] = -1; - - // go through all the active quads and insert them into the list at the point - // where they are after all the quads that are visible through them - for (int quadIndex = 0; quadIndex < activeQuads; quadIndex++) { - TQuad quad = quads[quadIndex]; - - // test all other quads - int insertAfter = -1; - int otherQuadIndex = start; - while (otherQuadIndex != -1) { - TQuad otherQuad = quads[otherQuadIndex]; - if (quadIndex != otherQuadIndex - && quadVisibleThrough(quad, otherQuad, distancesByNormal, cameraPos)) { - insertAfter = otherQuadIndex; - } - otherQuadIndex = next[otherQuadIndex]; - } - - // if the move index is lower than insert after, instead move the insert after - // to be right before the move index - int removeIndex = quadIndex; - boolean swapped = quadIndex < insertAfter; // implies insertAfter != -1 - if (swapped) { - removeIndex = insertAfter; - } - - // remove quadIndex or insertAfter from current location - int currentNext = next[removeIndex]; - int currentPrev = prev[removeIndex]; - if (currentNext != -1) { - prev[currentNext] = currentPrev; - } - if (currentPrev != -1) { - next[currentPrev] = currentNext; - } else { - start = currentNext; - } - - // insert after the identified last quad that this quad needs to be after - if (insertAfter == -1) { - // insert quadIndex at the start - next[quadIndex] = start; - prev[quadIndex] = -1; - prev[start] = quadIndex; - start = quadIndex; - } else if (swapped) { - // insert insertAfter at the start if quadIndex is the start - if (start == quadIndex) { - next[insertAfter] = start; - prev[insertAfter] = -1; - prev[start] = insertAfter; - start = insertAfter; - } else { - // insert insertAfter before quadIndex - next[insertAfter] = quadIndex; - next[prev[quadIndex]] = insertAfter; - prev[insertAfter] = prev[quadIndex]; - prev[quadIndex] = insertAfter; - } - } else { - // insert quadIndex after insertAfter - prev[quadIndex] = insertAfter; - if (next[insertAfter] != -1) { // end of chain - prev[next[insertAfter]] = quadIndex; - } - next[quadIndex] = next[insertAfter]; - next[insertAfter] = quadIndex; - } - } - - // write the sorted quads to the buffer - for (int i = 0; i < activeQuads; i++) { - TranslucentData.putMappedQuadVertexIndexes(indexBuffer, start, activeToRealIndex); - start = next[start]; - } - - // detect cycles - if (start != -1) { - return false; - } - - return true; - } - /** * Performs a topological sort without constructing the full graph in memory by * doing a DFS on the implicit graph. Edges are tested as they are searched for From 166522bb7ebccb1e46c7fa9412d5e3f3bb35d993 Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 6 Nov 2023 16:24:06 +0100 Subject: [PATCH 117/256] refactor gfni and direct triggering into separate classes --- .../client/model/quad/ModelQuadView.java | 8 +- .../render/chunk/RenderSectionManager.java | 16 +- .../render/chunk/gfni/ComplexSorting.java | 3 - .../render/chunk/gfni/DirectTriggers.java | 223 ++++++++ .../sodium/client/render/chunk/gfni/GFNI.java | 519 ------------------ .../render/chunk/gfni/GFNITriggers.java | 92 ++++ .../client/render/chunk/gfni/Group.java | 4 +- .../client/render/chunk/gfni/NormalList.java | 4 +- .../render/chunk/gfni/TranslucentSorting.java | 235 ++++++++ 9 files changed, 566 insertions(+), 538 deletions(-) create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DirectTriggers.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNITriggers.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentSorting.java diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java index 8d4fa62e37..82e55c0fe0 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.model.quad; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFlags; -import me.jellysquid.mods.sodium.client.render.chunk.gfni.GFNI; +import me.jellysquid.mods.sodium.client.render.chunk.gfni.TranslucentSorting; import net.caffeinemc.mods.sodium.api.util.NormI8; import net.minecraft.client.texture.Sprite; @@ -139,9 +139,9 @@ default int calculateNormals(boolean calculateUnitNormal) { // in each axis the number of values is 2 * QUANTIZATION_FACTOR + 1. // the total number of normals is the number of points on that cube's surface. this.setGFNINormal( - (int) (normX * GFNI.QUANTIZATION_FACTOR), - (int) (normY * GFNI.QUANTIZATION_FACTOR), - (int) (normZ * GFNI.QUANTIZATION_FACTOR)); + (int) (normX * TranslucentSorting.QUANTIZATION_FACTOR), + (int) (normY * TranslucentSorting.QUANTIZATION_FACTOR), + (int) (normZ * TranslucentSorting.QUANTIZATION_FACTOR)); return packedNormal; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index d1ae017c45..aea446092e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -22,7 +22,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.compile.tasks.ChunkBuilderTask; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionInfo; import me.jellysquid.mods.sodium.client.render.chunk.gfni.CameraMovement; -import me.jellysquid.mods.sodium.client.render.chunk.gfni.GFNI; +import me.jellysquid.mods.sodium.client.render.chunk.gfni.TranslucentSorting; import me.jellysquid.mods.sodium.client.render.chunk.gfni.TranslucentData; import me.jellysquid.mods.sodium.client.render.chunk.lists.ChunkRenderList; import me.jellysquid.mods.sodium.client.render.chunk.lists.SortedRenderLists; @@ -77,7 +77,7 @@ public class RenderSectionManager { private final int renderDistance; - private final GFNI gfni; + private final TranslucentSorting ts; @NotNull private SortedRenderLists renderLists; @@ -96,7 +96,7 @@ public RenderSectionManager(ClientWorld world, int renderDistance, CommandList c this.chunkRenderer = new DefaultChunkRenderer(RenderDevice.INSTANCE, ChunkMeshFormats.COMPACT); this.world = world; - this.gfni = new GFNI(); + this.ts = new TranslucentSorting(); this.builder = new ChunkBuilder(world, ChunkMeshFormats.COMPACT); @@ -211,7 +211,7 @@ public void onSectionRemoved(int x, int y, int z) { } if (section.getTranslucentData() != null) { - this.gfni.removeSection(section.getTranslucentData(), sectionPos); + this.ts.removeSection(section.getTranslucentData(), sectionPos); } RenderRegion region = section.getRegion(); @@ -326,13 +326,13 @@ private void processChunkBuildResults(ArrayList results) { if (result instanceof ChunkBuildOutput chunkBuildOutput) { this.updateSectionInfo(result.render, chunkBuildOutput.info); if (chunkBuildOutput.translucentData != null) { - this.gfni.integrateTranslucentData(oldData, chunkBuildOutput.translucentData, this.cameraPosition); + this.ts.integrateTranslucentData(oldData, chunkBuildOutput.translucentData, this.cameraPosition); // a rebuild always generates new translucent data which means applyTriggerChanges isn't necessary result.render.setTranslucentData(chunkBuildOutput.translucentData); } } else if (result instanceof ChunkSortOutput chunkSortOutput && chunkSortOutput.dynamicData.hasTriggerChanges()) { - this.gfni.applyTriggerChanges(chunkSortOutput.dynamicData, result.render.getPosition(), this.cameraPosition); + this.ts.applyTriggerChanges(chunkSortOutput.dynamicData, result.render.getPosition(), this.cameraPosition); } var job = result.render.getTaskCancellationToken(); @@ -446,7 +446,7 @@ public ChunkBuilderSortingTask createSortTask(RenderSection render, int frame) { } public void processGFNIMovement(CameraMovement movement) { - this.gfni.triggerSections(this::scheduleSort, movement); + this.ts.triggerSections(this::scheduleSort, movement); } public void markGraphDirty() { @@ -631,7 +631,7 @@ public Collection getDebugStrings() { this.taskLists.get(ChunkUpdateType.INITIAL_BUILD).size()) ); - this.gfni.addDebugStrings(list); + this.ts.addDebugStrings(list); return list; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java index aacca0c14d..576b3051da 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java @@ -380,9 +380,6 @@ private static boolean quadVisibleThrough(TQuad quad, TQuad other, * doing a DFS on the implicit graph. Edges are tested as they are searched for * and if necessary separator planes are used to disprove visibility. * - * TODO: the issue with it sometimes failing to sort is probably from the - * separator mechanism not working for unaligned quads yet. - * * @param indexBuffer the buffer to write the topo sort result to * @param allQuads the quads to sort * @param distancesByNormal a map of normals to sorted arrays of face plane diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DirectTriggers.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DirectTriggers.java new file mode 100644 index 0000000000..ed9acd26da --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DirectTriggers.java @@ -0,0 +1,223 @@ +package me.jellysquid.mods.sodium.client.render.chunk.gfni; + +import org.joml.Vector3d; +import org.joml.Vector3dc; + +import it.unimi.dsi.fastutil.doubles.Double2ObjectRBTreeMap; +import me.jellysquid.mods.sodium.client.render.chunk.gfni.TranslucentSorting.SectionTriggers; +import net.minecraft.util.math.ChunkSectionPos; + +class DirectTriggers implements SectionTriggers { + /** + * A tree map of the directly triggered sections, indexed by their + * minimum required camera movement. When the given camera movement is exceeded, + * they are tested for triggering the angle or distance condition. + * + * The accumulated distance is monotonically increasing and is never reset. This + * only becomes a problem when the camera moves more than 10^15 blocks in total. + * There will be precision issues at around 10^10 maybe, but it's still not a + * concern. + */ + private Double2ObjectRBTreeMap directTriggerSections = new Double2ObjectRBTreeMap<>(); + private double accumulatedDistance = 0; + + /** + * The factor by which the trigger distance and angle are multiplied to get a + * smaller threshold that is used for the actual trigger check but not the + * remaining distance calculation. This prevents curved movements from taking + * sections out of the tree and re-inserting without triggering many times near + * the actual trigger distance. It cuts the repeating unsuccessful trigger + * attempts off early. + */ + private static final double EARLY_TRIGGER_FACTOR = 0.9; + + /** + * Degrees of movement from last sort position before the section is sorted + * again. + */ + private static final double TRIGGER_ANGLE = Math.toRadians(20); + private static final double EARLY_TRIGGER_ANGLE_COS = Math.cos(TRIGGER_ANGLE * EARLY_TRIGGER_FACTOR); + private static final double SECTION_CENTER_DIST_SQUARED = 40 * 3 * Math.pow(16 / 2, 2); + private static final double SECTION_CENTER_DIST = Math.sqrt(SECTION_CENTER_DIST_SQUARED); + + /** + * How far the player must travel in blocks from the last position at which a + * section was sorted for it to be sorted again, if direct distance triggering + * is used (for close sections). + */ + private static final double DIRECT_TRIGGER_DISTANCE = 1; + private static final double EARLY_DIRECT_TRIGGER_DISTANCE_SQUARED = Math + .pow(DIRECT_TRIGGER_DISTANCE * EARLY_TRIGGER_FACTOR, 2); + + int getDirectTriggerCount() { + return this.directTriggerSections.size(); + } + + private class DirectTriggerData { + final ChunkSectionPos sectionPos; + private Vector3dc sectionCenter; + final DynamicData dynamicData; + + /** + * Absolute camera position at the time of the last trigger. + */ + Vector3dc triggerCameraPos; + + DirectTriggerData(DynamicData dynamicData, ChunkSectionPos sectionPos, Vector3dc triggerCameraPos) { + this.dynamicData = dynamicData; + this.sectionPos = sectionPos; + this.triggerCameraPos = triggerCameraPos; + } + + Vector3dc getSectionCenter() { + if (this.sectionCenter == null) { + this.sectionCenter = new Vector3d( + sectionPos.getMinX() + 8, + sectionPos.getMinY() + 8, + sectionPos.getMinZ() + 8); + } + return this.sectionCenter; + } + + /** + * Returns the distance between the sort camera pos and the center of the + * section. + */ + double getSectionCenterTriggerCameraDist() { + return Math.sqrt(getSectionCenterDistSquared(this.triggerCameraPos)); + } + + double getSectionCenterDistSquared(Vector3dc vector) { + Vector3dc sectionCenter = getSectionCenter(); + return sectionCenter.distanceSquared(vector); + } + + boolean isAngleTriggering(Vector3dc vector) { + return getSectionCenterDistSquared(vector) > SECTION_CENTER_DIST_SQUARED; + } + } + + // TODO: use faster code for this + private static double angleCos(double ax, double ay, double az, double bx, double by, double bz) { + double length1Squared = Math.fma(ax, ax, Math.fma(ay, ay, az * az)); + double length2Squared = Math.fma(bx, bx, Math.fma(by, by, bz * bz)); + double dot = Math.fma(ax, bx, Math.fma(ay, by, az * bz)); + return dot / Math.sqrt(length1Squared * length2Squared); + } + + private void insertDirectAngleTrigger(DirectTriggerData data, Vector3dc cameraPos, double remainingAngle) { + double triggerCameraSectionCenterDist = data.getSectionCenterTriggerCameraDist(); + double centerMinDistance = Math.tan(remainingAngle) * (triggerCameraSectionCenterDist - SECTION_CENTER_DIST); + this.insertJitteredTrigger(this.accumulatedDistance + centerMinDistance, data); + } + + private void insertDirectDistanceTrigger(DirectTriggerData data, Vector3dc cameraPos, double remainingDistance) { + this.insertJitteredTrigger(this.accumulatedDistance + remainingDistance, data); + } + + // TODO: instead of jittering use Tree where object is either a list or + // an individual record? + // jitters the double values to never overwrite the same key. abuses that + // doubles have more precision than we need to make them a kind of hash table + private double lastJittered = -1; + private double lastJitterResult = -1; + + private void insertJitteredTrigger(double key, DirectTriggerData data) { + // attempt insert without jittering + if (this.directTriggerSections.putIfAbsent(key, data) == null) { + data.dynamicData.directTriggerKey = key; + return; + } + + // if this is the same key as last time, skip all the identical keys that have + // already been jittered + if (this.lastJittered == key) { + key = this.lastJitterResult; + } else { + this.lastJittered = key; + } + + // Go to the next lower double to avoid collisions in the map. This slightly + // changes the key but doesn't significantly change its value. Subtraction is + // necessary to avoid delaying a trigger for too long. It's ok if it's too early + // though. This approach brings with it the disadvantages of linear probing but + // bad cases are unlikely to happen so it's fine. + do { + key = Math.nextDown(key); + } while (this.directTriggerSections.putIfAbsent(key, data) != null); + data.dynamicData.directTriggerKey = key; + this.lastJitterResult = key; + } + + @Override + public void processTriggers(TranslucentSorting ts, CameraMovement movement) { + Vector3dc lastCamera = movement.lastCamera(); + Vector3dc camera = movement.currentCamera(); + this.accumulatedDistance += lastCamera.distance(camera); + + // iterate all elements with a key of at most accumulatedDistance + var head = this.directTriggerSections.headMap(this.accumulatedDistance); + for (var entry : head.double2ObjectEntrySet()) { + this.directTriggerSections.remove(entry.getDoubleKey()); + DirectTriggerData data = entry.getValue(); + + boolean isAngle = data.isAngleTriggering(camera); + if (isAngle) { + double remainingAngle = TRIGGER_ANGLE; + + // check if the angle since the last sort exceeds the threshold + Vector3dc sectionCenter = data.getSectionCenter(); + double angleCos = angleCos( + sectionCenter.x() - data.triggerCameraPos.x(), + sectionCenter.y() - data.triggerCameraPos.y(), + sectionCenter.z() - data.triggerCameraPos.z(), + sectionCenter.x() - camera.x(), + sectionCenter.y() - camera.y(), + sectionCenter.z() - camera.z()); + + // compare angles inverted because cosine flips it + if (angleCos <= EARLY_TRIGGER_ANGLE_COS) { + ts.triggerSectionDirect(data.sectionPos); + data.triggerCameraPos = camera; + } else { + remainingAngle -= Math.acos(angleCos); + } + + this.insertDirectAngleTrigger(data, camera, remainingAngle); + } else { + double remainingDistance = DIRECT_TRIGGER_DISTANCE; + double lastTriggerCurrentCameraDistSquared = data.triggerCameraPos.distanceSquared(camera); + + if (lastTriggerCurrentCameraDistSquared >= EARLY_DIRECT_TRIGGER_DISTANCE_SQUARED) { + ts.triggerSectionDirect(data.sectionPos); + data.triggerCameraPos = camera; + } else { + remainingDistance -= Math.sqrt(lastTriggerCurrentCameraDistSquared); + } + + this.insertDirectDistanceTrigger(data, camera, remainingDistance); + } + } + } + + @Override + public void removeSection(long sectionPos, TranslucentData data) { + if (data instanceof DynamicData dynamicData) { + var key = dynamicData.directTriggerKey; + if (key != -1) { + this.directTriggerSections.remove(key); + dynamicData.directTriggerKey = -1; + } + } + } + + @Override + public void addSection(ChunkSectionPos sectionPos, DynamicData data, Vector3dc cameraPos) { + var newData = new DirectTriggerData(data, sectionPos, cameraPos); + if (newData.isAngleTriggering(cameraPos)) { + this.insertDirectAngleTrigger(newData, cameraPos, TRIGGER_ANGLE); + } else { + this.insertDirectDistanceTrigger(newData, cameraPos, DIRECT_TRIGGER_DISTANCE); + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java deleted file mode 100644 index 4626016e3d..0000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNI.java +++ /dev/null @@ -1,519 +0,0 @@ -package me.jellysquid.mods.sodium.client.render.chunk.gfni; - -import java.util.List; -import java.util.function.BiConsumer; - -import org.joml.Vector3d; -import org.joml.Vector3dc; -import org.joml.Vector3fc; - -import it.unimi.dsi.fastutil.doubles.Double2ObjectRBTreeMap; -import it.unimi.dsi.fastutil.ints.IntOpenHashSet; -import it.unimi.dsi.fastutil.longs.LongOpenHashSet; -import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; -import net.minecraft.util.math.ChunkSectionPos; - -/** - * Global Face Normal Indexing as described in - * https://hackmd.io/@douira100/sodium-sl-gfni - * - * Distances are stored as doubles and normals are stored as float vectors. - * - * TODO: - * - many sections can be marked as needing an update but they are only actually - * scheduled for sorting when the RenderSectionManager makes them visible. This - * may result in many sections suddenly needing sorting when the camera moves. - * Maybe it's better to schedule them to be sorted gradually even if not - * visible, if there are idle threads. - * - Groups of quads that form convex shapes in a single plane without holes can - * be sorted as one "quad". Their internal sorting can be arbitrary. Detecting - * and grouping/ungrouping them might prove difficult. Finding all quad groups - * is hard but finding one quad group at a time per direction is doable during - * building. Using the extents calculated for aligned quads, continuity can be - * easily tested and then convexity confirmed. How to deal with groups of quads - * that are only convex if a few of the quads are ignored? - * - Movement prediction and preemptive task scheduling to avoid needing to - * perform blocking sorts of close sections. Maybe not an issue? Might reduce - * stutter in high fps situations. However, high complexity with regards to - * processing the results of preemptive sorts. - * - Does fluid renderer sometimes produce aligned faces that it doesn't - * classify as such? they could be detected and then correctly assigned in the - * fluid renderer directly. - * - Check that separators still work on aligned geomtry. It seems that a lot of - * things are not topo sortable after the most recent fix to the quad visibility - * check. - * - figure out why when the player moves at high speed there end up being more - * direct trigger entries than sections with the dynamic sort type, even if - * everything is set to only direct trigger and not GFNI trigger. (the numbers - * should be the same, somehow they're not being bookkept correctly) - * - determine the right distance for angle/distance triggering. It seems just - * the diagonal of a section is too small, angle triggering is broken at close - * distances. - * - separate this class into GFNI and direct triggering? - * - * @author douira - */ -public class GFNI { - /** - * The quantization factor with which the normals are quantized such that there - * are fewer possible unique normals. The factor describes the number of steps - * in each direction per dimension that the components of the normals can have. - * It determines the density of the grid on the surface of a unit cube centered - * at the origin onto which the normals are projected. The normals are snapped - * to the nearest grid point. - */ - public static final int QUANTIZATION_FACTOR = 4; - - /** - * A map of all the normal lists, indexed by their normal. - */ - private Object2ReferenceOpenHashMap normalLists = new Object2ReferenceOpenHashMap<>(50); - - /** - * A tree map of the directly triggered sections, indexed by their - * minimum required camera movement. When the given camera movement is exceeded, - * they are tested for triggering the angle or distance condition. - * - * The accumulated distance is monotonically increasing and is never reset. This - * only becomes a problem when the camera moves more than 10^15 blocks in total. - * There will be precision issues at around 10^10 maybe, but it's still not a - * concern. - */ - private Double2ObjectRBTreeMap directTriggerSections = new Double2ObjectRBTreeMap<>(); - private double accumulatedDistance = 0; - - /** - * To avoid generating a collection of the triggered sections, this callback is - * used to process the triggered sections directly as they are queried from the - * normal lists' interval trees. The callback is given the section coordinates, - * and a boolean indicating if the trigger was an direct trigger. - */ - private BiConsumer triggerSectionCallback; - - /** - * A set of all the sections that were triggered the last time something was - * triggered. - * - * TODO: only count the sections and not their whole position - */ - private final LongOpenHashSet triggeredSections = new LongOpenHashSet(50); - private int triggeredSectionCount = 0; - - /** - * A set of all the normals that were triggered the last time something was - * triggered. - */ - private final IntOpenHashSet triggeredNormals = new IntOpenHashSet(50); - private int triggeredNormalCount = 0; - - /** - * A map of the number of times each sort type is currently in use. - */ - private final int[] sortTypeCounters = new int[SortType.values().length]; - - private void decrementSortTypeCounter(TranslucentData oldData) { - if (oldData != null) { - this.sortTypeCounters[oldData.getSortType().ordinal()]--; - } - } - - private void incrementSortTypeCounter(TranslucentData newData) { - this.sortTypeCounters[newData.getSortType().ordinal()]++; - } - - /** - * Triggers the sections that the given camera movement crosses face planes of. - * - * @param triggerSectionCallback called for each section that is triggered - * @param lastCameraX the camera x position before the movement - * @param lastCameraY the camera y position before the movement - * @param lastCameraZ the camera z position before the movement - * @param cameraX the camera x position after the movement - * @param cameraY the camera y position after the movement - * @param cameraZ the camera z position after the movement - */ - public void triggerSections(BiConsumer triggerSectionCallback, CameraMovement movement) { - triggeredSections.clear(); - triggeredNormals.clear(); - this.triggerSectionCallback = triggerSectionCallback; - - this.processGFNITriggers(movement); - this.processDirectTriggers(movement); - - var newTriggeredSectionsCount = this.triggeredSections.size(); - var newTriggeredNormalCount = this.triggeredNormals.size(); - if (newTriggeredSectionsCount > 0) { - this.triggeredSectionCount = newTriggeredSectionsCount; - this.triggeredNormalCount = newTriggeredNormalCount; - } - - // int triggerCount = this.triggeredSections.size(); - // if (triggerCount > 0) { - // System.out.println("Triggered " + triggerCount + " sections"); - // for (long section : this.triggeredSections) { - // ChunkSectionPos sectionPos = ChunkSectionPos.from(section); - // System.out.println(sectionPos.getX() + " " + sectionPos.getY() + " " + - // sectionPos.getZ()); - // } - // } - - triggerSectionCallback = null; - } - - private void processGFNITriggers(CameraMovement movement) { - for (var normalList : this.normalLists.values()) { - normalList.processMovement(this, movement); - } - } - - /** - * The factor by which the trigger distance and angle are multiplied to get a - * smaller threshold that is used for the actual trigger check but not the - * remaining distance calculation. This prevents curved movements from taking - * sections out of the tree and re-inserting without triggering many times near - * the actual trigger distance. It cuts the repeating unsuccessful trigger - * attempts off early. - */ - private static final double EARLY_TRIGGER_FACTOR = 0.9; - - /** - * Degrees of movement from last sort position before the section is sorted - * again. - */ - private static final double TRIGGER_ANGLE = Math.toRadians(20); - private static final double EARLY_TRIGGER_ANGLE_COS = Math.cos(TRIGGER_ANGLE * EARLY_TRIGGER_FACTOR); - private static final double SECTION_CENTER_DIST_SQUARED = 40 * 3 * Math.pow(16 / 2, 2); - private static final double SECTION_CENTER_DIST = Math.sqrt(SECTION_CENTER_DIST_SQUARED); - - /** - * How far the player must travel in blocks from the last position at which a - * section was sorted for it to be sorted again, if direct distance triggering - * is used (for close sections). - */ - private static final double DIRECT_TRIGGER_DISTANCE = 1; - private static final double EARLY_DIRECT_TRIGGER_DISTANCE_SQUARED = Math - .pow(DIRECT_TRIGGER_DISTANCE * EARLY_TRIGGER_FACTOR, 2); - - private class DirectTriggerData { - final ChunkSectionPos sectionPos; - private Vector3dc sectionCenter; - final DynamicData dynamicData; - - /** - * Absolute camera position at the time of the last trigger. - */ - Vector3dc triggerCameraPos; - - DirectTriggerData(DynamicData dynamicData, ChunkSectionPos sectionPos, Vector3dc triggerCameraPos) { - this.dynamicData = dynamicData; - this.sectionPos = sectionPos; - this.triggerCameraPos = triggerCameraPos; - } - - Vector3dc getSectionCenter() { - if (this.sectionCenter == null) { - this.sectionCenter = new Vector3d( - sectionPos.getMinX() + 8, - sectionPos.getMinY() + 8, - sectionPos.getMinZ() + 8); - } - return this.sectionCenter; - } - - /** - * Returns the distance between the sort camera pos and the center of the - * section. - */ - double getSectionCenterTriggerCameraDist() { - return Math.sqrt(getSectionCenterDistSquared(this.triggerCameraPos)); - } - - double getSectionCenterDistSquared(Vector3dc vector) { - Vector3dc sectionCenter = getSectionCenter(); - return sectionCenter.distanceSquared(vector); - } - - boolean isAngleTriggering(Vector3dc vector) { - return getSectionCenterDistSquared(vector) > SECTION_CENTER_DIST_SQUARED; - } - } - - // TODO: use faster code for this - private static double angleCos(double ax, double ay, double az, double bx, double by, double bz) { - double length1Squared = Math.fma(ax, ax, Math.fma(ay, ay, az * az)); - double length2Squared = Math.fma(bx, bx, Math.fma(by, by, bz * bz)); - double dot = Math.fma(ax, bx, Math.fma(ay, by, az * bz)); - return dot / Math.sqrt(length1Squared * length2Squared); - } - - private void processDirectTriggers(CameraMovement movement) { - Vector3dc lastCamera = movement.lastCamera(); - Vector3dc camera = movement.currentCamera(); - this.accumulatedDistance += lastCamera.distance(camera); - - // iterate all elements with a key of at most accumulatedDistance - var head = this.directTriggerSections.headMap(this.accumulatedDistance); - for (var entry : head.double2ObjectEntrySet()) { - this.directTriggerSections.remove(entry.getDoubleKey()); - DirectTriggerData data = entry.getValue(); - - boolean isAngle = data.isAngleTriggering(camera); - if (isAngle) { - double remainingAngle = TRIGGER_ANGLE; - - // check if the angle since the last sort exceeds the threshold - Vector3dc sectionCenter = data.getSectionCenter(); - double angleCos = angleCos( - sectionCenter.x() - data.triggerCameraPos.x(), - sectionCenter.y() - data.triggerCameraPos.y(), - sectionCenter.z() - data.triggerCameraPos.z(), - sectionCenter.x() - camera.x(), - sectionCenter.y() - camera.y(), - sectionCenter.z() - camera.z()); - - // compare angles inverted because cosine flips it - if (angleCos <= EARLY_TRIGGER_ANGLE_COS) { - this.triggerSectionDirect(data.sectionPos); - data.triggerCameraPos = camera; - } else { - remainingAngle -= Math.acos(angleCos); - } - - this.insertDirectAngleTrigger(data, camera, remainingAngle); - } else { - double remainingDistance = DIRECT_TRIGGER_DISTANCE; - double lastTriggerCurrentCameraDistSquared = data.triggerCameraPos.distanceSquared(camera); - - if (lastTriggerCurrentCameraDistSquared >= EARLY_DIRECT_TRIGGER_DISTANCE_SQUARED) { - this.triggerSectionDirect(data.sectionPos); - data.triggerCameraPos = camera; - } else { - remainingDistance -= Math.sqrt(lastTriggerCurrentCameraDistSquared); - } - - this.insertDirectDistanceTrigger(data, camera, remainingDistance); - } - } - } - - private void insertDirectAngleTrigger(DirectTriggerData data, Vector3dc cameraPos, double remainingAngle) { - double triggerCameraSectionCenterDist = data.getSectionCenterTriggerCameraDist(); - double centerMinDistance = Math.tan(remainingAngle) * (triggerCameraSectionCenterDist - SECTION_CENTER_DIST); - this.insertJitteredTrigger(this.accumulatedDistance + centerMinDistance, data); - } - - private void insertDirectDistanceTrigger(DirectTriggerData data, Vector3dc cameraPos, double remainingDistance) { - this.insertJitteredTrigger(this.accumulatedDistance + remainingDistance, data); - } - - // TODO: instead of jittering use Tree where object is either a list or an individual record? - // jitters the double values to never overwrite the same key. abuses that - // doubles have more precision than we need to make them a kind of hash table - private double lastJittered = -1; - private double lastJitterResult = -1; - - private void insertJitteredTrigger(double key, DirectTriggerData data) { - // attempt insert without jittering - if (this.directTriggerSections.putIfAbsent(key, data) == null) { - data.dynamicData.directTriggerKey = key; - return; - } - - // if this is the same key as last time, skip all the identical keys that have - // already been jittered - if (this.lastJittered == key) { - key = this.lastJitterResult; - } else { - this.lastJittered = key; - } - - // Go to the next lower double to avoid collisions in the map. This slightly - // changes the key but doesn't significantly change its value. Subtraction is - // necessary to avoid delaying a trigger for too long. It's ok if it's too early - // though. This approach brings with it the disadvantages of linear probing but - // bad cases are unlikely to happen so it's fine. - do { - key = Math.nextDown(key); - } while (this.directTriggerSections.putIfAbsent(key, data) != null); - data.dynamicData.directTriggerKey = key; - this.lastJitterResult = key; - } - - void triggerSectionGFNI(long sectionPos, int collectorKey) { - this.triggeredNormals.add(collectorKey); - this.triggeredSections.add(sectionPos); - this.triggerSectionCallback.accept(sectionPos, false); - } - - private void triggerSectionDirect(ChunkSectionPos sectionPos) { - var sectionPosLong = sectionPos.asLong(); - this.triggerSectionCallback.accept(sectionPosLong, true); - this.triggeredSections.add(sectionPosLong); - } - - public void applyTriggerChanges(DynamicData data, ChunkSectionPos pos, Vector3dc cameraPos) { - if (data.turnGFNITriggerOff) { - this.disableGFNITriggering(pos.asLong()); - } - if (data.turnDirectTriggerOn) { - this.enableDirectTriggering(data, pos, cameraPos); - } - if (data.turnDirectTriggerOff) { - this.disableDirectTriggering(data); - } - data.clearTriggerChanges(); - } - - private void enableDirectTriggering(DynamicData data, ChunkSectionPos section, Vector3dc cameraPos) { - var newData = new DirectTriggerData(data, section, cameraPos); - if (newData.isAngleTriggering(cameraPos)) { - this.insertDirectAngleTrigger(newData, cameraPos, TRIGGER_ANGLE); - } else { - this.insertDirectDistanceTrigger(newData, cameraPos, DIRECT_TRIGGER_DISTANCE); - } - } - - private void disableDirectTriggering(TranslucentData data) { - if (data instanceof DynamicData dynamicData) { - var key = dynamicData.directTriggerKey; - if (key != -1) { - this.directTriggerSections.remove(key); - dynamicData.directTriggerKey = -1; - } - } - } - - /** - * Removes a section from direct and GFNI triggering. This removes all its face - * planes. - * - * @param oldData the data of the section to remove - * @param sectionPos the section to remove - */ - public void removeSection(TranslucentData oldData, long sectionPos) { - if (oldData == null) { - return; - } - this.disableGFNITriggering(sectionPos); - this.disableDirectTriggering(oldData); - this.decrementSortTypeCounter(oldData); - } - - private void addSectionInNewNormalLists(DynamicData dynamicData, AccumulationGroup accGroup) { - var normal = accGroup.normal; - var normalList = this.normalLists.get(normal); - if (normalList == null) { - normalList = new NormalList(normal, accGroup.collectorKey); - this.normalLists.put(normal, normalList); - normalList.addSection(accGroup, accGroup.sectionPos.asLong()); - } - } - - private void removeSectionFromList(NormalList normalList, long sectionPos) { - normalList.removeSection(sectionPos); - if (normalList.isEmpty()) { - this.normalLists.remove(normalList.getNormal()); - } - } - - private void disableGFNITriggering(long sectionPos) { - for (var normalList : this.normalLists.values()) { - this.removeSectionFromList(normalList, sectionPos); - } - } - - private void initiallyEnableGFNITriggering(DynamicData data, long sectionPos) { - var collector = data.getCollector(); - - // go through all normal lists and check against the normals that the group - // builder has. if the normal list has data for the section, but the group - // builder doesn't, the group is removed. otherwise, the group is updated. - for (var normalList : this.normalLists.values()) { - // check if the geometry collector includes data for this normal. - var accGroup = collector.getGroupForNormal(normalList); - if (normalList.hasSection(sectionPos)) { - if (accGroup == null) { - this.removeSectionFromList(normalList, sectionPos); - } else { - normalList.updateSection(accGroup, sectionPos); - } - } else if (accGroup != null) { - normalList.addSection(accGroup, sectionPos); - } - } - - // go through the data of the geometry collector to check for data of new - // normals - // for which there are no normal lists yet. This only checks for new normal - // lists since new data for existing normal lists is handled above. - if (collector.axisAlignedDistances != null) { - for (var accGroup : collector.axisAlignedDistances) { - if (accGroup != null) { - this.addSectionInNewNormalLists(data, accGroup); - } - } - } - if (collector.unalignedDistances != null) { - for (var accGroup : collector.unalignedDistances.values()) { - this.addSectionInNewNormalLists(data, accGroup); - } - } - - data.deleteCollector(); - } - - /** - * Integrates the data from a geometry collector into GFNI. The geometry - * collector contains the translucent face planes of a single section. This - * method may also remove the section if it has become irrelevant. - * - * @param builder the geometry collector to integrate - * @return the sort type that the geometry collector's relevance heuristic - * determined - */ - public void integrateTranslucentData(TranslucentData oldData, TranslucentData newData, Vector3dc cameraPos) { - if (oldData == newData) { - return; - } - - long sectionPos = newData.sectionPos.asLong(); - - this.incrementSortTypeCounter(newData); - - // remove the section if the data doesn't need to trigger on face planes - if (newData instanceof DynamicData dynamicData) { - this.disableDirectTriggering(oldData); - this.decrementSortTypeCounter(oldData); - if (dynamicData.GFNITrigger) { - this.initiallyEnableGFNITriggering(dynamicData, sectionPos); - } else { - // remove the collector since this section is never going to get gfni triggering - // (there's no option to add sections to GFNI later currently) - dynamicData.deleteCollector(); - } - if (dynamicData.directTrigger) { - this.enableDirectTriggering(dynamicData, newData.sectionPos, cameraPos); - } - - // clear trigger changes on data change because the current state of trigger - // types was just set - dynamicData.clearTriggerChanges(); - } else { - this.removeSection(oldData, sectionPos); - return; - } - } - - public void addDebugStrings(List list) { - list.add(String.format("GFNI NL=%02d TrS=%03d TrN=%02d", - this.normalLists.size(), - this.triggeredSectionCount, - this.triggeredNormalCount)); - list.add(String.format("N=%05d SNR=%05d STA=%04d DYN=%04d (DIR=%04d)", - this.sortTypeCounters[SortType.NONE.ordinal()], - this.sortTypeCounters[SortType.STATIC_NORMAL_RELATIVE.ordinal()], - this.sortTypeCounters[SortType.STATIC_TOPO_ACYCLIC.ordinal()], - this.sortTypeCounters[SortType.DYNAMIC_ALL.ordinal()], - this.directTriggerSections.size())); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNITriggers.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNITriggers.java new file mode 100644 index 0000000000..01d0e7206b --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNITriggers.java @@ -0,0 +1,92 @@ +package me.jellysquid.mods.sodium.client.render.chunk.gfni; + +import org.joml.Vector3dc; +import org.joml.Vector3fc; + +import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; +import me.jellysquid.mods.sodium.client.render.chunk.gfni.TranslucentSorting.SectionTriggers; +import net.minecraft.util.math.ChunkSectionPos; + +class GFNITriggers implements SectionTriggers { + /** + * A map of all the normal lists, indexed by their normal. + */ + private Object2ReferenceOpenHashMap normalLists = new Object2ReferenceOpenHashMap<>(); + + int getUniqueNormalCount() { + return this.normalLists.size(); + } + + @Override + public void processTriggers(TranslucentSorting ts, CameraMovement movement) { + for (var normalList : this.normalLists.values()) { + normalList.processMovement(ts, movement); + } + } + + private void addSectionInNewNormalLists(DynamicData dynamicData, AccumulationGroup accGroup) { + var normal = accGroup.normal; + var normalList = this.normalLists.get(normal); + if (normalList == null) { + normalList = new NormalList(normal, accGroup.collectorKey); + this.normalLists.put(normal, normalList); + normalList.addSection(accGroup, accGroup.sectionPos.asLong()); + } + } + + private void removeSectionFromList(NormalList normalList, long sectionPos) { + normalList.removeSection(sectionPos); + if (normalList.isEmpty()) { + this.normalLists.remove(normalList.getNormal()); + } + } + + @Override + public void removeSection(long sectionPos, TranslucentData data) { + for (var normalList : this.normalLists.values()) { + this.removeSectionFromList(normalList, sectionPos); + } + } + + @Override + public void addSection(ChunkSectionPos pos, DynamicData data, Vector3dc cameraPos) { + long sectionPos = pos.asLong(); + var collector = data.getCollector(); + + // go through all normal lists and check against the normals that the group + // builder has. if the normal list has data for the section, but the group + // builder doesn't, the group is removed. otherwise, the group is updated. + for (var normalList : this.normalLists.values()) { + // check if the geometry collector includes data for this normal. + var accGroup = collector.getGroupForNormal(normalList); + if (normalList.hasSection(sectionPos)) { + if (accGroup == null) { + this.removeSectionFromList(normalList, sectionPos); + } else { + normalList.updateSection(accGroup, sectionPos); + } + } else if (accGroup != null) { + normalList.addSection(accGroup, sectionPos); + } + } + + // go through the data of the geometry collector to check for data of new + // normals + // for which there are no normal lists yet. This only checks for new normal + // lists since new data for existing normal lists is handled above. + if (collector.axisAlignedDistances != null) { + for (var accGroup : collector.axisAlignedDistances) { + if (accGroup != null) { + this.addSectionInNewNormalLists(data, accGroup); + } + } + } + if (collector.unalignedDistances != null) { + for (var accGroup : collector.unalignedDistances.values()) { + this.addSectionInNewNormalLists(data, accGroup); + } + } + + data.deleteCollector(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java index 355b3cff3f..252ee52bba 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java @@ -72,14 +72,14 @@ public static boolean queryRange(double[] sortedDistances, double start, double return false; } - void triggerRange(GFNI gfni, double start, double end, int collectorKey) { + void triggerRange(TranslucentSorting ts, double start, double end, int collectorKey) { // trigger self on the section if the query range overlaps with the group // testing for strict inequality because if the two intervals just touch at the // start/end, there can be no overlap if (start < this.distances.getEnd() && end > this.distances.getStart() && queryRange(this.facePlaneDistances, start - this.baseDistance, end - this.baseDistance)) { - gfni.triggerSectionGFNI(this.sectionPos, collectorKey); + ts.triggerSectionGFNI(this.sectionPos, collectorKey); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java index 2702f5d465..d631855dc6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java @@ -86,7 +86,7 @@ int getCollectorKey() { return collectorKey; } - void processMovement(GFNI gfni, CameraMovement movement) { + void processMovement(TranslucentSorting ts, CameraMovement movement) { // calculate the distance range of the movement with respect to the normal double start = this.normal.dot(movement.lastCamera()); double end = this.normal.dot(movement.currentCamera()); @@ -102,7 +102,7 @@ void processMovement(GFNI gfni, CameraMovement movement) { var interval = new DoubleInterval(start, end, Bounded.CLOSED); for (Interval groupInterval : groupIntervals.query(interval)) { for (Group group : groupsByInterval.get(groupInterval)) { - group.triggerRange(gfni, start, end, this.collectorKey); + group.triggerRange(ts, start, end, this.collectorKey); } } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentSorting.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentSorting.java new file mode 100644 index 0000000000..cb70a16580 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentSorting.java @@ -0,0 +1,235 @@ +package me.jellysquid.mods.sodium.client.render.chunk.gfni; + +import java.util.List; +import java.util.function.BiConsumer; + +import org.joml.Vector3dc; + +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import net.minecraft.util.math.ChunkSectionPos; + +/** + * Global Face Normal Indexing as described in + * https://hackmd.io/@douira100/sodium-sl-gfni + * + * Distances are stored as doubles and normals are stored as float vectors. + * + * TODO: + * - many sections can be marked as needing an update but they are only actually + * scheduled for sorting when the RenderSectionManager makes them visible. This + * may result in many sections suddenly needing sorting when the camera moves. + * Maybe it's better to schedule them to be sorted gradually even if not + * visible, if there are idle threads. + * - Groups of quads that form convex shapes in a single plane without holes can + * be sorted as one "quad". Their internal sorting can be arbitrary. Detecting + * and grouping/ungrouping them might prove difficult. Finding all quad groups + * is hard but finding one quad group at a time per direction is doable during + * building. Using the extents calculated for aligned quads, continuity can be + * easily tested and then convexity confirmed. How to deal with groups of quads + * that are only convex if a few of the quads are ignored? + * - Movement prediction and preemptive task scheduling to avoid needing to + * perform blocking sorts of close sections. Maybe not an issue? Might reduce + * stutter in high fps situations. However, high complexity with regards to + * processing the results of preemptive sorts. + * - Check that separators still work on aligned geomtry. It seems that a lot of + * things are not topo sortable after the most recent fix to the quad visibility + * check. + * - figure out why when the player moves at high speed there end up being more + * direct trigger entries than sections with the dynamic sort type, even if + * everything is set to only direct trigger and not GFNI trigger. (the numbers + * should be the same, somehow they're not being bookkept correctly) + * - determine the right distance for angle/distance triggering. It seems just + * the diagonal of a section is too small, angle triggering is broken at close + * distances. + * - re-use distance sort data to accelerate future distance sorting. Sorting + * mostly sorted data is probably faster than sorting unsorted data (or whatever + * data comes out of the mesh). + * - investigate why a small epsilon of 0.001 makes many more sections sortable + * when it's added as a "slack" distance to the complex sorting's quad + * visibility check. This suggests that the quad visibility check or the + * quantization of vertex positions is not working correctly. + * + * @author douira + */ +public class TranslucentSorting { + /** + * The quantization factor with which the normals are quantized such that there + * are fewer possible unique normals. The factor describes the number of steps + * in each direction per dimension that the components of the normals can have. + * It determines the density of the grid on the surface of a unit cube centered + * at the origin onto which the normals are projected. The normals are snapped + * to the nearest grid point. + */ + public static final int QUANTIZATION_FACTOR = 4; + + /** + * To avoid generating a collection of the triggered sections, this callback is + * used to process the triggered sections directly as they are queried from the + * normal lists' interval trees. The callback is given the section coordinates, + * and a boolean indicating if the trigger was an direct trigger. + */ + private BiConsumer triggerSectionCallback; + + /** + * The number of triggered sections and normals. The normals are kept in a + * hashmap to count them, triggered sections are not deduplicated. + */ + private int gfniTriggerCount = 0; + private int directTriggerCount = 0; + private final IntOpenHashSet triggeredNormals = new IntOpenHashSet(); + private int triggeredNormalCount = 0; + + /** + * A map of the number of times each sort type is currently in use. + */ + private final int[] sortTypeCounters = new int[SortType.values().length]; + + private final GFNITriggers gfni = new GFNITriggers(); + private final DirectTriggers direct = new DirectTriggers(); + + interface SectionTriggers { + void processTriggers(TranslucentSorting ts, CameraMovement movement); + + void removeSection(long sectionPos, TranslucentData data); + + void addSection(ChunkSectionPos sectionPos, DynamicData data, Vector3dc cameraPos); + } + + /** + * Triggers the sections that the given camera movement crosses face planes of. + * + * @param triggerSectionCallback called for each section that is triggered + * @param lastCameraX the camera x position before the movement + * @param lastCameraY the camera y position before the movement + * @param lastCameraZ the camera z position before the movement + * @param cameraX the camera x position after the movement + * @param cameraY the camera y position after the movement + * @param cameraZ the camera z position after the movement + */ + public void triggerSections(BiConsumer triggerSectionCallback, CameraMovement movement) { + triggeredNormals.clear(); + this.triggerSectionCallback = triggerSectionCallback; + var oldGfniTriggerCount = this.gfniTriggerCount; + var oldDirectTriggerCount = this.directTriggerCount; + this.gfniTriggerCount = 0; + this.directTriggerCount = 0; + + this.gfni.processTriggers(this, movement); + this.direct.processTriggers(this, movement); + + if (this.gfniTriggerCount > 0 || this.directTriggerCount > 0) { + this.triggeredNormalCount = this.triggeredNormals.size(); + } else { + this.gfniTriggerCount = oldGfniTriggerCount; + this.directTriggerCount = oldDirectTriggerCount; + } + + triggerSectionCallback = null; + } + + void triggerSectionGFNI(long sectionPos, int collectorKey) { + this.triggeredNormals.add(collectorKey); + this.triggerSectionCallback.accept(sectionPos, false); + this.gfniTriggerCount++; + } + + void triggerSectionDirect(ChunkSectionPos sectionPos) { + this.triggerSectionCallback.accept(sectionPos.asLong(), true); + this.directTriggerCount++; + } + + public void applyTriggerChanges(DynamicData data, ChunkSectionPos pos, Vector3dc cameraPos) { + if (data.turnGFNITriggerOff) { + this.gfni.removeSection(pos.asLong(), data); + } + if (data.turnDirectTriggerOn) { + this.direct.addSection(pos, data, cameraPos); + } + if (data.turnDirectTriggerOff) { + this.direct.removeSection(pos.asLong(), data); + } + data.clearTriggerChanges(); + } + + private void decrementSortTypeCounter(TranslucentData oldData) { + if (oldData != null) { + this.sortTypeCounters[oldData.getSortType().ordinal()]--; + } + } + + private void incrementSortTypeCounter(TranslucentData newData) { + this.sortTypeCounters[newData.getSortType().ordinal()]++; + } + + /** + * Removes a section from direct and GFNI triggering. This removes all its face + * planes. + * + * @param oldData the data of the section to remove + * @param sectionPos the section to remove + */ + public void removeSection(TranslucentData oldData, long sectionPos) { + if (oldData == null) { + return; + } + this.gfni.removeSection(sectionPos, oldData); + this.direct.removeSection(sectionPos, oldData); + this.decrementSortTypeCounter(oldData); + } + + /** + * Integrates the data from a geometry collector into GFNI. The geometry + * collector contains the translucent face planes of a single section. This + * method may also remove the section if it has become irrelevant. + * + * @param builder the geometry collector to integrate + * @return the sort type that the geometry collector's relevance heuristic + * determined + */ + public void integrateTranslucentData(TranslucentData oldData, TranslucentData newData, Vector3dc cameraPos) { + if (oldData == newData) { + return; + } + + var pos = newData.sectionPos; + + this.incrementSortTypeCounter(newData); + + // remove the section if the data doesn't need to trigger on face planes + if (newData instanceof DynamicData dynamicData) { + this.direct.removeSection(pos.asLong(), oldData); + this.decrementSortTypeCounter(oldData); + if (dynamicData.GFNITrigger) { + this.gfni.addSection(pos, dynamicData, cameraPos); + } else { + // remove the collector since this section is never going to get gfni triggering + // (there's no option to add sections to GFNI later currently) + dynamicData.deleteCollector(); + } + if (dynamicData.directTrigger) { + this.direct.addSection(pos, dynamicData, cameraPos); + } + + // clear trigger changes on data change because the current state of trigger + // types was just set + dynamicData.clearTriggerChanges(); + } else { + this.removeSection(oldData, pos.asLong()); + return; + } + } + + public void addDebugStrings(List list) { + list.add(String.format("TS NL=%02d TrN=%02d TrS=G%03d/D%03d", + this.gfni.getUniqueNormalCount(), + this.triggeredNormalCount, + this.gfniTriggerCount, + this.directTriggerCount)); + list.add(String.format("N=%05d SNR=%05d STA=%04d DYN=%04d (DIR=%04d)", + this.sortTypeCounters[SortType.NONE.ordinal()], + this.sortTypeCounters[SortType.STATIC_NORMAL_RELATIVE.ordinal()], + this.sortTypeCounters[SortType.STATIC_TOPO_ACYCLIC.ordinal()], + this.sortTypeCounters[SortType.DYNAMIC_ALL.ordinal()], + this.direct.getDirectTriggerCount())); + } +} From ac3d1de7101bac2e15b294880517228373c609c2 Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 6 Nov 2023 17:02:54 +0100 Subject: [PATCH 118/256] use a more reasonable linked list approach for direct trigger collisions --- .../render/chunk/gfni/DirectTriggers.java | 111 ++++++++---------- 1 file changed, 46 insertions(+), 65 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DirectTriggers.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DirectTriggers.java index ed9acd26da..4edaf54097 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DirectTriggers.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DirectTriggers.java @@ -57,6 +57,7 @@ private class DirectTriggerData { final ChunkSectionPos sectionPos; private Vector3dc sectionCenter; final DynamicData dynamicData; + DirectTriggerData next; /** * Absolute camera position at the time of the last trigger. @@ -108,45 +109,19 @@ private static double angleCos(double ax, double ay, double az, double bx, doubl private void insertDirectAngleTrigger(DirectTriggerData data, Vector3dc cameraPos, double remainingAngle) { double triggerCameraSectionCenterDist = data.getSectionCenterTriggerCameraDist(); double centerMinDistance = Math.tan(remainingAngle) * (triggerCameraSectionCenterDist - SECTION_CENTER_DIST); - this.insertJitteredTrigger(this.accumulatedDistance + centerMinDistance, data); + this.insertTrigger(this.accumulatedDistance + centerMinDistance, data); } private void insertDirectDistanceTrigger(DirectTriggerData data, Vector3dc cameraPos, double remainingDistance) { - this.insertJitteredTrigger(this.accumulatedDistance + remainingDistance, data); + this.insertTrigger(this.accumulatedDistance + remainingDistance, data); } - // TODO: instead of jittering use Tree where object is either a list or - // an individual record? - // jitters the double values to never overwrite the same key. abuses that - // doubles have more precision than we need to make them a kind of hash table - private double lastJittered = -1; - private double lastJitterResult = -1; - - private void insertJitteredTrigger(double key, DirectTriggerData data) { - // attempt insert without jittering - if (this.directTriggerSections.putIfAbsent(key, data) == null) { - data.dynamicData.directTriggerKey = key; - return; - } - - // if this is the same key as last time, skip all the identical keys that have - // already been jittered - if (this.lastJittered == key) { - key = this.lastJitterResult; - } else { - this.lastJittered = key; - } - - // Go to the next lower double to avoid collisions in the map. This slightly - // changes the key but doesn't significantly change its value. Subtraction is - // necessary to avoid delaying a trigger for too long. It's ok if it's too early - // though. This approach brings with it the disadvantages of linear probing but - // bad cases are unlikely to happen so it's fine. - do { - key = Math.nextDown(key); - } while (this.directTriggerSections.putIfAbsent(key, data) != null); + private void insertTrigger(double key, DirectTriggerData data) { data.dynamicData.directTriggerKey = key; - this.lastJitterResult = key; + + // attach the previous value after the current one in the list. if there is none + // it's just null + data.next = this.directTriggerSections.put(key, data); } @Override @@ -159,43 +134,49 @@ public void processTriggers(TranslucentSorting ts, CameraMovement movement) { var head = this.directTriggerSections.headMap(this.accumulatedDistance); for (var entry : head.double2ObjectEntrySet()) { this.directTriggerSections.remove(entry.getDoubleKey()); - DirectTriggerData data = entry.getValue(); - - boolean isAngle = data.isAngleTriggering(camera); - if (isAngle) { - double remainingAngle = TRIGGER_ANGLE; - - // check if the angle since the last sort exceeds the threshold - Vector3dc sectionCenter = data.getSectionCenter(); - double angleCos = angleCos( - sectionCenter.x() - data.triggerCameraPos.x(), - sectionCenter.y() - data.triggerCameraPos.y(), - sectionCenter.z() - data.triggerCameraPos.z(), - sectionCenter.x() - camera.x(), - sectionCenter.y() - camera.y(), - sectionCenter.z() - camera.z()); - - // compare angles inverted because cosine flips it - if (angleCos <= EARLY_TRIGGER_ANGLE_COS) { - ts.triggerSectionDirect(data.sectionPos); - data.triggerCameraPos = camera; + var data = entry.getValue(); + while (data != null) { + // get the next element before it's modified by the data being re-inserted into + // the tree + var next = data.next; + + if (data.isAngleTriggering(camera)) { + double remainingAngle = TRIGGER_ANGLE; + + // check if the angle since the last sort exceeds the threshold + Vector3dc sectionCenter = data.getSectionCenter(); + double angleCos = angleCos( + sectionCenter.x() - data.triggerCameraPos.x(), + sectionCenter.y() - data.triggerCameraPos.y(), + sectionCenter.z() - data.triggerCameraPos.z(), + sectionCenter.x() - camera.x(), + sectionCenter.y() - camera.y(), + sectionCenter.z() - camera.z()); + + // compare angles inverted because cosine flips it + if (angleCos <= EARLY_TRIGGER_ANGLE_COS) { + ts.triggerSectionDirect(data.sectionPos); + data.triggerCameraPos = camera; + } else { + remainingAngle -= Math.acos(angleCos); + } + + this.insertDirectAngleTrigger(data, camera, remainingAngle); } else { - remainingAngle -= Math.acos(angleCos); - } + double remainingDistance = DIRECT_TRIGGER_DISTANCE; + double lastTriggerCurrentCameraDistSquared = data.triggerCameraPos.distanceSquared(camera); - this.insertDirectAngleTrigger(data, camera, remainingAngle); - } else { - double remainingDistance = DIRECT_TRIGGER_DISTANCE; - double lastTriggerCurrentCameraDistSquared = data.triggerCameraPos.distanceSquared(camera); + if (lastTriggerCurrentCameraDistSquared >= EARLY_DIRECT_TRIGGER_DISTANCE_SQUARED) { + ts.triggerSectionDirect(data.sectionPos); + data.triggerCameraPos = camera; + } else { + remainingDistance -= Math.sqrt(lastTriggerCurrentCameraDistSquared); + } - if (lastTriggerCurrentCameraDistSquared >= EARLY_DIRECT_TRIGGER_DISTANCE_SQUARED) { - ts.triggerSectionDirect(data.sectionPos); - data.triggerCameraPos = camera; - } else { - remainingDistance -= Math.sqrt(lastTriggerCurrentCameraDistSquared); + this.insertDirectDistanceTrigger(data, camera, remainingDistance); } - this.insertDirectDistanceTrigger(data, camera, remainingDistance); + data = next; } } } From 3e83520ca752cf247db04e50e140621542343402 Mon Sep 17 00:00:00 2001 From: douira Date: Tue, 7 Nov 2023 19:37:44 +0100 Subject: [PATCH 119/256] documentation --- .../mods/sodium/client/render/chunk/gfni/DirectTriggers.java | 4 ++++ .../mods/sodium/client/render/chunk/gfni/GFNITriggers.java | 4 ++++ .../sodium/client/render/chunk/gfni/TranslucentSorting.java | 5 +++-- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DirectTriggers.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DirectTriggers.java index 4edaf54097..c9104f8d83 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DirectTriggers.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DirectTriggers.java @@ -7,6 +7,10 @@ import me.jellysquid.mods.sodium.client.render.chunk.gfni.TranslucentSorting.SectionTriggers; import net.minecraft.util.math.ChunkSectionPos; +/** + * Performs direct triggering for sections that can't (or shouldn't) be + * topologically sorted and thus aren't eligible for GFNI triggering. + */ class DirectTriggers implements SectionTriggers { /** * A tree map of the directly triggered sections, indexed by their diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNITriggers.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNITriggers.java index 01d0e7206b..18a36ce041 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNITriggers.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNITriggers.java @@ -7,6 +7,10 @@ import me.jellysquid.mods.sodium.client.render.chunk.gfni.TranslucentSorting.SectionTriggers; import net.minecraft.util.math.ChunkSectionPos; +/** + * Performs Global Face Normal Indexing-based triggering as described in + * https://hackmd.io/@douira100/sodium-sl-gfni + */ class GFNITriggers implements SectionTriggers { /** * A map of all the normal lists, indexed by their normal. diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentSorting.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentSorting.java index cb70a16580..e3b7df469c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentSorting.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentSorting.java @@ -9,8 +9,9 @@ import net.minecraft.util.math.ChunkSectionPos; /** - * Global Face Normal Indexing as described in - * https://hackmd.io/@douira100/sodium-sl-gfni + * This class is the central point in translucency sorting. It counts the number + * of translucent data objects for each sort type and delegates triggering of + * sections for dynamic sorting to the trigger components. * * Distances are stored as doubles and normals are stored as float vectors. * From 9eef8fbe34ae113bab70bd72ad5aa7da8dac2859 Mon Sep 17 00:00:00 2001 From: douira Date: Wed, 8 Nov 2023 03:18:05 +0100 Subject: [PATCH 120/256] fix separator plane selection breaking because of missing quantization on the plane distances --- .../render/chunk/gfni/TranslucentGeometryCollector.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java index 620900de31..3b43a828dd 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java @@ -203,8 +203,9 @@ public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] verti quadList.add(new TQuad(facing, accGroup.normal, center, extents)); } - var firstVertex = vertices[0]; - if (accGroup.addPlaneMember(firstVertex.x, firstVertex.y, firstVertex.z)) { + // use the center here because it's quantized while the vertices themselves + // aren't. If they were to be mixed this would cause issues in the sorting. + if (accGroup.addPlaneMember(centerX, centerY, centerZ)) { this.facePlaneCount++; } } From f86f80b9eee69b082e1170435c016bb71a22b57f Mon Sep 17 00:00:00 2001 From: douira Date: Wed, 8 Nov 2023 03:45:44 +0100 Subject: [PATCH 121/256] update documentation --- .../sodium/client/render/chunk/gfni/ComplexSorting.java | 9 +++++++++ .../sodium/client/render/chunk/gfni/GFNITriggers.java | 2 ++ .../client/render/chunk/gfni/TranslucentSorting.java | 6 ------ 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java index 576b3051da..b2df0ed62a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java @@ -9,6 +9,15 @@ import me.jellysquid.mods.sodium.client.util.collections.BitArray; import me.jellysquid.mods.sodium.client.util.sorting.MergeSort; +/** + * This class contains the sorting algorithms that do topological or distance + * sorting. The algorithms are combined in this class to separate them from the + * general management code in other classes. + * + * Rough attempts at underapproximation of the visibility graph where the + * conditions for visibility between quads are made more strict did not yield + * significantly more robust topo sorting. + */ public class ComplexSorting { private ComplexSorting() { } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNITriggers.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNITriggers.java index 18a36ce041..0a22326fa4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNITriggers.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNITriggers.java @@ -10,6 +10,8 @@ /** * Performs Global Face Normal Indexing-based triggering as described in * https://hackmd.io/@douira100/sodium-sl-gfni + * + * Distances are stored as doubles and normals are stored as float vectors. */ class GFNITriggers implements SectionTriggers { /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentSorting.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentSorting.java index e3b7df469c..c69b352d36 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentSorting.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentSorting.java @@ -13,8 +13,6 @@ * of translucent data objects for each sort type and delegates triggering of * sections for dynamic sorting to the trigger components. * - * Distances are stored as doubles and normals are stored as float vectors. - * * TODO: * - many sections can be marked as needing an update but they are only actually * scheduled for sorting when the RenderSectionManager makes them visible. This @@ -45,10 +43,6 @@ * - re-use distance sort data to accelerate future distance sorting. Sorting * mostly sorted data is probably faster than sorting unsorted data (or whatever * data comes out of the mesh). - * - investigate why a small epsilon of 0.001 makes many more sections sortable - * when it's added as a "slack" distance to the complex sorting's quad - * visibility check. This suggests that the quad visibility check or the - * quantization of vertex positions is not working correctly. * * @author douira */ From cbee8127367f8f3fa1e7bcd5dca4cd85a0f86799 Mon Sep 17 00:00:00 2001 From: douira Date: Thu, 16 Nov 2023 18:10:09 +0100 Subject: [PATCH 122/256] typo --- .../jellysquid/mods/sodium/client/render/chunk/gfni/Group.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java index 252ee52bba..29a67a4c6a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java @@ -6,7 +6,7 @@ /** * A group represents a set of face planes of the same normal within a section. - * A + * * group keeps a tree of its face plane distances to determine if it needs to be * triggered. */ From 90462a9f06570a35ed61a11297930f4b67c04177 Mon Sep 17 00:00:00 2001 From: douira Date: Thu, 16 Nov 2023 18:59:17 +0100 Subject: [PATCH 123/256] rename gfni package to translucent_sorting gfni is not appropriate as a name for the whole system as it's just a part of the whole thing --- .../mods/sodium/client/gui/SodiumGameOptions.java | 2 +- .../mods/sodium/client/model/quad/ModelQuadView.java | 2 +- .../mods/sodium/client/render/SodiumWorldRenderer.java | 2 +- .../mods/sodium/client/render/chunk/RenderSection.java | 2 +- .../sodium/client/render/chunk/RenderSectionManager.java | 6 +++--- .../client/render/chunk/compile/ChunkBuildOutput.java | 4 ++-- .../sodium/client/render/chunk/compile/ChunkSortOutput.java | 4 ++-- .../client/render/chunk/compile/OutputWithIndexData.java | 2 +- .../render/chunk/compile/pipeline/BlockRenderContext.java | 2 +- .../client/render/chunk/compile/pipeline/FluidRenderer.java | 2 +- .../render/chunk/compile/tasks/ChunkBuilderMeshingTask.java | 6 +++--- .../render/chunk/compile/tasks/ChunkBuilderSortingTask.java | 2 +- .../client/render/chunk/region/RenderRegionManager.java | 3 ++- .../{gfni => translucent_sorting}/AccumulationGroup.java | 2 +- .../chunk/{gfni => translucent_sorting}/AnyOrderData.java | 2 +- .../chunk/{gfni => translucent_sorting}/CameraMovement.java | 2 +- .../chunk/{gfni => translucent_sorting}/ComplexSorting.java | 2 +- .../chunk/{gfni => translucent_sorting}/DirectTriggers.java | 4 ++-- .../chunk/{gfni => translucent_sorting}/DynamicData.java | 2 +- .../chunk/{gfni => translucent_sorting}/GFNITriggers.java | 4 ++-- .../render/chunk/{gfni => translucent_sorting}/Group.java | 2 +- .../{gfni => translucent_sorting}/MixedDirectionData.java | 2 +- .../render/chunk/{gfni => translucent_sorting}/NoData.java | 2 +- .../chunk/{gfni => translucent_sorting}/NormalList.java | 2 +- .../PresentTranslucentData.java | 2 +- .../chunk/{gfni => translucent_sorting}/SortType.java | 2 +- .../{gfni => translucent_sorting}/SplitDirectionData.java | 2 +- .../StaticNormalRelativeData.java | 2 +- .../StaticTopoAcyclicData.java | 2 +- .../render/chunk/{gfni => translucent_sorting}/TQuad.java | 2 +- .../{gfni => translucent_sorting}/TranslucentData.java | 2 +- .../TranslucentGeometryCollector.java | 2 +- .../{gfni => translucent_sorting}/TranslucentSorting.java | 2 +- 33 files changed, 42 insertions(+), 41 deletions(-) rename src/main/java/me/jellysquid/mods/sodium/client/render/chunk/{gfni => translucent_sorting}/AccumulationGroup.java (96%) rename src/main/java/me/jellysquid/mods/sodium/client/render/chunk/{gfni => translucent_sorting}/AnyOrderData.java (96%) rename src/main/java/me/jellysquid/mods/sodium/client/render/chunk/{gfni => translucent_sorting}/CameraMovement.java (59%) rename src/main/java/me/jellysquid/mods/sodium/client/render/chunk/{gfni => translucent_sorting}/ComplexSorting.java (99%) rename src/main/java/me/jellysquid/mods/sodium/client/render/chunk/{gfni => translucent_sorting}/DirectTriggers.java (97%) rename src/main/java/me/jellysquid/mods/sodium/client/render/chunk/{gfni => translucent_sorting}/DynamicData.java (98%) rename src/main/java/me/jellysquid/mods/sodium/client/render/chunk/{gfni => translucent_sorting}/GFNITriggers.java (94%) rename src/main/java/me/jellysquid/mods/sodium/client/render/chunk/{gfni => translucent_sorting}/Group.java (97%) rename src/main/java/me/jellysquid/mods/sodium/client/render/chunk/{gfni => translucent_sorting}/MixedDirectionData.java (91%) rename src/main/java/me/jellysquid/mods/sodium/client/render/chunk/{gfni => translucent_sorting}/NoData.java (87%) rename src/main/java/me/jellysquid/mods/sodium/client/render/chunk/{gfni => translucent_sorting}/NormalList.java (98%) rename src/main/java/me/jellysquid/mods/sodium/client/render/chunk/{gfni => translucent_sorting}/PresentTranslucentData.java (95%) rename src/main/java/me/jellysquid/mods/sodium/client/render/chunk/{gfni => translucent_sorting}/SortType.java (96%) rename src/main/java/me/jellysquid/mods/sodium/client/render/chunk/{gfni => translucent_sorting}/SplitDirectionData.java (90%) rename src/main/java/me/jellysquid/mods/sodium/client/render/chunk/{gfni => translucent_sorting}/StaticNormalRelativeData.java (98%) rename src/main/java/me/jellysquid/mods/sodium/client/render/chunk/{gfni => translucent_sorting}/StaticTopoAcyclicData.java (94%) rename src/main/java/me/jellysquid/mods/sodium/client/render/chunk/{gfni => translucent_sorting}/TQuad.java (95%) rename src/main/java/me/jellysquid/mods/sodium/client/render/chunk/{gfni => translucent_sorting}/TranslucentData.java (97%) rename src/main/java/me/jellysquid/mods/sodium/client/render/chunk/{gfni => translucent_sorting}/TranslucentGeometryCollector.java (99%) rename src/main/java/me/jellysquid/mods/sodium/client/render/chunk/{gfni => translucent_sorting}/TranslucentSorting.java (99%) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java index 54e56dc409..ec79775ffc 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java @@ -5,7 +5,7 @@ import com.google.gson.GsonBuilder; import com.google.gson.annotations.SerializedName; import me.jellysquid.mods.sodium.client.gui.options.TextProvider; -import me.jellysquid.mods.sodium.client.render.chunk.gfni.SortType; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortType; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.client.option.GraphicsMode; import net.minecraft.text.Text; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java index 82e55c0fe0..7390499c86 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.model.quad; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFlags; -import me.jellysquid.mods.sodium.client.render.chunk.gfni.TranslucentSorting; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TranslucentSorting; import net.caffeinemc.mods.sodium.api.util.NormI8; import net.minecraft.client.texture.Sprite; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index 8edd81cabb..36485b3cb4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -7,12 +7,12 @@ import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; import me.jellysquid.mods.sodium.client.render.chunk.ChunkRenderMatrices; import me.jellysquid.mods.sodium.client.render.chunk.RenderSectionManager; -import me.jellysquid.mods.sodium.client.render.chunk.gfni.CameraMovement; import me.jellysquid.mods.sodium.client.render.chunk.lists.ChunkRenderList; import me.jellysquid.mods.sodium.client.render.chunk.lists.SortedRenderLists; import me.jellysquid.mods.sodium.client.render.chunk.map.ChunkTracker; import me.jellysquid.mods.sodium.client.render.chunk.map.ChunkTrackerHolder; import me.jellysquid.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.CameraMovement; import me.jellysquid.mods.sodium.client.render.viewport.Viewport; import me.jellysquid.mods.sodium.client.util.NativeBuffer; import me.jellysquid.mods.sodium.client.world.WorldRendererExtended; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java index 9391bbba79..2a39205b2f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java @@ -1,11 +1,11 @@ package me.jellysquid.mods.sodium.client.render.chunk; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionInfo; -import me.jellysquid.mods.sodium.client.render.chunk.gfni.TranslucentData; import me.jellysquid.mods.sodium.client.render.chunk.occlusion.GraphDirection; import me.jellysquid.mods.sodium.client.render.chunk.occlusion.GraphDirectionSet; import me.jellysquid.mods.sodium.client.render.chunk.occlusion.VisibilityEncoding; import me.jellysquid.mods.sodium.client.render.chunk.region.RenderRegion; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TranslucentData; import me.jellysquid.mods.sodium.client.util.task.CancellationToken; import net.minecraft.block.entity.BlockEntity; import net.minecraft.client.texture.Sprite; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index aea446092e..b4ee799bea 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -21,9 +21,6 @@ import me.jellysquid.mods.sodium.client.render.chunk.compile.tasks.ChunkBuilderSortingTask; import me.jellysquid.mods.sodium.client.render.chunk.compile.tasks.ChunkBuilderTask; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionInfo; -import me.jellysquid.mods.sodium.client.render.chunk.gfni.CameraMovement; -import me.jellysquid.mods.sodium.client.render.chunk.gfni.TranslucentSorting; -import me.jellysquid.mods.sodium.client.render.chunk.gfni.TranslucentData; import me.jellysquid.mods.sodium.client.render.chunk.lists.ChunkRenderList; import me.jellysquid.mods.sodium.client.render.chunk.lists.SortedRenderLists; import me.jellysquid.mods.sodium.client.render.chunk.lists.VisibleChunkCollector; @@ -32,6 +29,9 @@ import me.jellysquid.mods.sodium.client.render.chunk.region.RenderRegion; import me.jellysquid.mods.sodium.client.render.chunk.region.RenderRegionManager; import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.CameraMovement; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TranslucentData; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TranslucentSorting; import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkMeshFormats; import me.jellysquid.mods.sodium.client.render.texture.SpriteUtil; import me.jellysquid.mods.sodium.client.render.viewport.CameraTransform; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java index 690d56df6a..070c5acd56 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java @@ -2,9 +2,9 @@ import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.PresentTranslucentData; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TranslucentData; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; -import me.jellysquid.mods.sodium.client.render.chunk.gfni.PresentTranslucentData; -import me.jellysquid.mods.sodium.client.render.chunk.gfni.TranslucentData; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionInfo; import java.util.Map; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java index a83265134b..eab1e04961 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java @@ -1,8 +1,8 @@ package me.jellysquid.mods.sodium.client.render.chunk.compile; import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; -import me.jellysquid.mods.sodium.client.render.chunk.gfni.DynamicData; -import me.jellysquid.mods.sodium.client.render.chunk.gfni.PresentTranslucentData; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.DynamicData; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.PresentTranslucentData; public class ChunkSortOutput extends BuilderTaskOutput implements OutputWithIndexData { public final DynamicData dynamicData; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/OutputWithIndexData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/OutputWithIndexData.java index 0c456df40e..e66207f9cf 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/OutputWithIndexData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/OutputWithIndexData.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.render.chunk.compile; -import me.jellysquid.mods.sodium.client.render.chunk.gfni.PresentTranslucentData; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.PresentTranslucentData; public interface OutputWithIndexData { PresentTranslucentData getTranslucentData(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderContext.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderContext.java index 7c14942e86..9741ae8923 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderContext.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderContext.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline; -import me.jellysquid.mods.sodium.client.render.chunk.gfni.TranslucentGeometryCollector; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TranslucentGeometryCollector; import me.jellysquid.mods.sodium.client.world.WorldSlice; import net.minecraft.block.BlockState; import net.minecraft.client.render.model.BakedModel; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java index 07ad402e38..2e76852cb5 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java @@ -14,9 +14,9 @@ import me.jellysquid.mods.sodium.client.model.color.DefaultColorProviders; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildBuffers; import me.jellysquid.mods.sodium.client.render.chunk.compile.buffers.ChunkModelBuilder; -import me.jellysquid.mods.sodium.client.render.chunk.gfni.TranslucentGeometryCollector; import me.jellysquid.mods.sodium.client.render.chunk.terrain.material.DefaultMaterials; import me.jellysquid.mods.sodium.client.render.chunk.terrain.material.Material; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TranslucentGeometryCollector; import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexEncoder; import me.jellysquid.mods.sodium.client.world.WorldSlice; import me.jellysquid.mods.sodium.client.util.DirectionUtil; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java index ea4ae632bf..58ed3e998d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java @@ -11,11 +11,11 @@ import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.BlockRenderContext; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionInfo; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; -import me.jellysquid.mods.sodium.client.render.chunk.gfni.TranslucentGeometryCollector; -import me.jellysquid.mods.sodium.client.render.chunk.gfni.SortType; -import me.jellysquid.mods.sodium.client.render.chunk.gfni.TranslucentData; import me.jellysquid.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses; import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortType; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TranslucentData; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TranslucentGeometryCollector; import me.jellysquid.mods.sodium.client.util.task.CancellationToken; import me.jellysquid.mods.sodium.client.world.WorldSlice; import me.jellysquid.mods.sodium.client.world.cloned.ChunkRenderContext; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java index 93a393474c..71cf468f66 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java @@ -5,7 +5,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildContext; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkSortOutput; -import me.jellysquid.mods.sodium.client.render.chunk.gfni.DynamicData; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.DynamicData; import me.jellysquid.mods.sodium.client.util.task.CancellationToken; public class ChunkBuilderSortingTask extends ChunkBuilderTask { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java index b86680b28d..5051140cae 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java @@ -15,9 +15,10 @@ import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildOutput; import me.jellysquid.mods.sodium.client.render.chunk.compile.OutputWithIndexData; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; -import me.jellysquid.mods.sodium.client.render.chunk.gfni.PresentTranslucentData; import me.jellysquid.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses; import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.PresentTranslucentData; + import org.jetbrains.annotations.NotNull; import java.util.*; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AccumulationGroup.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AccumulationGroup.java similarity index 96% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AccumulationGroup.java rename to src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AccumulationGroup.java index 34708f6bce..3eac1ed2fd 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AccumulationGroup.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AccumulationGroup.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.gfni; +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; import org.joml.Vector3fc; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AnyOrderData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AnyOrderData.java similarity index 96% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AnyOrderData.java rename to src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AnyOrderData.java index 498d6534e5..dc6163530f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/AnyOrderData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AnyOrderData.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.gfni; +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; import me.jellysquid.mods.sodium.client.gl.util.VertexRange; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/CameraMovement.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/CameraMovement.java similarity index 59% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/CameraMovement.java rename to src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/CameraMovement.java index 0aa85d5096..9c678c40ed 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/CameraMovement.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/CameraMovement.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.gfni; +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; import org.joml.Vector3dc; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/ComplexSorting.java similarity index 99% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java rename to src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/ComplexSorting.java index b2df0ed62a..83f6bd322b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/ComplexSorting.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/ComplexSorting.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.gfni; +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; import java.nio.IntBuffer; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DirectTriggers.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/DirectTriggers.java similarity index 97% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DirectTriggers.java rename to src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/DirectTriggers.java index c9104f8d83..858de48bc3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DirectTriggers.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/DirectTriggers.java @@ -1,10 +1,10 @@ -package me.jellysquid.mods.sodium.client.render.chunk.gfni; +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; import org.joml.Vector3d; import org.joml.Vector3dc; import it.unimi.dsi.fastutil.doubles.Double2ObjectRBTreeMap; -import me.jellysquid.mods.sodium.client.render.chunk.gfni.TranslucentSorting.SectionTriggers; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TranslucentSorting.SectionTriggers; import net.minecraft.util.math.ChunkSectionPos; /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/DynamicData.java similarity index 98% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java rename to src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/DynamicData.java index ba4b999920..2b035a1187 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/DynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/DynamicData.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.gfni; +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; import java.nio.IntBuffer; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNITriggers.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/GFNITriggers.java similarity index 94% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNITriggers.java rename to src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/GFNITriggers.java index 0a22326fa4..f81f825067 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/GFNITriggers.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/GFNITriggers.java @@ -1,10 +1,10 @@ -package me.jellysquid.mods.sodium.client.render.chunk.gfni; +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; import org.joml.Vector3dc; import org.joml.Vector3fc; import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; -import me.jellysquid.mods.sodium.client.render.chunk.gfni.TranslucentSorting.SectionTriggers; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TranslucentSorting.SectionTriggers; import net.minecraft.util.math.ChunkSectionPos; /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/Group.java similarity index 97% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java rename to src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/Group.java index 29a67a4c6a..b2f893e9bb 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/Group.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/Group.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.gfni; +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; import com.lodborg.intervaltree.DoubleInterval; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/MixedDirectionData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/MixedDirectionData.java similarity index 91% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/MixedDirectionData.java rename to src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/MixedDirectionData.java index 98e02e8385..2bb5015f58 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/MixedDirectionData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/MixedDirectionData.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.gfni; +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; import me.jellysquid.mods.sodium.client.gl.util.VertexRange; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NoData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/NoData.java similarity index 87% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NoData.java rename to src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/NoData.java index d474c347a9..ed32276a1e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NoData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/NoData.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.gfni; +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; import net.minecraft.util.math.ChunkSectionPos; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/NormalList.java similarity index 98% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java rename to src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/NormalList.java index d631855dc6..ba9a49b63d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/NormalList.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/NormalList.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.gfni; +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; import java.util.Collection; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/PresentTranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/PresentTranslucentData.java similarity index 95% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/PresentTranslucentData.java rename to src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/PresentTranslucentData.java index e0151df08c..745d46c11e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/PresentTranslucentData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/PresentTranslucentData.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.gfni; +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; import me.jellysquid.mods.sodium.client.gl.util.VertexRange; import me.jellysquid.mods.sodium.client.util.NativeBuffer; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/SortType.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SortType.java similarity index 96% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/SortType.java rename to src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SortType.java index eb938f4cbc..70e562555b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/SortType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SortType.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.gfni; +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; /** * What type of sorting to use for a section. Calculated by a heuristic after diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/SplitDirectionData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SplitDirectionData.java similarity index 90% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/SplitDirectionData.java rename to src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SplitDirectionData.java index a82d03f627..97c543c47b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/SplitDirectionData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SplitDirectionData.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.gfni; +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; import me.jellysquid.mods.sodium.client.gl.util.VertexRange; import me.jellysquid.mods.sodium.client.util.NativeBuffer; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/StaticNormalRelativeData.java similarity index 98% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java rename to src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/StaticNormalRelativeData.java index 31683bde86..175014a02e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticNormalRelativeData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/StaticNormalRelativeData.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.gfni; +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; import java.nio.IntBuffer; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/StaticTopoAcyclicData.java similarity index 94% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java rename to src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/StaticTopoAcyclicData.java index e4692f6eea..1749d79010 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/StaticTopoAcyclicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/StaticTopoAcyclicData.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.gfni; +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; import me.jellysquid.mods.sodium.client.gl.util.VertexRange; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TQuad.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java similarity index 95% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TQuad.java rename to src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java index e2c03a7953..de0b1a469f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TQuad.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.gfni; +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; import java.util.Arrays; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentData.java similarity index 97% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java rename to src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentData.java index 7b424fb4dd..955b3301aa 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentData.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.gfni; +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; import java.nio.IntBuffer; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java similarity index 99% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java rename to src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java index 3b43a828dd..c10e9f080e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentGeometryCollector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.gfni; +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; import org.joml.Vector3f; import org.joml.Vector3fc; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentSorting.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentSorting.java similarity index 99% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentSorting.java rename to src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentSorting.java index c69b352d36..aac3c1db79 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/gfni/TranslucentSorting.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentSorting.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.gfni; +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; import java.util.List; import java.util.function.BiConsumer; From 34361aa8f84c565713e1dc8c3b3a71b043e5b2c4 Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 17 Nov 2023 01:20:42 +0100 Subject: [PATCH 124/256] fix separator condition --- .../translucent_sorting/ComplexSorting.java | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/ComplexSorting.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/ComplexSorting.java index 83f6bd322b..eb37199665 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/ComplexSorting.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/ComplexSorting.java @@ -297,7 +297,11 @@ private static boolean visibilityWithSeparator(TQuad quadA, TQuad quadB, var oppositeDirection = oppositeFacing.ordinal(); var sign = facing.getSign(); - // test that they're not overlapping in this direction + // test that they're not overlapping in this direction. Multiplication with the + // sign makes the > work in the other direction which is necessary since the + // facing turns the whole space around. The start and end are ordered along the + // < relation as is the normal. The normal always points in the direction of + // greater values, even if all of the geometry has negative values. var separatorRangeStart = sign * quadB.extents()[direction]; var separatorRangeEnd = sign * quadA.extents()[oppositeDirection]; if (separatorRangeStart > separatorRangeEnd) { @@ -311,13 +315,19 @@ private static boolean visibilityWithSeparator(TQuad quadA, TQuad quadB, continue; } - // restrict the separator range start to the camera distance - separatorRangeStart = Math.max(separatorRangeStart, cameraDistance); + // use camera distance as the start because even if there's no geometry that + // generates such separator plane itself, if there's any plane that triggers the + // section before the camera can see B through A this is enough. The separator + // doesn't need to be between B and A if the camera will cross another separator + // before any separator that could be between B and A. + separatorRangeStart = cameraDistance; + + // swapping the start and end is not necessary since the start is always smaller + // than the end value. // test if there is a separator plane that is outside/on the surface of the - // current trigger volume - if (testSeparatorRange(distancesByNormal, facingNormal, - separatorRangeStart, separatorRangeEnd)) { + // current trigger volume. + if (testSeparatorRange(distancesByNormal, facingNormal, separatorRangeStart, separatorRangeEnd)) { return false; } } From 455dd9c194602ae89c8c7f130264f77b760d7b0c Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 17 Nov 2023 02:27:54 +0100 Subject: [PATCH 125/256] refactor fast sorting mode to not use static topo sorting at all --- .../sodium/client/gui/SodiumGameOptions.java | 24 ++++--------------- .../TranslucentGeometryCollector.java | 20 ++++++++++++---- .../resources/assets/sodium/lang/en_us.json | 2 +- 3 files changed, 20 insertions(+), 26 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java index ec79775ffc..9d37a40a7a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java @@ -5,7 +5,6 @@ import com.google.gson.GsonBuilder; import com.google.gson.annotations.SerializedName; import me.jellysquid.mods.sodium.client.gui.options.TextProvider; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortType; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.client.option.GraphicsMode; import net.minecraft.text.Text; @@ -16,8 +15,6 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; -import java.util.Set; -import java.util.EnumSet; public class SodiumGameOptions { private static final String DEFAULT_FILE_NAME = "sodium-options.json"; @@ -53,33 +50,20 @@ public static class PerformanceSettings { } public enum SortBehavior implements TextProvider { - OFF("options.off", Set.of(SortType.NONE)), - STATIC("options.clouds.fast", getUpTo(SortType.STATIC_TOPO_ACYCLIC)), - DYNAMIC("options.clouds.fancy", getUpTo(SortType.DYNAMIC_ALL)); + OFF("options.off"), + STATIC("options.clouds.fast"), + DYNAMIC("options.clouds.fancy"); private final Text name; - public final Set sortTypes; - SortBehavior(String name, Set sortTypes) { + SortBehavior(String name) { this.name = Text.translatable(name); - this.sortTypes = sortTypes; } @Override public Text getLocalizedName() { return this.name; } - - private static final Set getUpTo(SortType sortType) { - var set = EnumSet.noneOf(SortType.class); - for (var type : SortType.values()) { - set.add(type); - if (type == sortType) { - break; - } - } - return set; - } } public static class AdvancedSettings { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java index c10e9f080e..5ee25edaf6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java @@ -218,10 +218,20 @@ public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] verti */ private static SortType filterSortType(SortType sortType) { SortBehavior sortBehavior = SodiumClientMod.options().performance.sortBehavior; - if (!sortBehavior.sortTypes.contains(sortType)) { - return SortType.NONE; + switch (sortBehavior) { + case OFF: + return SortType.NONE; + case STATIC: + if (sortType == SortType.NONE) { + return sortType; + } else { + return SortType.STATIC_NORMAL_RELATIVE; + } + case DYNAMIC: + return sortType; + default: + throw new IllegalStateException("Unknown sort behavior: " + sortBehavior); } - return sortType; } /** @@ -377,7 +387,7 @@ public SortType finishRendering() { return this.sortType; } - private TranslucentData getTranslucentDataNew(BuiltSectionMeshParts translucentMesh, Vector3fc cameraPos) { + private TranslucentData makeNewTranslucentData(BuiltSectionMeshParts translucentMesh, Vector3fc cameraPos) { if (this.sortType == SortType.NONE) { return AnyOrderData.fromMesh(translucentMesh, quads, sectionPos, null); } @@ -455,7 +465,7 @@ public TranslucentData getTranslucentData( } } - var newData = getTranslucentDataNew(translucentMesh, cameraPos); + var newData = makeNewTranslucentData(translucentMesh, cameraPos); if (newData instanceof PresentTranslucentData presentData) { presentData.setQuadHash(getQuadHash(this.quads)); } diff --git a/src/main/resources/assets/sodium/lang/en_us.json b/src/main/resources/assets/sodium/lang/en_us.json index d18489fd66..d0685f7c28 100644 --- a/src/main/resources/assets/sodium/lang/en_us.json +++ b/src/main/resources/assets/sodium/lang/en_us.json @@ -61,5 +61,5 @@ "sodium.console.core_shaders_warn": "The following resource packs may be incompatible with Sodium:", "sodium.console.core_shaders_info": "Check the game log for detailed information.", "sodium.options.sort_behavior.name": "Translucency Sorting", - "sodium.options.sort_behavior.tooltip": "Controls when and with how much effort translucency sorting is performed. Fast only performs sorting when the chunk it loaded. Only Fancy sorting ensures correct sorting all the time and you may see glitches otherwise. More sorting has a performance impact on chunk loading speeds, but usually not frame rates." + "sodium.options.sort_behavior.tooltip": "Controls when and with how much effort translucency sorting is performed. Fancy attempts correct sorting everywhere while in Fast mode there may be glitches. More sorting has a performance impact on chunk loading speeds, but usually not frame rates." } From 57535a65b41d449b8f5ab98969f711659649c5e0 Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 17 Nov 2023 02:51:09 +0100 Subject: [PATCH 126/256] fix concurrent modification of normal list map --- .../translucent_sorting/GFNITriggers.java | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/GFNITriggers.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/GFNITriggers.java index f81f825067..f187da2b86 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/GFNITriggers.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/GFNITriggers.java @@ -40,17 +40,25 @@ private void addSectionInNewNormalLists(DynamicData dynamicData, AccumulationGro } } - private void removeSectionFromList(NormalList normalList, long sectionPos) { + /** + * Removes the section from the normal list and returns whether the normal list + * is now empty and should itself be removed from the normal lists map. This is + * done with a return value so that the iterator can be used to remove it safely + * without a concurrent modification. + */ + private boolean removeSectionFromList(NormalList normalList, long sectionPos) { normalList.removeSection(sectionPos); - if (normalList.isEmpty()) { - this.normalLists.remove(normalList.getNormal()); - } + return normalList.isEmpty(); } @Override public void removeSection(long sectionPos, TranslucentData data) { - for (var normalList : this.normalLists.values()) { - this.removeSectionFromList(normalList, sectionPos); + var iterator = this.normalLists.values().iterator(); + while (iterator.hasNext()) { + var normalList = iterator.next(); + if (this.removeSectionFromList(normalList, sectionPos)) { + iterator.remove(); + } } } @@ -62,12 +70,17 @@ public void addSection(ChunkSectionPos pos, DynamicData data, Vector3dc cameraPo // go through all normal lists and check against the normals that the group // builder has. if the normal list has data for the section, but the group // builder doesn't, the group is removed. otherwise, the group is updated. - for (var normalList : this.normalLists.values()) { + var iterator = this.normalLists.values().iterator(); + while (iterator.hasNext()) { + var normalList = iterator.next(); + // check if the geometry collector includes data for this normal. var accGroup = collector.getGroupForNormal(normalList); if (normalList.hasSection(sectionPos)) { if (accGroup == null) { - this.removeSectionFromList(normalList, sectionPos); + if (this.removeSectionFromList(normalList, sectionPos)) { + iterator.remove(); + } } else { normalList.updateSection(accGroup, sectionPos); } From 0fc65737ba62710b0980fa6454334361ba29ed2e Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 17 Nov 2023 03:47:13 +0100 Subject: [PATCH 127/256] fix slow initial sorts throwing off the heuristic, and slow sort protection breaking sections into never being triggered at all --- .../translucent_sorting/DynamicData.java | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/DynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/DynamicData.java index 2b035a1187..1458a900c5 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/DynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/DynamicData.java @@ -53,7 +53,7 @@ public void prepareTrigger(boolean isAngleTrigger) { @Override public void sortOnTrigger(Vector3fc cameraPos) { - this.sort(cameraPos, this.pendingTriggerIsAngle); + this.sort(cameraPos, this.pendingTriggerIsAngle, false); } private void turnGFNITriggerOff() { @@ -81,7 +81,7 @@ private static int getAttemptsForTime(long ns) { return ns <= MAX_TOPO_SORT_PATIENT_TIME_NS ? PATIENT_TOPO_ATTEMPTS : REGULAR_TOPO_ATTEMPTS; } - private void sort(Vector3fc cameraPos, boolean isAngleTrigger) { + private void sort(Vector3fc cameraPos, boolean isAngleTrigger, boolean initial) { // mark as not being reused to ensure the updated buffer is actually uploaded this.unsetReuseUploadedData(); @@ -94,23 +94,24 @@ private void sort(Vector3fc cameraPos, boolean isAngleTrigger) { } if (this.GFNITrigger && !isAngleTrigger) { - var sortStart = System.nanoTime(); + var sortStart = initial ? 0 : System.nanoTime(); var result = ComplexSorting.topoSortDepthFirstCyclic( indexBuffer, this.quads, this.distancesByNormal, cameraPos); - var sortTime = System.nanoTime() - sortStart; + var sortTime = initial ? 0 : System.nanoTime() - sortStart; // if we've already failed, there's reduced patience for sorting since the - // probability of failure and wasted compute time is higher - if (sortTime > (this.consecutiveTopoSortFailures > 0 + // probability of failure and wasted compute time is higher. Initial sorting is + // often very slow when the cpu is loaded and the JIT isn't ready yet, so it's + // ignored here. + if (!initial && sortTime > (this.consecutiveTopoSortFailures > 0 ? MAX_FAILING_TOPO_SORT_TIME_NS : MAX_TOPO_SORT_TIME_NS)) { this.turnGFNITriggerOff(); this.turnDirectTriggerOn(); - } - - if (result) { + System.out.println("topo sort took too long"); + } else if (result) { // disable distance sorting because topo sort seems to be possible. this.turnDirectTriggerOff(); this.consecutiveTopoSortFailures = 0; @@ -154,7 +155,8 @@ void deleteCollector() { } static DynamicData fromMesh(BuiltSectionMeshParts translucentMesh, - Vector3fc cameraPos, TQuad[] quads, ChunkSectionPos sectionPos, TranslucentGeometryCollector collector, NativeBuffer buffer) { + Vector3fc cameraPos, TQuad[] quads, ChunkSectionPos sectionPos, TranslucentGeometryCollector collector, + NativeBuffer buffer) { // prepare accumulation groups for GFNI integration and copy var size = 0; if (collector.axisAlignedDistances != null) { @@ -188,7 +190,7 @@ static DynamicData fromMesh(BuiltSectionMeshParts translucentMesh, var dynamicData = new DynamicData(sectionPos, buffer, range, quads, collector, distancesByNormal); - dynamicData.sort(cameraPos, false); + dynamicData.sort(cameraPos, false, true); return dynamicData; } From 244c7aed7ea2643a2ae134fe7503b2de17a2dc62 Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 17 Nov 2023 17:21:50 +0100 Subject: [PATCH 128/256] keep distance sorting indices around for faster re-sorting, keep a keys array around to avoid re-allocating each time --- .../translucent_sorting/ComplexSorting.java | 28 +++++++++++++------ .../translucent_sorting/DynamicData.java | 6 +++- .../TranslucentSorting.java | 3 -- .../sodium/client/util/sorting/MergeSort.java | 2 +- 4 files changed, 26 insertions(+), 13 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/ComplexSorting.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/ComplexSorting.java index eb37199665..ef5b99a1bc 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/ComplexSorting.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/ComplexSorting.java @@ -45,19 +45,31 @@ private static boolean pointInsideHalfSpace(Vector3fc planeAnchor, Vector3fc pla return halfspace(planeAnchor, planeNormal, point) < 0; } - private static int[] distanceSortIndexes(TQuad[] quads, Vector3fc cameraPos) { - float[] keys = new float[quads.length]; + private static ThreadLocal distanceSortKeys = new ThreadLocal<>(); + + public static int[] distanceSortDirect(int[] indexes, + IntBuffer indexBuffer, TQuad[] quads, Vector3fc cameraPos) { + if (indexes == null) { + indexes = new int[quads.length]; + for (int i = 0; i < quads.length; i++) { + indexes[i] = i; + } + } + + float[] keys = distanceSortKeys.get(); + if (keys == null || keys.length < quads.length) { + keys = new float[quads.length]; + distanceSortKeys.set(keys); + } + for (int i = 0; i < quads.length; i++) { keys[i] = cameraPos.distanceSquared(quads[i].center()); } - // TODO: use sort algorithm other than merge sort - return MergeSort.mergeSort(keys); - } - - public static void distanceSortDirect(IntBuffer indexBuffer, TQuad[] quads, Vector3fc cameraPos) { - var indexes = distanceSortIndexes(quads, cameraPos); + MergeSort.mergeSort(indexes, keys); TranslucentData.writeQuadVertexIndexes(indexBuffer, indexes); + + return indexes; } private static boolean orthogonalQuadVisibleThrough(TQuad halfspace, TQuad otherQuad) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/DynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/DynamicData.java index 1458a900c5..1bfe511a0a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/DynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/DynamicData.java @@ -23,6 +23,7 @@ public class DynamicData extends MixedDirectionData { private boolean pendingTriggerIsAngle; private TranslucentGeometryCollector collector; private Object2ReferenceOpenHashMap distancesByNormal; + private int[] distanceSortIndexes; private static final int MAX_TOPO_SORT_QUADS = 1000; private static final int MAX_TOPO_SORT_TIME_NS = 1_000_000; @@ -75,6 +76,7 @@ private void turnDirectTriggerOff() { this.directTrigger = false; this.turnDirectTriggerOff = true; } + this.distanceSortIndexes = null; } private static int getAttemptsForTime(long ns) { @@ -129,9 +131,11 @@ private void sort(Vector3fc cameraPos, boolean isAngleTrigger, boolean initial) this.turnDirectTriggerOn(); } } + if (this.directTrigger) { indexBuffer.rewind(); - ComplexSorting.distanceSortDirect(indexBuffer, this.quads, cameraPos); + this.distanceSortIndexes = ComplexSorting.distanceSortDirect( + this.distanceSortIndexes, indexBuffer, this.quads, cameraPos); return; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentSorting.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentSorting.java index aac3c1db79..6eb5ebb5d7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentSorting.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentSorting.java @@ -40,9 +40,6 @@ * - determine the right distance for angle/distance triggering. It seems just * the diagonal of a section is too small, angle triggering is broken at close * distances. - * - re-use distance sort data to accelerate future distance sorting. Sorting - * mostly sorted data is probably faster than sorting unsorted data (or whatever - * data comes out of the mesh). * * @author douira */ diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/MergeSort.java b/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/MergeSort.java index 5333d6490a..c9b4d69104 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/MergeSort.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/MergeSort.java @@ -42,7 +42,7 @@ public static int[] mergeSort(float[] keys) { return indices; } - private static void mergeSort(final int[] indices, final float[] keys) { + public static void mergeSort(final int[] indices, final float[] keys) { mergeSort(indices, keys, 0, indices.length, null); } From 84e4c3de10e89a7b773825fd4bca0925cedf85b7 Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 17 Nov 2023 19:00:39 +0100 Subject: [PATCH 129/256] use better quad hashing algorithm --- .../chunk/translucent_sorting/TQuad.java | 42 ++++--------------- .../TranslucentGeometryCollector.java | 5 ++- .../TranslucentSorting.java | 7 ---- 3 files changed, 12 insertions(+), 42 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java index de0b1a469f..afb28f8f68 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java @@ -15,40 +15,16 @@ * correctly compared.. */ record TQuad(ModelQuadFacing facing, Vector3fc normal, Vector3f center, float[] extents) { - @Override - public int hashCode() { - final int prime = 31; + int getQuadHash() { + // the hash code needs to be particularly collision resistant int result = 1; - result = prime * result + ((facing == null) ? 0 : facing.hashCode()); - result = prime * result + ((normal == null) ? 0 : normal.hashCode()); - result = prime * result + ((center == null) ? 0 : center.hashCode()); - result = prime * result + Arrays.hashCode(extents); + result = 31 * result + Arrays.hashCode(this.extents); + if (facing == ModelQuadFacing.UNASSIGNED) { + result = 31 * result + this.facing.hashCode(); + } else { + result = 31 * result + this.normal.hashCode(); + } + result = 31 * result + this.center.hashCode(); return result; } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - TQuad other = (TQuad) obj; - if (facing != other.facing) - return false; - if (normal == null) { - if (other.normal != null) - return false; - } else if (!normal.equals(other.normal)) - return false; - if (center == null) { - if (other.center != null) - return false; - } else if (!center.equals(other.center)) - return false; - if (!Arrays.equals(extents, other.extents)) - return false; - return true; - } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java index 5ee25edaf6..397d24e3ed 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java @@ -426,8 +426,9 @@ private int getQuadHash(TQuad[] quads) { return this.quadHash; } - for (TQuad quad : quads) { - this.quadHash ^= this.quadHash * 31 + quad.hashCode(); + for (int i = 0; i < quads.length; i++) { + var quad = quads[i]; + this.quadHash = this.quadHash * 31 + quad.getQuadHash() + i * 3; } return this.quadHash; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentSorting.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentSorting.java index 6eb5ebb5d7..fdd01fed53 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentSorting.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentSorting.java @@ -30,13 +30,6 @@ * perform blocking sorts of close sections. Maybe not an issue? Might reduce * stutter in high fps situations. However, high complexity with regards to * processing the results of preemptive sorts. - * - Check that separators still work on aligned geomtry. It seems that a lot of - * things are not topo sortable after the most recent fix to the quad visibility - * check. - * - figure out why when the player moves at high speed there end up being more - * direct trigger entries than sections with the dynamic sort type, even if - * everything is set to only direct trigger and not GFNI trigger. (the numbers - * should be the same, somehow they're not being bookkept correctly) * - determine the right distance for angle/distance triggering. It seems just * the diagonal of a section is too small, angle triggering is broken at close * distances. From 90d6f62aba498b68f8dc61d1798388da624263bf Mon Sep 17 00:00:00 2001 From: douira Date: Thu, 23 Nov 2023 00:28:14 +0100 Subject: [PATCH 130/256] remove unused import --- .../jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java index b00354d4a9..c011732a66 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java @@ -20,7 +20,6 @@ import org.lwjgl.opengl.GL; import org.lwjgl.opengl.GLCapabilities; -import javax.sound.sampled.BooleanControl; import java.util.ArrayList; import java.util.List; From 560693d9eacca1a75a4a81688ec022048c3b04b5 Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 24 Nov 2023 06:04:41 +0100 Subject: [PATCH 131/256] implement BSP tree sorting and integrate with the rest of the sorting and triggering system. TODO: there's still improvements to be done to BSP construction and overall architecture --- .../client/render/chunk/RenderSection.java | 2 +- .../render/chunk/RenderSectionManager.java | 8 +- .../chunk/compile/ChunkBuildOutput.java | 4 +- .../render/chunk/compile/ChunkSortOutput.java | 4 +- .../chunk/compile/OutputWithIndexData.java | 2 +- .../chunk/compile/pipeline/BlockRenderer.java | 2 +- .../chunk/compile/pipeline/FluidRenderer.java | 11 +- .../tasks/ChunkBuilderMeshingTask.java | 2 +- .../tasks/ChunkBuilderSortingTask.java | 2 +- .../chunk/region/RenderRegionManager.java | 2 +- .../translucent_sorting/AccGroupResult.java | 38 +++ .../AccumulationGroup.java | 51 ++-- .../translucent_sorting/DirectTriggers.java | 18 +- .../translucent_sorting/GFNITriggers.java | 24 +- .../chunk/translucent_sorting/Group.java | 18 +- .../chunk/translucent_sorting/NormalList.java | 13 +- .../chunk/translucent_sorting/TQuad.java | 2 +- ...plexSorting.java => TopoGraphSorting.java} | 56 +--- .../TranslucentGeometryCollector.java | 128 ++++---- .../TranslucentSorting.java | 53 ++-- .../bsp_tree/BSPBuildFailureException.java | 7 + .../translucent_sorting/bsp_tree/BSPNode.java | 39 +++ .../bsp_tree/BSPResult.java | 46 +++ .../bsp_tree/BSPWorkspace.java | 54 ++++ .../bsp_tree/InnerBinaryPartitionBSPNode.java | 55 ++++ .../bsp_tree/InnerMultiPartitionBSPNode.java | 71 +++++ .../bsp_tree/InnerPartitionBSPNode.java | 282 ++++++++++++++++++ .../bsp_tree/LeafMultiBSPNode.java | 20 ++ .../bsp_tree/LeafSingleBSPNode.java | 20 ++ .../{ => data}/AnyOrderData.java | 12 +- .../data/BSPDynamicData.java | 67 +++++ .../translucent_sorting/data/DynamicData.java | 29 ++ .../{ => data}/MixedDirectionData.java | 2 +- .../{ => data}/NoData.java | 3 +- .../{ => data}/PresentTranslucentData.java | 22 +- .../{ => data}/SplitDirectionData.java | 2 +- .../{ => data}/StaticNormalRelativeData.java | 13 +- .../{ => data}/StaticTopoAcyclicData.java | 9 +- .../TopoSortDynamicData.java} | 152 ++++++---- .../{ => data}/TranslucentData.java | 17 +- 40 files changed, 1079 insertions(+), 283 deletions(-) create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AccGroupResult.java rename src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/{ComplexSorting.java => TopoGraphSorting.java} (91%) create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPBuildFailureException.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPResult.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerMultiPartitionBSPNode.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafMultiBSPNode.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafSingleBSPNode.java rename src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/{ => data}/AnyOrderData.java (80%) create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicData.java rename src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/{ => data}/MixedDirectionData.java (98%) rename src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/{ => data}/NoData.java (85%) rename src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/{ => data}/PresentTranslucentData.java (71%) rename src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/{ => data}/SplitDirectionData.java (98%) rename src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/{ => data}/StaticNormalRelativeData.java (91%) rename src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/{ => data}/StaticTopoAcyclicData.java (71%) rename src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/{DynamicData.java => data/TopoSortDynamicData.java} (62%) rename src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/{ => data}/TranslucentData.java (80%) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java index 2a39205b2f..d25647c39b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java @@ -5,7 +5,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.occlusion.GraphDirectionSet; import me.jellysquid.mods.sodium.client.render.chunk.occlusion.VisibilityEncoding; import me.jellysquid.mods.sodium.client.render.chunk.region.RenderRegion; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TranslucentData; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; import me.jellysquid.mods.sodium.client.util.task.CancellationToken; import net.minecraft.block.entity.BlockEntity; import net.minecraft.client.texture.Sprite; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index b4ee799bea..1d3bdd63aa 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -30,8 +30,9 @@ import me.jellysquid.mods.sodium.client.render.chunk.region.RenderRegionManager; import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.CameraMovement; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TranslucentData; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TranslucentSorting; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TopoSortDynamicData; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkMeshFormats; import me.jellysquid.mods.sodium.client.render.texture.SpriteUtil; import me.jellysquid.mods.sodium.client.render.viewport.CameraTransform; @@ -331,8 +332,9 @@ private void processChunkBuildResults(ArrayList results) { // a rebuild always generates new translucent data which means applyTriggerChanges isn't necessary result.render.setTranslucentData(chunkBuildOutput.translucentData); } - } else if (result instanceof ChunkSortOutput chunkSortOutput && chunkSortOutput.dynamicData.hasTriggerChanges()) { - this.ts.applyTriggerChanges(chunkSortOutput.dynamicData, result.render.getPosition(), this.cameraPosition); + } else if (result instanceof ChunkSortOutput chunkSortOutput + && chunkSortOutput.dynamicData instanceof TopoSortDynamicData data) { + this.ts.applyTriggerChanges(data, result.render.getPosition(), this.cameraPosition); } var job = result.render.getTaskCancellationToken(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java index 070c5acd56..51daa27273 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java @@ -2,8 +2,8 @@ import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.PresentTranslucentData; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TranslucentData; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.PresentTranslucentData; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionInfo; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java index eab1e04961..0cf4ec60fd 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java @@ -1,8 +1,8 @@ package me.jellysquid.mods.sodium.client.render.chunk.compile; import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.DynamicData; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.PresentTranslucentData; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.DynamicData; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.PresentTranslucentData; public class ChunkSortOutput extends BuilderTaskOutput implements OutputWithIndexData { public final DynamicData dynamicData; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/OutputWithIndexData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/OutputWithIndexData.java index e66207f9cf..a650fa3b92 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/OutputWithIndexData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/OutputWithIndexData.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.render.chunk.compile; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.PresentTranslucentData; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.PresentTranslucentData; public interface OutputWithIndexData { PresentTranslucentData getTranslucentData(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java index 69b67d9566..017a05b03b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java @@ -164,7 +164,7 @@ private void writeGeometry(BlockRenderContext ctx, } if (material == DefaultMaterials.TRANSLUCENT && ctx.collector != null) { - ctx.collector.appendQuad(quad, vertices, normalFace); + ctx.collector.appendQuad(quad, vertices, normalFace, false); } var vertexBuffer = builder.getVertexBuffer(normalFace); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java index 2e76852cb5..b184b1faa0 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java @@ -230,13 +230,14 @@ public void render(WorldSlice world, FluidState fluidState, BlockPos blockPos, B setVertex(quad, 2, 1.0F, southEastHeight, 1.0F, u3, v3); setVertex(quad, 3, 1.0F, northEastHeight, 0.0f, u4, v4); + boolean aligned = northEastHeight == northWestHeight + && northWestHeight == southEastHeight + && southEastHeight == southWestHeight; + this.updateQuad(quad, world, blockPos, lighter, Direction.UP, 1.0F, colorProvider, fluidState); - this.writeQuad(meshBuilder, collector, material, offset, quad, facing, false); + this.writeQuad(meshBuilder, collector, material, offset, quad, aligned ? facing : ModelQuadFacing.UNASSIGNED, false); if (fluidState.canFlowTo(world, this.scratchPos.set(posX, posY + 1, posZ))) { - boolean aligned = northEastHeight == northWestHeight - && northWestHeight == southEastHeight - && southEastHeight == southWestHeight; this.writeQuad(meshBuilder, collector, material, offset, quad, aligned ? ModelQuadFacing.NEG_Y : ModelQuadFacing.UNASSIGNED, true); @@ -432,7 +433,7 @@ private void writeQuad(ChunkModelBuilder builder, TranslucentGeometryCollector c // calculate the current GFNI normal but not the unit normal quad.calculateNormals(false); } - collector.appendQuad(quad, vertices, facing); + collector.appendQuad(quad, vertices, facing, flip); } var vertexBuffer = builder.getVertexBuffer(facing); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java index 58ed3e998d..e2746902f2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java @@ -14,8 +14,8 @@ import me.jellysquid.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses; import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortType; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TranslucentData; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TranslucentGeometryCollector; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; import me.jellysquid.mods.sodium.client.util.task.CancellationToken; import me.jellysquid.mods.sodium.client.world.WorldSlice; import me.jellysquid.mods.sodium.client.world.cloned.ChunkRenderContext; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java index 71cf468f66..e09bbefbd4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java @@ -5,7 +5,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildContext; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkSortOutput; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.DynamicData; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.DynamicData; import me.jellysquid.mods.sodium.client.util.task.CancellationToken; public class ChunkBuilderSortingTask extends ChunkBuilderTask { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java index 5051140cae..f430b418cd 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java @@ -17,7 +17,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; import me.jellysquid.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses; import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.PresentTranslucentData; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.PresentTranslucentData; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AccGroupResult.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AccGroupResult.java new file mode 100644 index 0000000000..896ce606df --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AccGroupResult.java @@ -0,0 +1,38 @@ +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; + +import java.util.Collection; + +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; + +public abstract class AccGroupResult { + AccumulationGroup[] alignedDistances; + + public AccumulationGroup[] getAlignedDistances() { + return this.alignedDistances; + } + + public AccumulationGroup[] getAlignedDistancesOrCreate() { + if (this.alignedDistances == null) { + this.alignedDistances = new AccumulationGroup[ModelQuadFacing.DIRECTIONS]; + } + return this.alignedDistances; + } + + public abstract Collection getUnalignedDistances(); + + public abstract int getUnalignedDistanceCount(); + + public abstract AccumulationGroup getGroupForUnalignedNormal(NormalList normalList); + + AccumulationGroup getGroupForNormal(NormalList normalList) { + int collectorKey = normalList.getCollectorKey(); + if (collectorKey < 0xFF) { + if (this.alignedDistances == null) { + return null; + } + return this.alignedDistances[collectorKey]; + } else { + return getGroupForUnalignedNormal(normalList); + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AccumulationGroup.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AccumulationGroup.java index 3eac1ed2fd..062186f411 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AccumulationGroup.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AccumulationGroup.java @@ -5,60 +5,71 @@ import com.lodborg.intervaltree.DoubleInterval; import com.lodborg.intervaltree.Interval.Bounded; -import it.unimi.dsi.fastutil.doubles.DoubleArrays; -import it.unimi.dsi.fastutil.doubles.DoubleOpenHashSet; +import it.unimi.dsi.fastutil.floats.FloatArrays; +import it.unimi.dsi.fastutil.floats.FloatOpenHashSet; +import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; import net.minecraft.util.math.ChunkSectionPos; -class AccumulationGroup { - final DoubleOpenHashSet relativeDistances = new DoubleOpenHashSet(16); +public class AccumulationGroup { + final FloatOpenHashSet relativeDistancesSet = new FloatOpenHashSet(16); final Vector3fc normal; final int collectorKey; final ChunkSectionPos sectionPos; - double[] facePlaneDistances; // relative to the base distance - DoubleInterval distances; + float[] relativeDistances; // relative to the base distance + DoubleInterval distanceRange; long relDistanceHash; double baseDistance; - AccumulationGroup(ChunkSectionPos sectionPos, Vector3fc normal, int collectorKey) { + static int collectorKeyFromNormal(int normalX, int normalY, int normalZ) { + return 0xFF | (normalX & 0xFF << 8) | (normalY & 0xFF << 15) | (normalZ & 0xFF << 22); + } + + public AccumulationGroup(ChunkSectionPos sectionPos, Vector3fc normal, int collectorKey) { this.sectionPos = sectionPos; this.normal = normal; this.collectorKey = collectorKey; } boolean addPlaneMember(float vertexX, float vertexY, float vertexZ) { - double distance = this.normal.dot(vertexX, vertexY, vertexZ); + return this.addPlaneMember(this.normal.dot(vertexX, vertexY, vertexZ)); + } - // add the distance to the set and update the min/max distances if necessary - return this.relativeDistances.add(distance); + public boolean addPlaneMember(float distance) { + return this.relativeDistancesSet.add(distance); } - void prepareIntegration() { + public void prepareIntegration() { // stop if already prepared - if (this.facePlaneDistances != null) { + if (this.relativeDistances != null) { throw new IllegalStateException("Already prepared"); } // store the absolute face plane distances in an array - var size = this.relativeDistances.size(); - this.facePlaneDistances = new double[this.relativeDistances.size()]; + var size = this.relativeDistancesSet.size(); + this.relativeDistances = new float[this.relativeDistancesSet.size()]; int i = 0; - for (double relDistance : this.relativeDistances) { - this.facePlaneDistances[i++] = relDistance; + for (float relDistance : this.relativeDistancesSet) { + this.relativeDistances[i++] = relDistance; long distanceBits = Double.doubleToLongBits(relDistance); this.relDistanceHash ^= this.relDistanceHash * 31L + distanceBits; } // sort the array ascending - DoubleArrays.quickSort(facePlaneDistances); + FloatArrays.quickSort(relativeDistances); this.baseDistance = this.normal.dot( sectionPos.getMinX(), sectionPos.getMinY(), sectionPos.getMinZ()); - this.distances = new DoubleInterval( - this.facePlaneDistances[0] + this.baseDistance, - this.facePlaneDistances[size - 1] + this.baseDistance, + this.distanceRange = new DoubleInterval( + this.relativeDistances[0] + this.baseDistance, + this.relativeDistances[size - 1] + this.baseDistance, Bounded.CLOSED); } + + public void prepareAndInsert(Object2ReferenceOpenHashMap distancesByNormal) { + this.prepareIntegration(); + distancesByNormal.put(this.normal, this.relativeDistances); + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/DirectTriggers.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/DirectTriggers.java index 858de48bc3..4e51d67c39 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/DirectTriggers.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/DirectTriggers.java @@ -5,13 +5,15 @@ import it.unimi.dsi.fastutil.doubles.Double2ObjectRBTreeMap; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TranslucentSorting.SectionTriggers; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TopoSortDynamicData; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; import net.minecraft.util.math.ChunkSectionPos; /** * Performs direct triggering for sections that can't (or shouldn't) be * topologically sorted and thus aren't eligible for GFNI triggering. */ -class DirectTriggers implements SectionTriggers { +class DirectTriggers implements SectionTriggers { /** * A tree map of the directly triggered sections, indexed by their * minimum required camera movement. When the given camera movement is exceeded, @@ -60,7 +62,7 @@ int getDirectTriggerCount() { private class DirectTriggerData { final ChunkSectionPos sectionPos; private Vector3dc sectionCenter; - final DynamicData dynamicData; + final TopoSortDynamicData dynamicData; DirectTriggerData next; /** @@ -68,7 +70,7 @@ private class DirectTriggerData { */ Vector3dc triggerCameraPos; - DirectTriggerData(DynamicData dynamicData, ChunkSectionPos sectionPos, Vector3dc triggerCameraPos) { + DirectTriggerData(TopoSortDynamicData dynamicData, ChunkSectionPos sectionPos, Vector3dc triggerCameraPos) { this.dynamicData = dynamicData; this.sectionPos = sectionPos; this.triggerCameraPos = triggerCameraPos; @@ -121,7 +123,7 @@ private void insertDirectDistanceTrigger(DirectTriggerData data, Vector3dc camer } private void insertTrigger(double key, DirectTriggerData data) { - data.dynamicData.directTriggerKey = key; + data.dynamicData.setDirectTriggerKey(key); // attach the previous value after the current one in the list. if there is none // it's just null @@ -187,17 +189,17 @@ public void processTriggers(TranslucentSorting ts, CameraMovement movement) { @Override public void removeSection(long sectionPos, TranslucentData data) { - if (data instanceof DynamicData dynamicData) { - var key = dynamicData.directTriggerKey; + if (data instanceof TopoSortDynamicData triggerable) { + var key = triggerable.getDirectTriggerKey(); if (key != -1) { this.directTriggerSections.remove(key); - dynamicData.directTriggerKey = -1; + triggerable.setDirectTriggerKey(-1); } } } @Override - public void addSection(ChunkSectionPos sectionPos, DynamicData data, Vector3dc cameraPos) { + public void addSection(ChunkSectionPos sectionPos, TopoSortDynamicData data, Vector3dc cameraPos) { var newData = new DirectTriggerData(data, sectionPos, cameraPos); if (newData.isAngleTriggering(cameraPos)) { this.insertDirectAngleTrigger(newData, cameraPos, TRIGGER_ANGLE); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/GFNITriggers.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/GFNITriggers.java index f187da2b86..790aa6ce1f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/GFNITriggers.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/GFNITriggers.java @@ -5,15 +5,19 @@ import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TranslucentSorting.SectionTriggers; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.DynamicData; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; import net.minecraft.util.math.ChunkSectionPos; /** * Performs Global Face Normal Indexing-based triggering as described in * https://hackmd.io/@douira100/sodium-sl-gfni * - * Distances are stored as doubles and normals are stored as float vectors. + * Global distances are stored as doubles while section-relative distances are + * stored as floats. Normals are stored as float vectors unless they're needed + * to produce global double distances. */ -class GFNITriggers implements SectionTriggers { +class GFNITriggers implements SectionTriggers { /** * A map of all the normal lists, indexed by their normal. */ @@ -65,7 +69,7 @@ public void removeSection(long sectionPos, TranslucentData data) { @Override public void addSection(ChunkSectionPos pos, DynamicData data, Vector3dc cameraPos) { long sectionPos = pos.asLong(); - var collector = data.getCollector(); + var accGroupResult = data.getAccGroupResult(); // go through all normal lists and check against the normals that the group // builder has. if the normal list has data for the section, but the group @@ -75,7 +79,7 @@ public void addSection(ChunkSectionPos pos, DynamicData data, Vector3dc cameraPo var normalList = iterator.next(); // check if the geometry collector includes data for this normal. - var accGroup = collector.getGroupForNormal(normalList); + var accGroup = accGroupResult.getGroupForNormal(normalList); if (normalList.hasSection(sectionPos)) { if (accGroup == null) { if (this.removeSectionFromList(normalList, sectionPos)) { @@ -93,19 +97,21 @@ public void addSection(ChunkSectionPos pos, DynamicData data, Vector3dc cameraPo // normals // for which there are no normal lists yet. This only checks for new normal // lists since new data for existing normal lists is handled above. - if (collector.axisAlignedDistances != null) { - for (var accGroup : collector.axisAlignedDistances) { + var aligned = accGroupResult.getAlignedDistances(); + if (aligned != null) { + for (var accGroup : aligned) { if (accGroup != null) { this.addSectionInNewNormalLists(data, accGroup); } } } - if (collector.unalignedDistances != null) { - for (var accGroup : collector.unalignedDistances.values()) { + var unaligned = accGroupResult.getUnalignedDistances(); + if (unaligned != null) { + for (var accGroup : unaligned) { this.addSectionInNewNormalLists(data, accGroup); } } - data.deleteCollector(); + data.clearAccGroupData(); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/Group.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/Group.java index b2f893e9bb..0292452e63 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/Group.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/Group.java @@ -2,7 +2,7 @@ import com.lodborg.intervaltree.DoubleInterval; -import it.unimi.dsi.fastutil.doubles.DoubleArrays; +import it.unimi.dsi.fastutil.floats.FloatArrays; /** * A group represents a set of face planes of the same normal within a section. @@ -20,7 +20,7 @@ class Group { * A sorted list of all the face plane distances in this group. Relative to the * base distance. */ - double[] facePlaneDistances; + float[] facePlaneDistances; /** * A hash of all the face plane distances in this group (before adding the base @@ -42,15 +42,15 @@ class Group { void replaceWith(AccumulationGroup accGroup) { this.sectionPos = accGroup.sectionPos.asLong(); - this.distances = accGroup.distances; + this.distances = accGroup.distanceRange; this.relDistanceHash = accGroup.relDistanceHash; - this.facePlaneDistances = accGroup.facePlaneDistances; + this.facePlaneDistances = accGroup.relativeDistances; this.baseDistance = accGroup.baseDistance; } - public static boolean queryRange(double[] sortedDistances, double start, double end) { + public static boolean queryRange(float[] sortedDistances, float start, float end) { // test that there is actually an entry in the query range - int result = DoubleArrays.binarySearch(sortedDistances, start); + int result = FloatArrays.binarySearch(sortedDistances, start); if (result < 0) { // recover the insertion point int insertionPoint = -result - 1; @@ -78,7 +78,7 @@ void triggerRange(TranslucentSorting ts, double start, double end, int collector // start/end, there can be no overlap if (start < this.distances.getEnd() && end > this.distances.getStart() && queryRange(this.facePlaneDistances, - start - this.baseDistance, end - this.baseDistance)) { + (float) (start - this.baseDistance), (float) (end - this.baseDistance))) { ts.triggerSectionGFNI(this.sectionPos, collectorKey); } } @@ -94,8 +94,8 @@ && queryRange(this.facePlaneDistances, * If they are common, use second hash */ boolean equalsAccGroup(AccumulationGroup accGroup) { - return this.facePlaneDistances.length == accGroup.relativeDistances.size() - && this.distances.equals(accGroup.distances) + return this.facePlaneDistances.length == accGroup.relativeDistancesSet.size() + && this.distances.equals(accGroup.distanceRange) && this.relDistanceHash == accGroup.relDistanceHash; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/NormalList.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/NormalList.java index ba9a49b63d..fa399cf91d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/NormalList.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/NormalList.java @@ -19,16 +19,16 @@ /** * A normal list contains all the face planes that have the same normal. */ -class NormalList { +public class NormalList { /** * Size threshold after which group sets in {@link #groupsByInterval} are * replaced with hash sets to improve update performance. */ - private static final int HASH_SET_THRESHOLD = 40; + private static final int HASH_SET_THRESHOLD = 20; /** * Size threshold under which group sets in {@link #groupsByInterval} are - * downgraded to array sets to improve reduce memory usage. + * downgraded to array sets to reduce memory usage. */ private static final int ARRAY_SET_THRESHOLD = 10; @@ -40,7 +40,8 @@ class NormalList { /** * If this normal list is for an axis-aligned normal, this is the index of it - * for querying in {@link TranslucentGeometryCollector#getGroupForNormal(Vector3fc)}. + * for querying in + * {@link TranslucentGeometryCollector#getGroupForNormal(Vector3fc)}. * * If this normal list is for an unaligned normal, this is the key for the * hash map of quantized normals. @@ -69,7 +70,7 @@ class NormalList { * Constructs a new normal list with the given unit normal vector and aligned * normal index. * - * @param normal The unit normal vector + * @param normal The unit normal vector * @param collectorKey The geometry collector index */ NormalList(Vector3fc normal, int collectorKey) { @@ -78,7 +79,7 @@ class NormalList { this.collectorKey = collectorKey; } - Vector3fc getNormal() { + public Vector3fc getNormal() { return normalf; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java index afb28f8f68..bf0f5d8c12 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java @@ -14,7 +14,7 @@ * @implNote Autogenerated hashcode and equals methods to ensure the arrays are * correctly compared.. */ -record TQuad(ModelQuadFacing facing, Vector3fc normal, Vector3f center, float[] extents) { +public record TQuad(ModelQuadFacing facing, Vector3fc normal, Vector3f center, float[] extents) { int getQuadHash() { // the hash code needs to be particularly collision resistant int result = 1; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/ComplexSorting.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TopoGraphSorting.java similarity index 91% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/ComplexSorting.java rename to src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TopoGraphSorting.java index ef5b99a1bc..9970e532d0 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/ComplexSorting.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TopoGraphSorting.java @@ -6,6 +6,7 @@ import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; import me.jellysquid.mods.sodium.client.util.collections.BitArray; import me.jellysquid.mods.sodium.client.util.sorting.MergeSort; @@ -18,8 +19,8 @@ * conditions for visibility between quads are made more strict did not yield * significantly more robust topo sorting. */ -public class ComplexSorting { - private ComplexSorting() { +public class TopoGraphSorting { + private TopoGraphSorting() { } private static float halfspace(Vector3fc planeAnchor, Vector3fc planeNormal, Vector3fc point) { @@ -45,34 +46,7 @@ private static boolean pointInsideHalfSpace(Vector3fc planeAnchor, Vector3fc pla return halfspace(planeAnchor, planeNormal, point) < 0; } - private static ThreadLocal distanceSortKeys = new ThreadLocal<>(); - - public static int[] distanceSortDirect(int[] indexes, - IntBuffer indexBuffer, TQuad[] quads, Vector3fc cameraPos) { - if (indexes == null) { - indexes = new int[quads.length]; - for (int i = 0; i < quads.length; i++) { - indexes[i] = i; - } - } - - float[] keys = distanceSortKeys.get(); - if (keys == null || keys.length < quads.length) { - keys = new float[quads.length]; - distanceSortKeys.set(keys); - } - - for (int i = 0; i < quads.length; i++) { - keys[i] = cameraPos.distanceSquared(quads[i].center()); - } - - MergeSort.mergeSort(indexes, keys); - TranslucentData.writeQuadVertexIndexes(indexBuffer, indexes); - - return indexes; - } - - private static boolean orthogonalQuadVisibleThrough(TQuad halfspace, TQuad otherQuad) { + public static boolean orthogonalQuadVisibleThrough(TQuad halfspace, TQuad otherQuad) { var hd = halfspace.facing().ordinal(); var hdOpposite = halfspace.facing().getOpposite().ordinal(); var od = otherQuad.facing().ordinal(); @@ -141,7 +115,7 @@ public static boolean topoSortAlignedScanningCyclic(IntBuffer indexBuffer, TQuad activeQuads++; } else { // write the invisible quads right away - TranslucentData.putQuadVertexIndexes(indexBuffer, i); + TranslucentData.writeQuadVertexIndexes(indexBuffer, i); } } } else { @@ -276,7 +250,7 @@ public static boolean topoSortAlignedScanningCyclic(IntBuffer indexBuffer, TQuad leafQuads.unset(nextLeafQuadIndex); // add it to the topo sort result - TranslucentData.putMappedQuadVertexIndexes(indexBuffer, nextLeafQuadIndex, activeToRealIndex); + TranslucentData.writeMappedQuadVertexIndexes(indexBuffer, nextLeafQuadIndex, activeToRealIndex); // remove the edges to this quad and mark them as leaves if that was the last // outgoing edge they had @@ -291,7 +265,7 @@ public static boolean topoSortAlignedScanningCyclic(IntBuffer indexBuffer, TQuad return true; } - private static boolean testSeparatorRange(Object2ReferenceOpenHashMap distancesByNormal, + private static boolean testSeparatorRange(Object2ReferenceOpenHashMap distancesByNormal, Vector3fc normal, float start, float end) { var distances = distancesByNormal.get(normal); if (distances == null) { @@ -301,7 +275,7 @@ private static boolean testSeparatorRange(Object2ReferenceOpenHashMap distancesByNormal, Vector3fc cameraPos) { + Object2ReferenceOpenHashMap distancesByNormal, Vector3fc cameraPos) { // check if there is an aligned separator for (int direction = 0; direction < ModelQuadFacing.DIRECTIONS; direction++) { var facing = ModelQuadFacing.VALUES[direction]; @@ -364,7 +338,7 @@ private static boolean visibilityWithSeparator(TQuad quadA, TQuad quadB, * @return true if the other quad is visible through the first quad */ private static boolean quadVisibleThrough(TQuad quad, TQuad other, - Object2ReferenceOpenHashMap distancesByNormal, Vector3fc cameraPos) { + Object2ReferenceOpenHashMap distancesByNormal, Vector3fc cameraPos) { if (quad == other) { return false; } @@ -420,7 +394,7 @@ private static boolean quadVisibleThrough(TQuad quad, TQuad other, */ public static boolean topoSortDepthFirstCyclic( IntBuffer indexBuffer, TQuad[] allQuads, - Object2ReferenceOpenHashMap distancesByNormal, + Object2ReferenceOpenHashMap distancesByNormal, Vector3fc cameraPos) { // TODO: quads visibility filter copy-pasted from topoSortAlignedAcyclic // if enabled, check for visibility and produce a mapping of indices @@ -444,7 +418,7 @@ public static boolean topoSortDepthFirstCyclic( activeQuads++; } else { // write the invisible quads right away - TranslucentData.putQuadVertexIndexes(indexBuffer, i); + TranslucentData.writeQuadVertexIndexes(indexBuffer, i); } } } else { @@ -457,7 +431,7 @@ public static boolean topoSortDepthFirstCyclic( return true; } if (activeQuads == 1) { - TranslucentData.putMappedQuadVertexIndexes(indexBuffer, 0, activeToRealIndex); + TranslucentData.writeMappedQuadVertexIndexes(indexBuffer, 0, activeToRealIndex); return true; } @@ -469,8 +443,8 @@ public static boolean topoSortDepthFirstCyclic( a = 1; b = 0; } - TranslucentData.putMappedQuadVertexIndexes(indexBuffer, a, activeToRealIndex); - TranslucentData.putMappedQuadVertexIndexes(indexBuffer, b, activeToRealIndex); + TranslucentData.writeMappedQuadVertexIndexes(indexBuffer, a, activeToRealIndex); + TranslucentData.writeMappedQuadVertexIndexes(indexBuffer, b, activeToRealIndex); return true; } @@ -529,7 +503,7 @@ public static boolean topoSortDepthFirstCyclic( stackPos--; // write to the index buffer since the order is now correct - TranslucentData.putMappedQuadVertexIndexes(indexBuffer, currentQuadIndex, activeToRealIndex); + TranslucentData.writeMappedQuadVertexIndexes(indexBuffer, currentQuadIndex, activeToRealIndex); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java index 397d24e3ed..2c30223080 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java @@ -11,10 +11,20 @@ import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.FluidRenderer; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree.BSPBuildFailureException; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.AnyOrderData; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.BSPDynamicData; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.NoData; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.PresentTranslucentData; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.StaticNormalRelativeData; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.StaticTopoAcyclicData; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TopoSortDynamicData; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexEncoder; import me.jellysquid.mods.sodium.client.util.NativeBuffer; import net.minecraft.util.math.ChunkSectionPos; import java.util.Arrays; +import java.util.Collection; /** * The translucent geometry collector collects the data from the renderers and @@ -31,13 +41,12 @@ * doing it once without invisible quad exclusion and once with if the first * attempt fails. */ -public class TranslucentGeometryCollector { - AccumulationGroup[] axisAlignedDistances; - Int2ReferenceLinkedOpenHashMap unalignedDistances; +public class TranslucentGeometryCollector extends AccGroupResult { + private Int2ReferenceLinkedOpenHashMap unalignedDistances; private final ChunkSectionPos sectionPos; private int facePlaneCount = 0; - int alignedNormalBitmap = 0; + private int alignedNormalBitmap = 0; private Vector3f minBounds = new Vector3f(16, 16, 16); private Vector3f maxBounds = new Vector3f(0, 0, 0); @@ -70,7 +79,8 @@ private static float quantizeEpsilon(float value) { return (float) Math.floor(value * INV_QUANTIZE_EPSILON + 0.5) * QUANTIZE_EPSILON; } - public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] vertices, ModelQuadFacing facing) { + public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] vertices, ModelQuadFacing facing, + boolean flipNormal) { float xSum = 0; float ySum = 0; float zSum = 0; @@ -82,34 +92,24 @@ public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] verti float lastZ = vertices[3].z; int uniqueQuads = 0; - float negXExtent = Float.POSITIVE_INFINITY; - float negYExtent = Float.POSITIVE_INFINITY; - float negZExtent = Float.POSITIVE_INFINITY; float posXExtent = Float.NEGATIVE_INFINITY; float posYExtent = Float.NEGATIVE_INFINITY; float posZExtent = Float.NEGATIVE_INFINITY; + float negXExtent = Float.POSITIVE_INFINITY; + float negYExtent = Float.POSITIVE_INFINITY; + float negZExtent = Float.POSITIVE_INFINITY; for (int i = 0; i < 4; i++) { float x = vertices[i].x; float y = vertices[i].y; float z = vertices[i].z; - // TODO: see if this is faster than using Math.min and Math.max - if (x < negXExtent) { - negXExtent = x; - } else if (x > posXExtent) { - posXExtent = x; - } - if (y < negYExtent) { - negYExtent = y; - } else if (y > posYExtent) { - posYExtent = y; - } - if (z < negZExtent) { - negZExtent = z; - } else if (z > posZExtent) { - posZExtent = z; - } + posXExtent = Math.max(posXExtent, x); + posYExtent = Math.max(posYExtent, y); + posZExtent = Math.max(posZExtent, z); + negXExtent = Math.min(negXExtent, x); + negYExtent = Math.min(negYExtent, y); + negZExtent = Math.min(negZExtent, z); if (x != lastX || y != lastY || z != lastZ) { xSum += x; @@ -129,20 +129,20 @@ public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] verti var centerZ = quantizeEpsilon(zSum / uniqueQuads); var center = new Vector3f(centerX, centerY, centerZ); - negXExtent = quantizeEpsilon(negXExtent); - negYExtent = quantizeEpsilon(negYExtent); - negZExtent = quantizeEpsilon(negZExtent); posXExtent = quantizeEpsilon(posXExtent); posYExtent = quantizeEpsilon(posYExtent); posZExtent = quantizeEpsilon(posZExtent); + negXExtent = quantizeEpsilon(negXExtent); + negYExtent = quantizeEpsilon(negYExtent); + negZExtent = quantizeEpsilon(negZExtent); if (facing != ModelQuadFacing.UNASSIGNED && this.unalignedDistances == null) { - minBounds.x = Math.min(minBounds.x, negXExtent); - minBounds.y = Math.min(minBounds.y, negYExtent); - minBounds.z = Math.min(minBounds.z, negZExtent); maxBounds.x = Math.max(maxBounds.x, posXExtent); maxBounds.y = Math.max(maxBounds.y, posYExtent); maxBounds.z = Math.max(maxBounds.z, posZExtent); + minBounds.x = Math.min(minBounds.x, negXExtent); + minBounds.y = Math.min(minBounds.y, negYExtent); + minBounds.z = Math.min(minBounds.z, negZExtent); } // POS_X, POS_Y, POS_Z, NEG_X, NEG_Y, NEG_Z @@ -162,9 +162,10 @@ public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] verti } if (facing == ModelQuadFacing.UNASSIGNED) { - int normalX = quadView.getGFNINormX(); - int normalY = quadView.getGFNINormY(); - int normalZ = quadView.getGFNINormZ(); + int flipFactor = flipNormal ? -1 : 1; + int normalX = flipFactor * quadView.getGFNINormX(); + int normalY = flipFactor * quadView.getGFNINormY(); + int normalZ = flipFactor * quadView.getGFNINormZ(); if (this.unalignedDistances == null) { this.unalignedDistances = new Int2ReferenceLinkedOpenHashMap<>(4); @@ -173,7 +174,7 @@ public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] verti // the key for the hash map is the normal packed into an int // the lowest byte is 0xFF to prevent collisions with axis-aligned normals // (assuming quantization with 32, which is 5 bits per component) - int normalKey = 0xFF | (normalX & 0xFF << 8) | (normalY & 0xFF << 15) | (normalZ & 0xFF << 22); + int normalKey = AccumulationGroup.collectorKeyFromNormal(normalX, normalY, normalZ); accGroup = this.unalignedDistances.get(normalKey); if (accGroup == null) { @@ -187,16 +188,16 @@ public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] verti quadList.add(new TQuad(facing, accGroup.normal, center, extents)); } else { - if (this.axisAlignedDistances == null) { - this.axisAlignedDistances = new AccumulationGroup[ModelQuadFacing.DIRECTIONS]; + if (this.alignedDistances == null) { + this.alignedDistances = new AccumulationGroup[ModelQuadFacing.DIRECTIONS]; } int quadDirection = facing.ordinal(); - accGroup = this.axisAlignedDistances[quadDirection]; + accGroup = this.alignedDistances[quadDirection]; if (accGroup == null) { accGroup = new AccumulationGroup(sectionPos, ModelQuadFacing.NORMALS[quadDirection], quadDirection); - this.axisAlignedDistances[quadDirection] = accGroup; + this.alignedDistances[quadDirection] = accGroup; this.alignedNormalBitmap |= 1 << quadDirection; } @@ -302,12 +303,12 @@ private SortType sortTypeHeuristic() { // the more complex test that checks for distances aligned with the bounding box if (this.facePlaneCount <= ModelQuadFacing.DIRECTIONS) { boolean passesBoundingBoxTest = true; - for (AccumulationGroup accGroup : this.axisAlignedDistances) { + for (AccumulationGroup accGroup : this.alignedDistances) { if (accGroup == null) { continue; } - if (accGroup.relativeDistances.size() > 1) { + if (accGroup.relativeDistancesSet.size() > 1) { passesBoundingBoxTest = false; break; } @@ -318,7 +319,7 @@ private SortType sortTypeHeuristic() { || accGroup.normal.z() < 0) ? accGroup.normal.dot(minBounds) : accGroup.normal.dot(maxBounds); - if (accGroup.relativeDistances.iterator().nextDouble() != outwardBoundDistance) { + if (accGroup.relativeDistancesSet.iterator().nextFloat() != outwardBoundDistance) { passesBoundingBoxTest = false; break; } @@ -398,6 +399,7 @@ private TranslucentData makeNewTranslucentData(BuiltSectionMeshParts translucent // from this point on we know the estimated sort type requires direction mixing // (no backface culling) and all vertices are in the UNASSIGNED direction. + // TODO: don't attempt static topo sorting if BSP sorting works well. NativeBuffer buffer = PresentTranslucentData.nativeBufferForQuads(this.quads); if (this.sortType == SortType.STATIC_TOPO_ACYCLIC) { var result = StaticTopoAcyclicData.fromMesh(translucentMesh, this.quads, sectionPos, buffer); @@ -415,7 +417,12 @@ private TranslucentData makeNewTranslucentData(BuiltSectionMeshParts translucent } if (this.sortType == SortType.DYNAMIC_ALL) { - return DynamicData.fromMesh(translucentMesh, cameraPos, quads, sectionPos, this, buffer); + try { + return BSPDynamicData.fromMesh(translucentMesh, cameraPos, quads, sectionPos, this, buffer); + } catch (BSPBuildFailureException e) { + System.out.println("BSP build failure: " + sectionPos); + return TopoSortDynamicData.fromMesh(translucentMesh, cameraPos, quads, sectionPos, this, buffer); + } } throw new IllegalStateException("Unknown sort type: " + this.sortType); @@ -473,18 +480,31 @@ public TranslucentData getTranslucentData( return newData; } - AccumulationGroup getGroupForNormal(NormalList normalList) { - int collectorKey = normalList.getCollectorKey(); - if (collectorKey < 0xFF) { - if (this.axisAlignedDistances == null) { - return null; - } - return this.axisAlignedDistances[collectorKey]; - } else { - if (this.unalignedDistances == null) { - return null; - } - return this.unalignedDistances.get(collectorKey); + @Override + public AccumulationGroup getGroupForUnalignedNormal(NormalList normalList) { + if (this.unalignedDistances == null) { + return null; + } + return this.unalignedDistances.get(normalList.getCollectorKey()); + } + + @Override + public Collection getUnalignedDistances() { + if (this.unalignedDistances == null) { + return null; } + return this.unalignedDistances.values(); + } + + @Override + public int getUnalignedDistanceCount() { + if (this.unalignedDistances == null) { + return 0; + } + return this.unalignedDistances.size(); + } + + public int getAlignedNormalBitmap() { + return this.alignedNormalBitmap; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentSorting.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentSorting.java index fdd01fed53..e9f9e91bd2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentSorting.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentSorting.java @@ -6,6 +6,9 @@ import org.joml.Vector3dc; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.DynamicData; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TopoSortDynamicData; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; import net.minecraft.util.math.ChunkSectionPos; /** @@ -19,13 +22,6 @@ * may result in many sections suddenly needing sorting when the camera moves. * Maybe it's better to schedule them to be sorted gradually even if not * visible, if there are idle threads. - * - Groups of quads that form convex shapes in a single plane without holes can - * be sorted as one "quad". Their internal sorting can be arbitrary. Detecting - * and grouping/ungrouping them might prove difficult. Finding all quad groups - * is hard but finding one quad group at a time per direction is doable during - * building. Using the extents calculated for aligned quads, continuity can be - * easily tested and then convexity confirmed. How to deal with groups of quads - * that are only convex if a few of the quads are ignored? * - Movement prediction and preemptive task scheduling to avoid needing to * perform blocking sorts of close sections. Maybe not an issue? Might reduce * stutter in high fps situations. However, high complexity with regards to @@ -72,12 +68,12 @@ public class TranslucentSorting { private final GFNITriggers gfni = new GFNITriggers(); private final DirectTriggers direct = new DirectTriggers(); - interface SectionTriggers { + interface SectionTriggers { void processTriggers(TranslucentSorting ts, CameraMovement movement); void removeSection(long sectionPos, TranslucentData data); - void addSection(ChunkSectionPos sectionPos, DynamicData data, Vector3dc cameraPos); + void addSection(ChunkSectionPos sectionPos, T data, Vector3dc cameraPos); } /** @@ -123,17 +119,16 @@ void triggerSectionDirect(ChunkSectionPos sectionPos) { this.directTriggerCount++; } - public void applyTriggerChanges(DynamicData data, ChunkSectionPos pos, Vector3dc cameraPos) { - if (data.turnGFNITriggerOff) { + public void applyTriggerChanges(TopoSortDynamicData data, ChunkSectionPos pos, Vector3dc cameraPos) { + if (data.getAndFlushTurnGFNITriggerOff()) { this.gfni.removeSection(pos.asLong(), data); } - if (data.turnDirectTriggerOn) { + if (data.getAndFlushTurnDirectTriggerOn()) { this.direct.addSection(pos, data, cameraPos); } - if (data.turnDirectTriggerOff) { + if (data.getAndFlushTurnDirectTriggerOff()) { this.direct.removeSection(pos.asLong(), data); } - data.clearTriggerChanges(); } private void decrementSortTypeCounter(TranslucentData oldData) { @@ -180,24 +175,28 @@ public void integrateTranslucentData(TranslucentData oldData, TranslucentData ne this.incrementSortTypeCounter(newData); - // remove the section if the data doesn't need to trigger on face planes if (newData instanceof DynamicData dynamicData) { this.direct.removeSection(pos.asLong(), oldData); this.decrementSortTypeCounter(oldData); - if (dynamicData.GFNITrigger) { - this.gfni.addSection(pos, dynamicData, cameraPos); + + if (dynamicData instanceof TopoSortDynamicData topoSortData) { + if (topoSortData.GFNITriggerEnabled()) { + this.gfni.addSection(pos, topoSortData, cameraPos); + } else { + // remove the trigger data since this section is never going to get gfni + // triggering (there's no option to add sections to GFNI later currently) + topoSortData.clearAccGroupData(); + } + if (topoSortData.directTriggerEnabled()) { + this.direct.addSection(pos, topoSortData, cameraPos); + } + + // clear trigger changes on data change because the current state of trigger + // types was just applied + topoSortData.clearTriggerChanges(); } else { - // remove the collector since this section is never going to get gfni triggering - // (there's no option to add sections to GFNI later currently) - dynamicData.deleteCollector(); - } - if (dynamicData.directTrigger) { - this.direct.addSection(pos, dynamicData, cameraPos); + this.gfni.addSection(pos, dynamicData, cameraPos); } - - // clear trigger changes on data change because the current state of trigger - // types was just set - dynamicData.clearTriggerChanges(); } else { this.removeSection(oldData, pos.asLong()); return; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPBuildFailureException.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPBuildFailureException.java new file mode 100644 index 0000000000..5520c22dae --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPBuildFailureException.java @@ -0,0 +1,7 @@ +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; + +public class BSPBuildFailureException extends RuntimeException { + BSPBuildFailureException(String message) { + super(message); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java new file mode 100644 index 0000000000..88b623d4e3 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java @@ -0,0 +1,39 @@ +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; + +import java.nio.IntBuffer; + +import org.joml.Vector3fc; + +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; +import net.minecraft.util.math.ChunkSectionPos; + +/** + * A node in the BSP tree. The BSP tree is made up of nodes that split quads + * into groups on either side of a plane and those that lie on the plane. + * There's also leaf nodes that contain one or more quads. + */ +public abstract class BSPNode { + public abstract void collectSortedQuads(IntBuffer indexBuffer, Vector3fc cameraPos); + + public static BSPResult buildBSP(TQuad[] quads, ChunkSectionPos sectionPos) { + // create a workspace and then the nodes figure out the recursive building. + // throws if the BSP can't be built, null if none is necessary + var workspace = new BSPWorkspace(quads, sectionPos); + var rootNode = BSPNode.build(workspace); + var result = workspace.result; + result.rootNode = rootNode; + return result; + } + + static BSPNode build(BSPWorkspace workspace) { + // pick which type of node to create for the given workspace + // TODO: add more heuristics here + if (workspace.indexes.isEmpty()) { + return null; + } else if (workspace.indexes.size() == 1) { + return new LeafSingleBSPNode(workspace.indexes.getInt(0)); + } else { + return InnerPartitionBSPNode.build(workspace); + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPResult.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPResult.java new file mode 100644 index 0000000000..a48323e8be --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPResult.java @@ -0,0 +1,46 @@ +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; + +import java.util.Collection; + +import org.joml.Vector3fc; + +import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.AccGroupResult; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.AccumulationGroup; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.NormalList; + +public class BSPResult extends AccGroupResult { + // TODO: BSP triggering needs to be bidirectional + Object2ReferenceOpenHashMap unalignedDistances; + + BSPNode rootNode; + + @Override + public Collection getUnalignedDistances() { + if (this.unalignedDistances == null) { + return null; + } + return this.unalignedDistances.values(); + } + + @Override + public AccumulationGroup getGroupForUnalignedNormal(NormalList normalList) { + if (this.unalignedDistances == null) { + return null; + } + return this.unalignedDistances.get(normalList.getNormal()); + } + + @Override + public int getUnalignedDistanceCount() { + if (this.unalignedDistances == null) { + return 0; + } + return this.unalignedDistances.size(); + } + + public BSPNode getRootNode() { + return this.rootNode; + } + +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java new file mode 100644 index 0000000000..13112dc5d4 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java @@ -0,0 +1,54 @@ +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; + +import it.unimi.dsi.fastutil.ints.IntArrayList; +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.AccumulationGroup; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; +import net.minecraft.util.math.ChunkSectionPos; + +class BSPWorkspace { + /** + * All the quads in the section. + */ + final TQuad[] quads; + + final ChunkSectionPos sectionPos; + + /** + * A list of all the quad indexes to process in the next build invocation. + */ + IntArrayList indexes; + + BSPResult result = new BSPResult(); + + BSPWorkspace(TQuad[] quads, ChunkSectionPos sectionPos) { + this.quads = quads; + this.sectionPos = sectionPos; + + // initialize the indexes to all quads + int[] initialIndexes = new int[quads.length]; + for (int i = 0; i < quads.length; i++) { + initialIndexes[i] = i; + } + this.indexes = new IntArrayList(initialIndexes); + } + + // TODO: better bidirectional triggering: integrate bidirectionality in GFNI if + // top-level topo sorting isn't used anymore (and only use half as much memory + // by not storing it double) + void addAlignedPartitionPlane(int axis, float distance) { + var accGroups = result.getAlignedDistancesOrCreate(); + this.addOneSidedPlane(accGroups, axis, distance); + this.addOneSidedPlane(accGroups, axis + 3, -distance); + } + + void addOneSidedPlane(AccumulationGroup[] accGroups, int direction, float distance) { + var accGroup = accGroups[direction]; + if (accGroup == null) { + accGroup = new AccumulationGroup( + this.sectionPos, ModelQuadFacing.NORMALS[direction], direction); + accGroups[direction] = accGroup; + } + accGroup.addPlaneMember(distance); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java new file mode 100644 index 0000000000..3136386492 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java @@ -0,0 +1,55 @@ +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; + +import java.nio.IntBuffer; + +import org.joml.Vector3fc; + +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; + +class InnerBinaryPartitionBSPNode extends InnerPartitionBSPNode { + private final float planeDistance; + + // side towards which the normal points + private final BSPNode inside; // nullable + private final BSPNode outside; // nullable + private final int[] onPlaneQuads; + + InnerBinaryPartitionBSPNode(float planeDistance, Vector3fc planeNormal, + BSPNode inside, BSPNode outside, int[] onPlaneQuads) { + super(planeNormal); + this.planeDistance = planeDistance; + this.inside = inside; + this.outside = outside; + this.onPlaneQuads = onPlaneQuads; + } + + private void collectInside(IntBuffer indexBuffer, Vector3fc cameraPos) { + if (this.inside != null) { + this.inside.collectSortedQuads(indexBuffer, cameraPos); + } + } + + private void collectOutside(IntBuffer indexBuffer, Vector3fc cameraPos) { + if (this.outside != null) { + this.outside.collectSortedQuads(indexBuffer, cameraPos); + } + } + + @Override + public void collectSortedQuads(IntBuffer indexBuffer, Vector3fc cameraPos) { + var cameraInside = this.planeNormal.dot(cameraPos) < this.planeDistance; + if (cameraInside) { + this.collectOutside(indexBuffer, cameraPos); + } else { + this.collectInside(indexBuffer, cameraPos); + } + if (this.onPlaneQuads != null) { + TranslucentData.writeQuadVertexIndexes(indexBuffer, this.onPlaneQuads); + } + if (cameraInside) { + this.collectInside(indexBuffer, cameraPos); + } else { + this.collectOutside(indexBuffer, cameraPos); + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerMultiPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerMultiPartitionBSPNode.java new file mode 100644 index 0000000000..dce56fbd92 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerMultiPartitionBSPNode.java @@ -0,0 +1,71 @@ +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; + +import java.nio.IntBuffer; + +import org.joml.Vector3fc; + +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; + +class InnerMultiPartitionBSPNode extends InnerPartitionBSPNode { + private final float[] planeDistances; // one less than there are partitions + + private final BSPNode[] partitions; + private final int[][] onPlaneQuads; + + InnerMultiPartitionBSPNode(float[] planeDistances, Vector3fc planeNormal, + BSPNode[] partitions, int[][] onPlaneQuads) { + super(planeNormal); + this.planeDistances = planeDistances; + this.partitions = partitions; + this.onPlaneQuads = onPlaneQuads; + } + + private void collectPlaneQuads(IntBuffer indexBuffer, int planeIndex) { + if (this.onPlaneQuads[planeIndex] != null) { + TranslucentData.writeQuadVertexIndexes(indexBuffer, this.onPlaneQuads[planeIndex]); + } + } + + private void collectPartitionQuads(IntBuffer indexBuffer, int partitionIndex, Vector3fc cameraPos) { + if (this.partitions[partitionIndex] != null) { + this.partitions[partitionIndex].collectSortedQuads(indexBuffer, cameraPos); + } + } + + @Override + public void collectSortedQuads(IntBuffer indexBuffer, Vector3fc cameraPos) { + // calculate the camera's distance. Then render the partitions in order of + // distance to the partition the camera is in. + var cameraDistance = this.planeNormal.dot(cameraPos); + + // forward sweep: collect quads until the camera is in the partition + for (int i = 0; i < this.planeDistances.length; i++) { + if (cameraDistance <= this.planeDistances[i]) { + // collect the plane the camera is in + var isOnPlane = cameraDistance == this.planeDistances[i]; + if (isOnPlane) { + this.collectPartitionQuads(indexBuffer, i, cameraPos); + } + + // backwards sweep: collect all partitions backwards until the camera is reached + for (int j = this.planeDistances.length; j > i; j--) { + this.collectPartitionQuads(indexBuffer, j, cameraPos); + this.collectPlaneQuads(indexBuffer, j - 1); + } + + if (!isOnPlane) { + this.collectPartitionQuads(indexBuffer, i, cameraPos); + } + + return; + } + + // collect the quads in the partition and on the plane + this.collectPartitionQuads(indexBuffer, i, cameraPos); + this.collectPlaneQuads(indexBuffer, i); + } + + // collect the last partition + this.collectPartitionQuads(indexBuffer, this.planeDistances.length, cameraPos); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java new file mode 100644 index 0000000000..88d2a0e152 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java @@ -0,0 +1,282 @@ +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; + +import java.util.Comparator; + +import org.joml.Vector3fc; + +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.objects.ReferenceArrayList; +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TopoGraphSorting; + +/** + * TODO: + * - make partition finding more sophisticated by using distancesByNormal + * and other information. + * - pass partition information to child nodes instead of discarding if + * partition didn't work + * - detect many coplanar quads and avoid partitioning sorting alltogether. Try + * to partition so that large groups of coplanar quads are kept together and + * then not sorted at all. + * - sort the quads inside a node using the same heuristics as in the global + * level: convex hulls (like cuboids where the faces point outwards) don't need + * to be sorted. This could be used to optimize the inside of honey blocks, and + * other blocks. + */ +abstract class InnerPartitionBSPNode extends BSPNode { + final Vector3fc planeNormal; + + InnerPartitionBSPNode(Vector3fc planeNormal) { + this.planeNormal = planeNormal; + } + + private static record IntervalPoint(float distance, int quadIndex, byte type) { + // the indices of the type are chosen such that tie-breaking items that have the + // same distance with the type ascending yields a beneficial sort order + // (END of the current interval, on-edge quads, then the START of the next + // interval) + + // the start of a quad's extent in this direction + static final byte START = 2; + + // end end of a quad's extent in this direction + static final byte END = 0; + + // looking at a quad from the side where it has zero thickness + static final byte SIDE = 1; + } + + private static final Comparator INTERVAL_POINT_COMPARATOR = (a, b) -> { + // sort by distance ascending + float distanceDiff = a.distance() - b.distance(); + if (distanceDiff != 0) { + return distanceDiff < 0 ? -1 : 1; + } + + // sort by type ascending + return a.type() - b.type(); + }; + + /** + * models a partition of the space into a set of quads that lie inside or on the + * plane with the specified distance. If the distance is -1 this is the "end" + * partition after the last partition plane. + */ + private static record Partition(float distance, IntArrayList quadsBefore, IntArrayList quadsOn) { + } + + static BSPNode build(BSPWorkspace workspace) { + // special case two quads + if (workspace.indexes.size() == 2) { + var quadA = workspace.quads[workspace.indexes.getInt(0)]; + var quadB = workspace.quads[workspace.indexes.getInt(1)]; + + // check for coplanar or mutually invisible quads + var facingA = quadA.facing(); + var facingB = quadB.facing(); + var normalA = quadA.normal(); + var normalB = quadB.normal(); + if ( + // coplanar quads + ((facingA == ModelQuadFacing.UNASSIGNED || facingB == ModelQuadFacing.UNASSIGNED) + ? // opposite normal (distance irrelevant) + normalA.x() == -normalB.x() + && normalA.y() == -normalB.y() + && normalA.z() == -normalB.z() + // same normal and same distance + || normalA.equals(quadB.normal()) + && normalA.dot(quadA.center()) == quadB.normal().dot(quadB.center()) + // aligned same distance + : quadA.extents()[facingA.ordinal()] == quadB.extents()[facingB.ordinal()]) + // facing away from eachother + || facingA == facingB.getOpposite() + // otherwise mutually invisible + || facingA != ModelQuadFacing.UNASSIGNED + && facingB != ModelQuadFacing.UNASSIGNED + && !TopoGraphSorting.orthogonalQuadVisibleThrough(quadA, quadB) + && !TopoGraphSorting.orthogonalQuadVisibleThrough(quadB, quadA)) { + return new LeafMultiBSPNode(workspace.indexes.toIntArray()); + } + } + + ReferenceArrayList partitions = new ReferenceArrayList<>(); + ReferenceArrayList points = new ReferenceArrayList<>( + (int) (workspace.indexes.size() * 1.5)); + + // find any aligned partition, search each axis + for (int axis = 0; axis < 3; axis++) { + var facing = ModelQuadFacing.VALUES[axis]; + var oppositeFacing = facing.getOpposite(); + var oppositeDirection = oppositeFacing.ordinal(); + + // collect all the geometry's start and end points in this direction + points.clear(); + for (int quadIndex : workspace.indexes) { + var quad = workspace.quads[quadIndex]; + var extents = quad.extents(); + var posExtent = extents[axis]; + var negExtent = extents[oppositeDirection]; + if (posExtent == negExtent) { + points.add(new IntervalPoint(posExtent, quadIndex, IntervalPoint.SIDE)); + } else { + points.add(new IntervalPoint(posExtent, quadIndex, IntervalPoint.END)); + points.add(new IntervalPoint(negExtent, quadIndex, IntervalPoint.START)); + } + } + + points.sort(INTERVAL_POINT_COMPARATOR); + + // find gaps + partitions.clear(); + float distance = -1; + IntArrayList quadsBefore = null; + IntArrayList quadsOn = null; + int thickness = 0; + for (InnerPartitionBSPNode.IntervalPoint point : points) { + switch (point.type()) { + case IntervalPoint.START -> { + // unless at the start, flush if there's a gap + if (thickness == 0 && (quadsBefore != null || quadsOn != null)) { + partitions.add(new Partition(distance, quadsBefore, quadsOn)); + distance = -1; + quadsBefore = null; + quadsOn = null; + } + + thickness++; + + // flush to partition if still writing last partition + if (quadsOn != null) { + if (distance == -1) { + throw new IllegalStateException("distance not set"); + } + partitions.add(new Partition(distance, quadsBefore, quadsOn)); + distance = -1; + quadsOn = null; + quadsOn = null; + } + if (quadsBefore == null) { + quadsBefore = new IntArrayList(); + } + quadsBefore.add(point.quadIndex()); + } + case IntervalPoint.END -> { + thickness--; + if (quadsOn == null) { + distance = point.distance(); + } + } + case IntervalPoint.SIDE -> { + // if this point in a gap, it can be put on the plane itself + if (thickness == 0) { + if (quadsOn == null) { + // no partition end created yet, set here + quadsOn = new IntArrayList(); + distance = point.distance(); + } else if (distance != point.distance()) { + // partition end has passed already, flush for new partition plane distance + partitions.add(new Partition(distance, quadsBefore, quadsOn)); + distance = point.distance(); + quadsBefore = null; + quadsOn = new IntArrayList(); + } + quadsOn.add(point.quadIndex()); + } else { + if (quadsBefore == null) { + throw new IllegalStateException("there must be started intervals here"); + } + quadsBefore.add(point.quadIndex()); + if (quadsOn == null) { + distance = point.distance(); + } + } + } + } + } + + // check a different axis if everything is in one quadsBefore, + // which means there are no gaps + if (quadsBefore != null && quadsBefore.size() == workspace.indexes.size()) { + // TODO: reuse the sorted point array for child nodes (add to workspace) + continue; + } + + // check if there's a trailing plane. Otherwise the last plane has distance -1 + // since it just holds the trailing quads + boolean trailingPlane = quadsOn != null; + + // flush the last partition, use the -1 distance to indicate the end if it + // doesn't use quadsOn (which requires a certain distance to be given) + if (quadsBefore != null || quadsOn != null) { + partitions.add(new Partition(trailingPlane ? distance : -1, quadsBefore, quadsOn)); + } + + // check if this can be turned into a binary partition node + // (if there's at most two partitions and one plane) + if (partitions.size() <= 2) { + // get the two partitions + var inside = partitions.get(0); + var outside = partitions.size() == 2 ? partitions.get(1) : null; + if (outside == null || !trailingPlane) { + var partitionDistance = inside.distance(); + workspace.addAlignedPartitionPlane(axis, partitionDistance); + + BSPNode insideNode = null; + BSPNode outsideNode = null; + if (inside.quadsBefore() != null) { + workspace.indexes = inside.quadsBefore(); + insideNode = BSPNode.build(workspace); + } + if (outside != null) { + workspace.indexes = outside.quadsBefore(); + outsideNode = BSPNode.build(workspace); + } + var onPlane = inside.quadsOn() == null ? null : inside.quadsOn().toIntArray(); + + return new InnerBinaryPartitionBSPNode( + partitionDistance, ModelQuadFacing.NORMALS[axis], + insideNode, outsideNode, onPlane); + } + } + + // create a multi-partition node + int planeCount = trailingPlane ? partitions.size() : partitions.size() - 1; + float[] planeDistances = new float[planeCount]; + BSPNode[] partitionNodes = new BSPNode[planeCount + 1]; + int[][] onPlaneQuads = new int[planeCount][]; + + // write the partition planes and nodes + for (int i = 0, count = partitions.size(); i < count; i++) { + var partition = partitions.get(i); + + // if the partition actually has a plane + if (trailingPlane || i < count - 1) { + var partitionDistance = partition.distance(); + workspace.addAlignedPartitionPlane(axis, partitionDistance); + + // TODO: remove + if (partitionDistance == -1) { + throw new IllegalStateException("partition distance not set"); + } + + planeDistances[i] = partitionDistance; + } + + if (partition.quadsBefore() != null) { + workspace.indexes = partition.quadsBefore(); + partitionNodes[i] = BSPNode.build(workspace); + } + if (partition.quadsOn() != null) { + onPlaneQuads[i] = partition.quadsOn().toIntArray(); + } + } + + return new InnerMultiPartitionBSPNode(planeDistances, ModelQuadFacing.NORMALS[axis], + partitionNodes, onPlaneQuads); + } + + // TODO: attempt unaligned partitioning, convex decomposition, etc. + + throw new BSPBuildFailureException("no partition found"); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafMultiBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafMultiBSPNode.java new file mode 100644 index 0000000000..e59757a7da --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafMultiBSPNode.java @@ -0,0 +1,20 @@ +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; + +import java.nio.IntBuffer; + +import org.joml.Vector3fc; + +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; + +class LeafMultiBSPNode extends BSPNode { + private final int[] quads; + + LeafMultiBSPNode(int[] quads) { + this.quads = quads; + } + + @Override + public void collectSortedQuads(IntBuffer indexBuffer, Vector3fc cameraPos) { + TranslucentData.writeQuadVertexIndexes(indexBuffer, this.quads); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafSingleBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafSingleBSPNode.java new file mode 100644 index 0000000000..9b6815bcb7 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafSingleBSPNode.java @@ -0,0 +1,20 @@ +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; + +import java.nio.IntBuffer; + +import org.joml.Vector3fc; + +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; + +class LeafSingleBSPNode extends BSPNode { + private final int quad; + + LeafSingleBSPNode(int quad) { + this.quad = quad; + } + + @Override + public void collectSortedQuads(IntBuffer indexBuffer, Vector3fc cameraPos) { + TranslucentData.writeQuadVertexIndexes(indexBuffer, this.quad); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AnyOrderData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/AnyOrderData.java similarity index 80% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AnyOrderData.java rename to src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/AnyOrderData.java index dc6163530f..7d22419a77 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AnyOrderData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/AnyOrderData.java @@ -1,7 +1,9 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data; import me.jellysquid.mods.sodium.client.gl.util.VertexRange; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortType; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; import me.jellysquid.mods.sodium.client.util.NativeBuffer; import net.minecraft.util.math.ChunkSectionPos; @@ -25,11 +27,9 @@ public SortType getSortType() { return SortType.NONE; } - static AnyOrderData fromMesh(BuiltSectionMeshParts translucentMesh, + public static AnyOrderData fromMesh(BuiltSectionMeshParts translucentMesh, TQuad[] quads, ChunkSectionPos sectionPos, NativeBuffer buffer) { - if (buffer == null) { - buffer = PresentTranslucentData.nativeBufferForQuads(quads); - } + buffer = PresentTranslucentData.nativeBufferForQuads(buffer, quads); var indexBuffer = buffer.getDirectBuffer().asIntBuffer(); var counter = 0; var lastFacing = quads[0].facing(); @@ -39,7 +39,7 @@ static AnyOrderData fromMesh(BuiltSectionMeshParts translucentMesh, counter = 0; } lastFacing = currentFacing; - TranslucentData.putQuadVertexIndexes(indexBuffer, counter++); + TranslucentData.writeQuadVertexIndexes(indexBuffer, counter++); } return new AnyOrderData(sectionPos, buffer, translucentMesh.getVertexRanges()); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java new file mode 100644 index 0000000000..6cc75b0f34 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java @@ -0,0 +1,67 @@ +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data; + +import org.joml.Vector3fc; + +import me.jellysquid.mods.sodium.client.gl.util.VertexRange; +import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TranslucentGeometryCollector; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree.BSPNode; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree.BSPResult; +import me.jellysquid.mods.sodium.client.util.NativeBuffer; +import net.minecraft.util.math.ChunkSectionPos; + +public class BSPDynamicData extends DynamicData { + private final BSPNode rootNode; + + private BSPDynamicData(ChunkSectionPos sectionPos, + NativeBuffer buffer, VertexRange range, BSPResult result) { + super(sectionPos, buffer, range, result); + this.rootNode = result.getRootNode(); + } + + @Override + public void sortOnTrigger(Vector3fc cameraPos) { + this.sort(cameraPos); + } + + private void sort(Vector3fc cameraPos) { + this.unsetReuseUploadedData(); + + this.rootNode.collectSortedQuads( + this.getBuffer().getDirectBuffer().asIntBuffer(), cameraPos); + } + + public static BSPDynamicData fromMesh(BuiltSectionMeshParts translucentMesh, + Vector3fc cameraPos, TQuad[] quads, ChunkSectionPos sectionPos, TranslucentGeometryCollector collector, + NativeBuffer buffer) { + var result = BSPNode.buildBSP(quads, sectionPos); + + VertexRange range = TranslucentData.getUnassignedVertexRange(translucentMesh); + buffer = PresentTranslucentData.nativeBufferForQuads(buffer, quads); + + var dynamicData = new BSPDynamicData(sectionPos, buffer, range, result); + dynamicData.sort(cameraPos); + + // prepare accumulation groups for integration into GFNI triggering + // TODO: combine this and the similar code in TopoSortDynamicData + var aligned = result.getAlignedDistances(); + if (aligned != null) { + for (var accGroup : aligned) { + if (accGroup != null) { + accGroup.prepareIntegration(); + } + } + } + var unaligned = result.getUnalignedDistances(); + if (unaligned != null) { + for (var accGroup : unaligned) { + if (accGroup != null) { + accGroup.prepareIntegration(); + } + } + } + + return dynamicData; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicData.java new file mode 100644 index 0000000000..41858d714b --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicData.java @@ -0,0 +1,29 @@ +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data; + +import me.jellysquid.mods.sodium.client.gl.util.VertexRange; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.AccGroupResult; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortType; +import me.jellysquid.mods.sodium.client.util.NativeBuffer; +import net.minecraft.util.math.ChunkSectionPos; + +public abstract class DynamicData extends MixedDirectionData { + private AccGroupResult accGroupResult; + + DynamicData(ChunkSectionPos sectionPos, NativeBuffer buffer, VertexRange range, AccGroupResult accGroupResult) { + super(sectionPos, buffer, range); + this.accGroupResult = accGroupResult; + } + + @Override + public SortType getSortType() { + return SortType.DYNAMIC_ALL; + } + + public AccGroupResult getAccGroupResult() { + return this.accGroupResult; + } + + public void clearAccGroupData() { + this.accGroupResult = null; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/MixedDirectionData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/MixedDirectionData.java similarity index 98% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/MixedDirectionData.java rename to src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/MixedDirectionData.java index 2bb5015f58..873dacd611 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/MixedDirectionData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/MixedDirectionData.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data; import me.jellysquid.mods.sodium.client.gl.util.VertexRange; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/NoData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/NoData.java similarity index 85% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/NoData.java rename to src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/NoData.java index ed32276a1e..b72ef326ad 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/NoData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/NoData.java @@ -1,5 +1,6 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortType; import net.minecraft.util.math.ChunkSectionPos; /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/PresentTranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/PresentTranslucentData.java similarity index 71% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/PresentTranslucentData.java rename to src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/PresentTranslucentData.java index 745d46c11e..f5655be082 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/PresentTranslucentData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/PresentTranslucentData.java @@ -1,6 +1,7 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data; import me.jellysquid.mods.sodium.client.gl.util.VertexRange; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; import me.jellysquid.mods.sodium.client.util.NativeBuffer; import net.minecraft.util.math.ChunkSectionPos; @@ -30,15 +31,15 @@ public void delete() { } } - void setQuadHash(int hash) { + public void setQuadHash(int hash) { this.quadHash = hash; } - int getQuadHash() { + public int getQuadHash() { return this.quadHash; } - int getLength() { + public int getLength() { return this.length; } @@ -50,15 +51,22 @@ public boolean isReusingUploadedData() { return this.reuseUploadedData; } - void setReuseUploadedData() { + public void setReuseUploadedData() { this.reuseUploadedData = true; } - void unsetReuseUploadedData() { + public void unsetReuseUploadedData() { this.reuseUploadedData = false; } - static NativeBuffer nativeBufferForQuads(TQuad[] quads) { + public static NativeBuffer nativeBufferForQuads(TQuad[] quads) { return new NativeBuffer(TranslucentData.quadCountToIndexBytes(quads.length)); } + + public static NativeBuffer nativeBufferForQuads(NativeBuffer existing, TQuad[] quads) { + if (existing != null) { + return existing; + } + return nativeBufferForQuads(quads); + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SplitDirectionData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/SplitDirectionData.java similarity index 98% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SplitDirectionData.java rename to src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/SplitDirectionData.java index 97c543c47b..6e4581fe6f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SplitDirectionData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/SplitDirectionData.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data; import me.jellysquid.mods.sodium.client.gl.util.VertexRange; import me.jellysquid.mods.sodium.client.util.NativeBuffer; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/StaticNormalRelativeData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java similarity index 91% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/StaticNormalRelativeData.java rename to src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java index 175014a02e..1142860d0c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/StaticNormalRelativeData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data; import java.nio.IntBuffer; @@ -9,6 +9,9 @@ import me.jellysquid.mods.sodium.client.gl.util.VertexRange; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortType; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TranslucentGeometryCollector; import me.jellysquid.mods.sodium.client.util.NativeBuffer; import me.jellysquid.mods.sodium.client.util.sorting.MergeSort; import me.jellysquid.mods.sodium.client.util.sorting.VertexSorters; @@ -24,10 +27,6 @@ public SortType getSortType() { return SortType.STATIC_NORMAL_RELATIVE; } - /** - * The vertex sorter for each direction. - * TODO: is there a better place to put this - */ private static final VertexSorter[] SORTERS = new VertexSorter[ModelQuadFacing.DIRECTIONS]; static { @@ -102,9 +101,9 @@ private static StaticNormalRelativeData fromAligned(BuiltSectionMeshParts transl return new StaticNormalRelativeData(sectionPos, buffer, ranges); } - static StaticNormalRelativeData fromMesh(BuiltSectionMeshParts translucentMesh, + public static StaticNormalRelativeData fromMesh(BuiltSectionMeshParts translucentMesh, TQuad[] quads, ChunkSectionPos sectionPos, TranslucentGeometryCollector collector) { - if (collector.alignedNormalBitmap == 0) { + if (collector.getAlignedNormalBitmap() == 0) { return fromDoubleUnaligned(translucentMesh, quads, sectionPos, collector); } else { return fromAligned(translucentMesh, quads, sectionPos); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/StaticTopoAcyclicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticTopoAcyclicData.java similarity index 71% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/StaticTopoAcyclicData.java rename to src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticTopoAcyclicData.java index 1749d79010..8b74aeec5b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/StaticTopoAcyclicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticTopoAcyclicData.java @@ -1,7 +1,10 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data; import me.jellysquid.mods.sodium.client.gl.util.VertexRange; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortType; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TopoGraphSorting; import me.jellysquid.mods.sodium.client.util.NativeBuffer; import net.minecraft.util.math.ChunkSectionPos; @@ -17,7 +20,7 @@ public SortType getSortType() { return SortType.STATIC_TOPO_ACYCLIC; } - static StaticTopoAcyclicData fromMesh(BuiltSectionMeshParts translucentMesh, + public static StaticTopoAcyclicData fromMesh(BuiltSectionMeshParts translucentMesh, TQuad[] quads, ChunkSectionPos sectionPos, NativeBuffer buffer) { if (quads.length > MAX_STATIC_TOPO_SORT_QUADS) { return null; @@ -26,7 +29,7 @@ static StaticTopoAcyclicData fromMesh(BuiltSectionMeshParts translucentMesh, VertexRange range = TranslucentData.getUnassignedVertexRange(translucentMesh); var indexBuffer = buffer.getDirectBuffer().asIntBuffer(); - if (!ComplexSorting.topoSortDepthFirstCyclic(indexBuffer, quads, null, null)) { + if (!TopoGraphSorting.topoSortDepthFirstCyclic(indexBuffer, quads, null, null)) { return null; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/DynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java similarity index 62% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/DynamicData.java rename to src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java index 1bfe511a0a..6575a7b3a8 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/DynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data; import java.nio.IntBuffer; @@ -8,21 +8,24 @@ import me.jellysquid.mods.sodium.client.gl.util.VertexRange; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TopoGraphSorting; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TranslucentGeometryCollector; import me.jellysquid.mods.sodium.client.util.NativeBuffer; +import me.jellysquid.mods.sodium.client.util.sorting.MergeSort; import net.minecraft.util.math.ChunkSectionPos; -public class DynamicData extends MixedDirectionData { +public class TopoSortDynamicData extends DynamicData { private final TQuad[] quads; - boolean GFNITrigger = true; - boolean directTrigger = false; - boolean turnGFNITriggerOff = false; - boolean turnDirectTriggerOn = false; - boolean turnDirectTriggerOff = false; - double directTriggerKey = -1; + private boolean GFNITrigger = true; + private boolean directTrigger = false; + private boolean turnGFNITriggerOff = false; + private boolean turnDirectTriggerOn = false; + private boolean turnDirectTriggerOff = false; + private double directTriggerKey = -1; private int consecutiveTopoSortFailures = 0; private boolean pendingTriggerIsAngle; - private TranslucentGeometryCollector collector; - private Object2ReferenceOpenHashMap distancesByNormal; + private Object2ReferenceOpenHashMap distancesByNormal; private int[] distanceSortIndexes; private static final int MAX_TOPO_SORT_QUADS = 1000; @@ -32,29 +35,27 @@ public class DynamicData extends MixedDirectionData { private static final int PATIENT_TOPO_ATTEMPTS = 5; private static final int REGULAR_TOPO_ATTEMPTS = 2; - DynamicData(ChunkSectionPos sectionPos, + private TopoSortDynamicData(ChunkSectionPos sectionPos, NativeBuffer buffer, VertexRange range, TQuad[] quads, TranslucentGeometryCollector collector, - Object2ReferenceOpenHashMap distancesByNormal) { - super(sectionPos, buffer, range); + Object2ReferenceOpenHashMap distancesByNormal) { + super(sectionPos, buffer, range, collector); this.quads = quads; - this.collector = collector; this.distancesByNormal = distancesByNormal; } - @Override - public SortType getSortType() { - return SortType.DYNAMIC_ALL; + public boolean GFNITriggerEnabled() { + return this.GFNITrigger; } - @Override - public void prepareTrigger(boolean isAngleTrigger) { - this.pendingTriggerIsAngle = isAngleTrigger; + public boolean directTriggerEnabled() { + return this.directTrigger; } - @Override - public void sortOnTrigger(Vector3fc cameraPos) { - this.sort(cameraPos, this.pendingTriggerIsAngle, false); + public void clearTriggerChanges() { + this.turnGFNITriggerOff = false; + this.turnDirectTriggerOn = false; + this.turnDirectTriggerOff = false; } private void turnGFNITriggerOff() { @@ -79,6 +80,42 @@ private void turnDirectTriggerOff() { this.distanceSortIndexes = null; } + public boolean getAndFlushTurnGFNITriggerOff() { + var result = this.turnGFNITriggerOff; + this.turnGFNITriggerOff = false; + return result; + } + + public boolean getAndFlushTurnDirectTriggerOn() { + var result = this.turnDirectTriggerOn; + this.turnDirectTriggerOn = false; + return result; + } + + public boolean getAndFlushTurnDirectTriggerOff() { + var result = this.turnDirectTriggerOff; + this.turnDirectTriggerOff = false; + return result; + } + + public double getDirectTriggerKey() { + return this.directTriggerKey; + } + + public void setDirectTriggerKey(double key) { + this.directTriggerKey = key; + } + + @Override + public void prepareTrigger(boolean isAngleTrigger) { + this.pendingTriggerIsAngle = isAngleTrigger; + } + + @Override + public void sortOnTrigger(Vector3fc cameraPos) { + this.sort(cameraPos, this.pendingTriggerIsAngle, false); + } + private static int getAttemptsForTime(long ns) { return ns <= MAX_TOPO_SORT_PATIENT_TIME_NS ? PATIENT_TOPO_ATTEMPTS : REGULAR_TOPO_ATTEMPTS; } @@ -98,7 +135,7 @@ private void sort(Vector3fc cameraPos, boolean isAngleTrigger, boolean initial) if (this.GFNITrigger && !isAngleTrigger) { var sortStart = initial ? 0 : System.nanoTime(); - var result = ComplexSorting.topoSortDepthFirstCyclic( + var result = TopoGraphSorting.topoSortDepthFirstCyclic( indexBuffer, this.quads, this.distancesByNormal, cameraPos); var sortTime = initial ? 0 : System.nanoTime() - sortStart; @@ -134,56 +171,58 @@ private void sort(Vector3fc cameraPos, boolean isAngleTrigger, boolean initial) if (this.directTrigger) { indexBuffer.rewind(); - this.distanceSortIndexes = ComplexSorting.distanceSortDirect( + this.distanceSortIndexes = distanceSortDirect( this.distanceSortIndexes, indexBuffer, this.quads, cameraPos); return; } } - public void clearTriggerChanges() { - this.turnGFNITriggerOff = false; - this.turnDirectTriggerOn = false; - this.turnDirectTriggerOff = false; - } + private static ThreadLocal distanceSortKeys = new ThreadLocal<>(); - public boolean hasTriggerChanges() { - return this.turnGFNITriggerOff || this.turnDirectTriggerOn || this.turnDirectTriggerOff; - } + public static int[] distanceSortDirect(int[] indexes, + IntBuffer indexBuffer, TQuad[] quads, Vector3fc cameraPos) { + if (indexes == null) { + indexes = new int[quads.length]; + for (int i = 0; i < quads.length; i++) { + indexes[i] = i; + } + } - TranslucentGeometryCollector getCollector() { - return this.collector; - } + float[] keys = distanceSortKeys.get(); + if (keys == null || keys.length < quads.length) { + keys = new float[quads.length]; + distanceSortKeys.set(keys); + } + + for (int i = 0; i < quads.length; i++) { + keys[i] = cameraPos.distanceSquared(quads[i].center()); + } + + MergeSort.mergeSort(indexes, keys); + TranslucentData.writeQuadVertexIndexes(indexBuffer, indexes); - void deleteCollector() { - this.collector = null; + return indexes; } - static DynamicData fromMesh(BuiltSectionMeshParts translucentMesh, + public static TopoSortDynamicData fromMesh(BuiltSectionMeshParts translucentMesh, Vector3fc cameraPos, TQuad[] quads, ChunkSectionPos sectionPos, TranslucentGeometryCollector collector, NativeBuffer buffer) { // prepare accumulation groups for GFNI integration and copy - var size = 0; - if (collector.axisAlignedDistances != null) { - size += Integer.bitCount(collector.alignedNormalBitmap); - } - if (collector.unalignedDistances != null) { - size += collector.unalignedDistances.size(); - } - var distancesByNormal = new Object2ReferenceOpenHashMap(size); - if (collector.axisAlignedDistances != null) { + var size = Integer.bitCount(collector.getAlignedNormalBitmap()) + collector.getUnalignedDistanceCount(); + + var distancesByNormal = new Object2ReferenceOpenHashMap(size); + if (collector.getAlignedDistances() != null) { for (int direction = 0; direction < ModelQuadFacing.DIRECTIONS; direction++) { - var accGroup = collector.axisAlignedDistances[direction]; + var accGroup = collector.getAlignedDistances()[direction]; if (accGroup != null) { - accGroup.prepareIntegration(); - distancesByNormal.put(accGroup.normal, accGroup.facePlaneDistances); + accGroup.prepareAndInsert(distancesByNormal); } } } - if (collector.unalignedDistances != null) { - for (var accGroup : collector.unalignedDistances.values()) { + if (collector.getUnalignedDistanceCount() > 0) { + for (var accGroup : collector.getUnalignedDistances()) { // TODO: get rid of collector key and just use the normal vector's hash code - accGroup.prepareIntegration(); - distancesByNormal.put(accGroup.normal, accGroup.facePlaneDistances); + accGroup.prepareAndInsert(distancesByNormal); } } @@ -192,10 +231,11 @@ static DynamicData fromMesh(BuiltSectionMeshParts translucentMesh, buffer = PresentTranslucentData.nativeBufferForQuads(quads); } - var dynamicData = new DynamicData(sectionPos, buffer, range, quads, collector, distancesByNormal); + var dynamicData = new TopoSortDynamicData(sectionPos, buffer, range, quads, collector, distancesByNormal); dynamicData.sort(cameraPos, false, true); return dynamicData; } + } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TranslucentData.java similarity index 80% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentData.java rename to src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TranslucentData.java index 955b3301aa..9036b69c31 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TranslucentData.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data; import java.nio.IntBuffer; @@ -7,6 +7,7 @@ import me.jellysquid.mods.sodium.client.gl.util.VertexRange; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortType; import net.minecraft.util.math.ChunkSectionPos; /** @@ -41,7 +42,7 @@ public void sortOnTrigger(Vector3fc cameraPos) { * @param isAngleTrigger Whether the trigger is an angle trigger */ public void prepareTrigger(boolean isAngleTrigger) { - // no-op for other translucent data than dynamic + // no-op for other translucent data than GFNI dynamic } static int vertexCountToIndexBytes(int vertexCount) { @@ -57,15 +58,15 @@ static int indexBytesToQuadCount(int indexBytes) { return indexBytes / BYTES_PER_QUAD; } - static void putMappedQuadVertexIndexes(IntBuffer intBuffer, int quadIndex, int[] indexMapping) { + public static void writeMappedQuadVertexIndexes(IntBuffer intBuffer, int quadIndex, int[] indexMapping) { if (indexMapping == null) { - putQuadVertexIndexes(intBuffer, quadIndex); + writeQuadVertexIndexes(intBuffer, quadIndex); } else { - putQuadVertexIndexes(intBuffer, indexMapping[quadIndex]); + writeQuadVertexIndexes(intBuffer, indexMapping[quadIndex]); } } - static void putQuadVertexIndexes(IntBuffer intBuffer, int quadIndex) { + public static void writeQuadVertexIndexes(IntBuffer intBuffer, int quadIndex) { int vertexOffset = quadIndex * VERTICES_PER_QUAD; intBuffer.put(vertexOffset + 0); @@ -77,9 +78,9 @@ static void putQuadVertexIndexes(IntBuffer intBuffer, int quadIndex) { intBuffer.put(vertexOffset + 0); } - static void writeQuadVertexIndexes(IntBuffer intBuffer, int[] quadIndexes) { + public static void writeQuadVertexIndexes(IntBuffer intBuffer, int[] quadIndexes) { for (int quadIndexPos = 0; quadIndexPos < quadIndexes.length; quadIndexPos++) { - putQuadVertexIndexes(intBuffer, quadIndexes[quadIndexPos]); + writeQuadVertexIndexes(intBuffer, quadIndexes[quadIndexPos]); } } From 3d512959646915eb31a37dc6a2d2265d9d45f9ff Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 24 Nov 2023 15:08:02 +0100 Subject: [PATCH 132/256] do gfni trigger before section update to avoid artifacts --- .../sodium/client/render/SodiumWorldRenderer.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index 36485b3cb4..1531ba64e4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -187,6 +187,13 @@ public void setupTerrain(Camera camera, this.lastCameraYaw = yaw; this.lastFogDistance = fogDistance; + if (cameraLocationChanged) { + profiler.swap("translucent_triggering"); + + this.renderSectionManager.processGFNIMovement(new CameraMovement(lastCameraPos, pos)); + this.lastCameraPos = new Vector3d(pos); + } + profiler.swap("chunk_update"); this.renderSectionManager.updateChunks(updateChunksImmediately); @@ -201,13 +208,6 @@ public void setupTerrain(Camera camera, this.renderSectionManager.update(pos, camera, viewport, frame, spectator); } - if (cameraLocationChanged) { - profiler.swap("translucent_triggering"); - - this.renderSectionManager.processGFNIMovement(new CameraMovement(lastCameraPos, pos)); - this.lastCameraPos = new Vector3d(pos); - } - if (updateChunksImmediately) { profiler.swap("chunk_upload_immediately"); From 4738b968658d9cdf066013dad63df633e1227d46 Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 24 Nov 2023 16:35:32 +0100 Subject: [PATCH 133/256] consistent formatting --- .../translucent_sorting/DirectTriggers.java | 386 +++++++++--------- .../translucent_sorting/GFNITriggers.java | 172 ++++---- .../chunk/translucent_sorting/TQuad.java | 24 +- .../bsp_tree/BSPResult.java | 1 - .../data/BSPDynamicData.java | 86 ++-- 5 files changed, 334 insertions(+), 335 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/DirectTriggers.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/DirectTriggers.java index 4e51d67c39..b72b491a65 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/DirectTriggers.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/DirectTriggers.java @@ -14,197 +14,197 @@ * topologically sorted and thus aren't eligible for GFNI triggering. */ class DirectTriggers implements SectionTriggers { - /** - * A tree map of the directly triggered sections, indexed by their - * minimum required camera movement. When the given camera movement is exceeded, - * they are tested for triggering the angle or distance condition. - * - * The accumulated distance is monotonically increasing and is never reset. This - * only becomes a problem when the camera moves more than 10^15 blocks in total. - * There will be precision issues at around 10^10 maybe, but it's still not a - * concern. - */ - private Double2ObjectRBTreeMap directTriggerSections = new Double2ObjectRBTreeMap<>(); - private double accumulatedDistance = 0; - - /** - * The factor by which the trigger distance and angle are multiplied to get a - * smaller threshold that is used for the actual trigger check but not the - * remaining distance calculation. This prevents curved movements from taking - * sections out of the tree and re-inserting without triggering many times near - * the actual trigger distance. It cuts the repeating unsuccessful trigger - * attempts off early. - */ - private static final double EARLY_TRIGGER_FACTOR = 0.9; - - /** - * Degrees of movement from last sort position before the section is sorted - * again. - */ - private static final double TRIGGER_ANGLE = Math.toRadians(20); - private static final double EARLY_TRIGGER_ANGLE_COS = Math.cos(TRIGGER_ANGLE * EARLY_TRIGGER_FACTOR); - private static final double SECTION_CENTER_DIST_SQUARED = 40 * 3 * Math.pow(16 / 2, 2); - private static final double SECTION_CENTER_DIST = Math.sqrt(SECTION_CENTER_DIST_SQUARED); - - /** - * How far the player must travel in blocks from the last position at which a - * section was sorted for it to be sorted again, if direct distance triggering - * is used (for close sections). - */ - private static final double DIRECT_TRIGGER_DISTANCE = 1; - private static final double EARLY_DIRECT_TRIGGER_DISTANCE_SQUARED = Math - .pow(DIRECT_TRIGGER_DISTANCE * EARLY_TRIGGER_FACTOR, 2); - - int getDirectTriggerCount() { - return this.directTriggerSections.size(); - } - - private class DirectTriggerData { - final ChunkSectionPos sectionPos; - private Vector3dc sectionCenter; - final TopoSortDynamicData dynamicData; - DirectTriggerData next; - - /** - * Absolute camera position at the time of the last trigger. - */ - Vector3dc triggerCameraPos; - - DirectTriggerData(TopoSortDynamicData dynamicData, ChunkSectionPos sectionPos, Vector3dc triggerCameraPos) { - this.dynamicData = dynamicData; - this.sectionPos = sectionPos; - this.triggerCameraPos = triggerCameraPos; - } - - Vector3dc getSectionCenter() { - if (this.sectionCenter == null) { - this.sectionCenter = new Vector3d( - sectionPos.getMinX() + 8, - sectionPos.getMinY() + 8, - sectionPos.getMinZ() + 8); - } - return this.sectionCenter; - } - - /** - * Returns the distance between the sort camera pos and the center of the - * section. - */ - double getSectionCenterTriggerCameraDist() { - return Math.sqrt(getSectionCenterDistSquared(this.triggerCameraPos)); - } - - double getSectionCenterDistSquared(Vector3dc vector) { - Vector3dc sectionCenter = getSectionCenter(); - return sectionCenter.distanceSquared(vector); - } - - boolean isAngleTriggering(Vector3dc vector) { - return getSectionCenterDistSquared(vector) > SECTION_CENTER_DIST_SQUARED; - } - } - - // TODO: use faster code for this - private static double angleCos(double ax, double ay, double az, double bx, double by, double bz) { - double length1Squared = Math.fma(ax, ax, Math.fma(ay, ay, az * az)); - double length2Squared = Math.fma(bx, bx, Math.fma(by, by, bz * bz)); - double dot = Math.fma(ax, bx, Math.fma(ay, by, az * bz)); - return dot / Math.sqrt(length1Squared * length2Squared); - } - - private void insertDirectAngleTrigger(DirectTriggerData data, Vector3dc cameraPos, double remainingAngle) { - double triggerCameraSectionCenterDist = data.getSectionCenterTriggerCameraDist(); - double centerMinDistance = Math.tan(remainingAngle) * (triggerCameraSectionCenterDist - SECTION_CENTER_DIST); - this.insertTrigger(this.accumulatedDistance + centerMinDistance, data); - } - - private void insertDirectDistanceTrigger(DirectTriggerData data, Vector3dc cameraPos, double remainingDistance) { - this.insertTrigger(this.accumulatedDistance + remainingDistance, data); - } - - private void insertTrigger(double key, DirectTriggerData data) { - data.dynamicData.setDirectTriggerKey(key); - - // attach the previous value after the current one in the list. if there is none - // it's just null - data.next = this.directTriggerSections.put(key, data); - } - - @Override - public void processTriggers(TranslucentSorting ts, CameraMovement movement) { - Vector3dc lastCamera = movement.lastCamera(); - Vector3dc camera = movement.currentCamera(); - this.accumulatedDistance += lastCamera.distance(camera); - - // iterate all elements with a key of at most accumulatedDistance - var head = this.directTriggerSections.headMap(this.accumulatedDistance); - for (var entry : head.double2ObjectEntrySet()) { - this.directTriggerSections.remove(entry.getDoubleKey()); - var data = entry.getValue(); - while (data != null) { - // get the next element before it's modified by the data being re-inserted into - // the tree - var next = data.next; - - if (data.isAngleTriggering(camera)) { - double remainingAngle = TRIGGER_ANGLE; - - // check if the angle since the last sort exceeds the threshold - Vector3dc sectionCenter = data.getSectionCenter(); - double angleCos = angleCos( - sectionCenter.x() - data.triggerCameraPos.x(), - sectionCenter.y() - data.triggerCameraPos.y(), - sectionCenter.z() - data.triggerCameraPos.z(), - sectionCenter.x() - camera.x(), - sectionCenter.y() - camera.y(), - sectionCenter.z() - camera.z()); - - // compare angles inverted because cosine flips it - if (angleCos <= EARLY_TRIGGER_ANGLE_COS) { - ts.triggerSectionDirect(data.sectionPos); - data.triggerCameraPos = camera; - } else { - remainingAngle -= Math.acos(angleCos); - } - - this.insertDirectAngleTrigger(data, camera, remainingAngle); - } else { - double remainingDistance = DIRECT_TRIGGER_DISTANCE; - double lastTriggerCurrentCameraDistSquared = data.triggerCameraPos.distanceSquared(camera); - - if (lastTriggerCurrentCameraDistSquared >= EARLY_DIRECT_TRIGGER_DISTANCE_SQUARED) { - ts.triggerSectionDirect(data.sectionPos); - data.triggerCameraPos = camera; - } else { - remainingDistance -= Math.sqrt(lastTriggerCurrentCameraDistSquared); - } - - this.insertDirectDistanceTrigger(data, camera, remainingDistance); - } - - data = next; - } - } - } - - @Override - public void removeSection(long sectionPos, TranslucentData data) { - if (data instanceof TopoSortDynamicData triggerable) { - var key = triggerable.getDirectTriggerKey(); - if (key != -1) { - this.directTriggerSections.remove(key); - triggerable.setDirectTriggerKey(-1); - } - } - } - - @Override - public void addSection(ChunkSectionPos sectionPos, TopoSortDynamicData data, Vector3dc cameraPos) { - var newData = new DirectTriggerData(data, sectionPos, cameraPos); - if (newData.isAngleTriggering(cameraPos)) { - this.insertDirectAngleTrigger(newData, cameraPos, TRIGGER_ANGLE); - } else { - this.insertDirectDistanceTrigger(newData, cameraPos, DIRECT_TRIGGER_DISTANCE); - } - } + /** + * A tree map of the directly triggered sections, indexed by their + * minimum required camera movement. When the given camera movement is exceeded, + * they are tested for triggering the angle or distance condition. + * + * The accumulated distance is monotonically increasing and is never reset. This + * only becomes a problem when the camera moves more than 10^15 blocks in total. + * There will be precision issues at around 10^10 maybe, but it's still not a + * concern. + */ + private Double2ObjectRBTreeMap directTriggerSections = new Double2ObjectRBTreeMap<>(); + private double accumulatedDistance = 0; + + /** + * The factor by which the trigger distance and angle are multiplied to get a + * smaller threshold that is used for the actual trigger check but not the + * remaining distance calculation. This prevents curved movements from taking + * sections out of the tree and re-inserting without triggering many times near + * the actual trigger distance. It cuts the repeating unsuccessful trigger + * attempts off early. + */ + private static final double EARLY_TRIGGER_FACTOR = 0.9; + + /** + * Degrees of movement from last sort position before the section is sorted + * again. + */ + private static final double TRIGGER_ANGLE = Math.toRadians(20); + private static final double EARLY_TRIGGER_ANGLE_COS = Math.cos(TRIGGER_ANGLE * EARLY_TRIGGER_FACTOR); + private static final double SECTION_CENTER_DIST_SQUARED = 40 * 3 * Math.pow(16 / 2, 2); + private static final double SECTION_CENTER_DIST = Math.sqrt(SECTION_CENTER_DIST_SQUARED); + + /** + * How far the player must travel in blocks from the last position at which a + * section was sorted for it to be sorted again, if direct distance triggering + * is used (for close sections). + */ + private static final double DIRECT_TRIGGER_DISTANCE = 1; + private static final double EARLY_DIRECT_TRIGGER_DISTANCE_SQUARED = Math + .pow(DIRECT_TRIGGER_DISTANCE * EARLY_TRIGGER_FACTOR, 2); + + int getDirectTriggerCount() { + return this.directTriggerSections.size(); + } + + private class DirectTriggerData { + final ChunkSectionPos sectionPos; + private Vector3dc sectionCenter; + final TopoSortDynamicData dynamicData; + DirectTriggerData next; + + /** + * Absolute camera position at the time of the last trigger. + */ + Vector3dc triggerCameraPos; + + DirectTriggerData(TopoSortDynamicData dynamicData, ChunkSectionPos sectionPos, Vector3dc triggerCameraPos) { + this.dynamicData = dynamicData; + this.sectionPos = sectionPos; + this.triggerCameraPos = triggerCameraPos; + } + + Vector3dc getSectionCenter() { + if (this.sectionCenter == null) { + this.sectionCenter = new Vector3d( + sectionPos.getMinX() + 8, + sectionPos.getMinY() + 8, + sectionPos.getMinZ() + 8); + } + return this.sectionCenter; + } + + /** + * Returns the distance between the sort camera pos and the center of the + * section. + */ + double getSectionCenterTriggerCameraDist() { + return Math.sqrt(getSectionCenterDistSquared(this.triggerCameraPos)); + } + + double getSectionCenterDistSquared(Vector3dc vector) { + Vector3dc sectionCenter = getSectionCenter(); + return sectionCenter.distanceSquared(vector); + } + + boolean isAngleTriggering(Vector3dc vector) { + return getSectionCenterDistSquared(vector) > SECTION_CENTER_DIST_SQUARED; + } + } + + // TODO: use faster code for this + private static double angleCos(double ax, double ay, double az, double bx, double by, double bz) { + double length1Squared = Math.fma(ax, ax, Math.fma(ay, ay, az * az)); + double length2Squared = Math.fma(bx, bx, Math.fma(by, by, bz * bz)); + double dot = Math.fma(ax, bx, Math.fma(ay, by, az * bz)); + return dot / Math.sqrt(length1Squared * length2Squared); + } + + private void insertDirectAngleTrigger(DirectTriggerData data, Vector3dc cameraPos, double remainingAngle) { + double triggerCameraSectionCenterDist = data.getSectionCenterTriggerCameraDist(); + double centerMinDistance = Math.tan(remainingAngle) * (triggerCameraSectionCenterDist - SECTION_CENTER_DIST); + this.insertTrigger(this.accumulatedDistance + centerMinDistance, data); + } + + private void insertDirectDistanceTrigger(DirectTriggerData data, Vector3dc cameraPos, double remainingDistance) { + this.insertTrigger(this.accumulatedDistance + remainingDistance, data); + } + + private void insertTrigger(double key, DirectTriggerData data) { + data.dynamicData.setDirectTriggerKey(key); + + // attach the previous value after the current one in the list. if there is none + // it's just null + data.next = this.directTriggerSections.put(key, data); + } + + @Override + public void processTriggers(TranslucentSorting ts, CameraMovement movement) { + Vector3dc lastCamera = movement.lastCamera(); + Vector3dc camera = movement.currentCamera(); + this.accumulatedDistance += lastCamera.distance(camera); + + // iterate all elements with a key of at most accumulatedDistance + var head = this.directTriggerSections.headMap(this.accumulatedDistance); + for (var entry : head.double2ObjectEntrySet()) { + this.directTriggerSections.remove(entry.getDoubleKey()); + var data = entry.getValue(); + while (data != null) { + // get the next element before it's modified by the data being re-inserted into + // the tree + var next = data.next; + + if (data.isAngleTriggering(camera)) { + double remainingAngle = TRIGGER_ANGLE; + + // check if the angle since the last sort exceeds the threshold + Vector3dc sectionCenter = data.getSectionCenter(); + double angleCos = angleCos( + sectionCenter.x() - data.triggerCameraPos.x(), + sectionCenter.y() - data.triggerCameraPos.y(), + sectionCenter.z() - data.triggerCameraPos.z(), + sectionCenter.x() - camera.x(), + sectionCenter.y() - camera.y(), + sectionCenter.z() - camera.z()); + + // compare angles inverted because cosine flips it + if (angleCos <= EARLY_TRIGGER_ANGLE_COS) { + ts.triggerSectionDirect(data.sectionPos); + data.triggerCameraPos = camera; + } else { + remainingAngle -= Math.acos(angleCos); + } + + this.insertDirectAngleTrigger(data, camera, remainingAngle); + } else { + double remainingDistance = DIRECT_TRIGGER_DISTANCE; + double lastTriggerCurrentCameraDistSquared = data.triggerCameraPos.distanceSquared(camera); + + if (lastTriggerCurrentCameraDistSquared >= EARLY_DIRECT_TRIGGER_DISTANCE_SQUARED) { + ts.triggerSectionDirect(data.sectionPos); + data.triggerCameraPos = camera; + } else { + remainingDistance -= Math.sqrt(lastTriggerCurrentCameraDistSquared); + } + + this.insertDirectDistanceTrigger(data, camera, remainingDistance); + } + + data = next; + } + } + } + + @Override + public void removeSection(long sectionPos, TranslucentData data) { + if (data instanceof TopoSortDynamicData triggerable) { + var key = triggerable.getDirectTriggerKey(); + if (key != -1) { + this.directTriggerSections.remove(key); + triggerable.setDirectTriggerKey(-1); + } + } + } + + @Override + public void addSection(ChunkSectionPos sectionPos, TopoSortDynamicData data, Vector3dc cameraPos) { + var newData = new DirectTriggerData(data, sectionPos, cameraPos); + if (newData.isAngleTriggering(cameraPos)) { + this.insertDirectAngleTrigger(newData, cameraPos, TRIGGER_ANGLE); + } else { + this.insertDirectDistanceTrigger(newData, cameraPos, DIRECT_TRIGGER_DISTANCE); + } + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/GFNITriggers.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/GFNITriggers.java index 790aa6ce1f..b15517388d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/GFNITriggers.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/GFNITriggers.java @@ -18,100 +18,100 @@ * to produce global double distances. */ class GFNITriggers implements SectionTriggers { - /** - * A map of all the normal lists, indexed by their normal. - */ - private Object2ReferenceOpenHashMap normalLists = new Object2ReferenceOpenHashMap<>(); + /** + * A map of all the normal lists, indexed by their normal. + */ + private Object2ReferenceOpenHashMap normalLists = new Object2ReferenceOpenHashMap<>(); - int getUniqueNormalCount() { - return this.normalLists.size(); - } + int getUniqueNormalCount() { + return this.normalLists.size(); + } - @Override - public void processTriggers(TranslucentSorting ts, CameraMovement movement) { - for (var normalList : this.normalLists.values()) { - normalList.processMovement(ts, movement); - } - } + @Override + public void processTriggers(TranslucentSorting ts, CameraMovement movement) { + for (var normalList : this.normalLists.values()) { + normalList.processMovement(ts, movement); + } + } - private void addSectionInNewNormalLists(DynamicData dynamicData, AccumulationGroup accGroup) { - var normal = accGroup.normal; - var normalList = this.normalLists.get(normal); - if (normalList == null) { - normalList = new NormalList(normal, accGroup.collectorKey); - this.normalLists.put(normal, normalList); - normalList.addSection(accGroup, accGroup.sectionPos.asLong()); - } - } + private void addSectionInNewNormalLists(DynamicData dynamicData, AccumulationGroup accGroup) { + var normal = accGroup.normal; + var normalList = this.normalLists.get(normal); + if (normalList == null) { + normalList = new NormalList(normal, accGroup.collectorKey); + this.normalLists.put(normal, normalList); + normalList.addSection(accGroup, accGroup.sectionPos.asLong()); + } + } - /** - * Removes the section from the normal list and returns whether the normal list - * is now empty and should itself be removed from the normal lists map. This is - * done with a return value so that the iterator can be used to remove it safely - * without a concurrent modification. - */ - private boolean removeSectionFromList(NormalList normalList, long sectionPos) { - normalList.removeSection(sectionPos); - return normalList.isEmpty(); - } + /** + * Removes the section from the normal list and returns whether the normal list + * is now empty and should itself be removed from the normal lists map. This is + * done with a return value so that the iterator can be used to remove it safely + * without a concurrent modification. + */ + private boolean removeSectionFromList(NormalList normalList, long sectionPos) { + normalList.removeSection(sectionPos); + return normalList.isEmpty(); + } - @Override - public void removeSection(long sectionPos, TranslucentData data) { - var iterator = this.normalLists.values().iterator(); - while (iterator.hasNext()) { - var normalList = iterator.next(); - if (this.removeSectionFromList(normalList, sectionPos)) { - iterator.remove(); - } - } - } + @Override + public void removeSection(long sectionPos, TranslucentData data) { + var iterator = this.normalLists.values().iterator(); + while (iterator.hasNext()) { + var normalList = iterator.next(); + if (this.removeSectionFromList(normalList, sectionPos)) { + iterator.remove(); + } + } + } - @Override - public void addSection(ChunkSectionPos pos, DynamicData data, Vector3dc cameraPos) { - long sectionPos = pos.asLong(); - var accGroupResult = data.getAccGroupResult(); + @Override + public void addSection(ChunkSectionPos pos, DynamicData data, Vector3dc cameraPos) { + long sectionPos = pos.asLong(); + var accGroupResult = data.getAccGroupResult(); - // go through all normal lists and check against the normals that the group - // builder has. if the normal list has data for the section, but the group - // builder doesn't, the group is removed. otherwise, the group is updated. - var iterator = this.normalLists.values().iterator(); - while (iterator.hasNext()) { - var normalList = iterator.next(); + // go through all normal lists and check against the normals that the group + // builder has. if the normal list has data for the section, but the group + // builder doesn't, the group is removed. otherwise, the group is updated. + var iterator = this.normalLists.values().iterator(); + while (iterator.hasNext()) { + var normalList = iterator.next(); - // check if the geometry collector includes data for this normal. - var accGroup = accGroupResult.getGroupForNormal(normalList); - if (normalList.hasSection(sectionPos)) { - if (accGroup == null) { - if (this.removeSectionFromList(normalList, sectionPos)) { - iterator.remove(); - } - } else { - normalList.updateSection(accGroup, sectionPos); - } - } else if (accGroup != null) { - normalList.addSection(accGroup, sectionPos); - } - } + // check if the geometry collector includes data for this normal. + var accGroup = accGroupResult.getGroupForNormal(normalList); + if (normalList.hasSection(sectionPos)) { + if (accGroup == null) { + if (this.removeSectionFromList(normalList, sectionPos)) { + iterator.remove(); + } + } else { + normalList.updateSection(accGroup, sectionPos); + } + } else if (accGroup != null) { + normalList.addSection(accGroup, sectionPos); + } + } - // go through the data of the geometry collector to check for data of new - // normals - // for which there are no normal lists yet. This only checks for new normal - // lists since new data for existing normal lists is handled above. - var aligned = accGroupResult.getAlignedDistances(); - if (aligned != null) { - for (var accGroup : aligned) { - if (accGroup != null) { - this.addSectionInNewNormalLists(data, accGroup); - } - } - } - var unaligned = accGroupResult.getUnalignedDistances(); - if (unaligned != null) { - for (var accGroup : unaligned) { - this.addSectionInNewNormalLists(data, accGroup); - } - } + // go through the data of the geometry collector to check for data of new + // normals + // for which there are no normal lists yet. This only checks for new normal + // lists since new data for existing normal lists is handled above. + var aligned = accGroupResult.getAlignedDistances(); + if (aligned != null) { + for (var accGroup : aligned) { + if (accGroup != null) { + this.addSectionInNewNormalLists(data, accGroup); + } + } + } + var unaligned = accGroupResult.getUnalignedDistances(); + if (unaligned != null) { + for (var accGroup : unaligned) { + this.addSectionInNewNormalLists(data, accGroup); + } + } - data.clearAccGroupData(); - } + data.clearAccGroupData(); + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java index bf0f5d8c12..bdac22f952 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java @@ -15,16 +15,16 @@ * correctly compared.. */ public record TQuad(ModelQuadFacing facing, Vector3fc normal, Vector3f center, float[] extents) { - int getQuadHash() { - // the hash code needs to be particularly collision resistant - int result = 1; - result = 31 * result + Arrays.hashCode(this.extents); - if (facing == ModelQuadFacing.UNASSIGNED) { - result = 31 * result + this.facing.hashCode(); - } else { - result = 31 * result + this.normal.hashCode(); - } - result = 31 * result + this.center.hashCode(); - return result; - } + int getQuadHash() { + // the hash code needs to be particularly collision resistant + int result = 1; + result = 31 * result + Arrays.hashCode(this.extents); + if (facing == ModelQuadFacing.UNASSIGNED) { + result = 31 * result + this.facing.hashCode(); + } else { + result = 31 * result + this.normal.hashCode(); + } + result = 31 * result + this.center.hashCode(); + return result; + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPResult.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPResult.java index a48323e8be..476c075385 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPResult.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPResult.java @@ -10,7 +10,6 @@ import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.NormalList; public class BSPResult extends AccGroupResult { - // TODO: BSP triggering needs to be bidirectional Object2ReferenceOpenHashMap unalignedDistances; BSPNode rootNode; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java index 6cc75b0f34..44ccdaddd0 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java @@ -12,56 +12,56 @@ import net.minecraft.util.math.ChunkSectionPos; public class BSPDynamicData extends DynamicData { - private final BSPNode rootNode; + private final BSPNode rootNode; - private BSPDynamicData(ChunkSectionPos sectionPos, - NativeBuffer buffer, VertexRange range, BSPResult result) { - super(sectionPos, buffer, range, result); - this.rootNode = result.getRootNode(); - } + private BSPDynamicData(ChunkSectionPos sectionPos, + NativeBuffer buffer, VertexRange range, BSPResult result) { + super(sectionPos, buffer, range, result); + this.rootNode = result.getRootNode(); + } - @Override - public void sortOnTrigger(Vector3fc cameraPos) { - this.sort(cameraPos); - } + @Override + public void sortOnTrigger(Vector3fc cameraPos) { + this.sort(cameraPos); + } - private void sort(Vector3fc cameraPos) { - this.unsetReuseUploadedData(); + private void sort(Vector3fc cameraPos) { + this.unsetReuseUploadedData(); - this.rootNode.collectSortedQuads( - this.getBuffer().getDirectBuffer().asIntBuffer(), cameraPos); - } + this.rootNode.collectSortedQuads( + this.getBuffer().getDirectBuffer().asIntBuffer(), cameraPos); + } - public static BSPDynamicData fromMesh(BuiltSectionMeshParts translucentMesh, - Vector3fc cameraPos, TQuad[] quads, ChunkSectionPos sectionPos, TranslucentGeometryCollector collector, - NativeBuffer buffer) { - var result = BSPNode.buildBSP(quads, sectionPos); + public static BSPDynamicData fromMesh(BuiltSectionMeshParts translucentMesh, + Vector3fc cameraPos, TQuad[] quads, ChunkSectionPos sectionPos, TranslucentGeometryCollector collector, + NativeBuffer buffer) { + var result = BSPNode.buildBSP(quads, sectionPos); - VertexRange range = TranslucentData.getUnassignedVertexRange(translucentMesh); - buffer = PresentTranslucentData.nativeBufferForQuads(buffer, quads); + VertexRange range = TranslucentData.getUnassignedVertexRange(translucentMesh); + buffer = PresentTranslucentData.nativeBufferForQuads(buffer, quads); - var dynamicData = new BSPDynamicData(sectionPos, buffer, range, result); - dynamicData.sort(cameraPos); + var dynamicData = new BSPDynamicData(sectionPos, buffer, range, result); + dynamicData.sort(cameraPos); - // prepare accumulation groups for integration into GFNI triggering - // TODO: combine this and the similar code in TopoSortDynamicData - var aligned = result.getAlignedDistances(); - if (aligned != null) { - for (var accGroup : aligned) { - if (accGroup != null) { - accGroup.prepareIntegration(); - } - } - } - var unaligned = result.getUnalignedDistances(); - if (unaligned != null) { - for (var accGroup : unaligned) { - if (accGroup != null) { - accGroup.prepareIntegration(); - } - } - } + // prepare accumulation groups for integration into GFNI triggering + // TODO: combine this and the similar code in TopoSortDynamicData + var aligned = result.getAlignedDistances(); + if (aligned != null) { + for (var accGroup : aligned) { + if (accGroup != null) { + accGroup.prepareIntegration(); + } + } + } + var unaligned = result.getUnalignedDistances(); + if (unaligned != null) { + for (var accGroup : unaligned) { + if (accGroup != null) { + accGroup.prepareIntegration(); + } + } + } - return dynamicData; - } + return dynamicData; + } } From a55c4bff3980b2de6b7ca3a2b3020ae6162dcf7f Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 24 Nov 2023 18:56:49 +0100 Subject: [PATCH 134/256] fix bug with interval tree sync with hash map --- .../chunk/translucent_sorting/NormalList.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/NormalList.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/NormalList.java index fa399cf91d..6cc6ce1f12 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/NormalList.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/NormalList.java @@ -52,7 +52,7 @@ public class NormalList { * An interval tree of group intervals. Since this only stores intervals, the * stored intervals are mapped to groups in a separate hashmap. */ - private final IntervalTree groupIntervals = new IntervalTree<>(); + private final IntervalTree intervalTree = new IntervalTree<>(); /** * A separate hashmap of groups. This is what actually stores the groups since @@ -101,7 +101,7 @@ void processMovement(TranslucentSorting ts, CameraMovement movement) { // perform the interval query on the group intervals and resolve each interval // to the collection of groups it maps to var interval = new DoubleInterval(start, end, Bounded.CLOSED); - for (Interval groupInterval : groupIntervals.query(interval)) { + for (Interval groupInterval : intervalTree.query(interval)) { for (Group group : groupsByInterval.get(groupInterval)) { group.triggerRange(ts, start, end, this.collectorKey); } @@ -109,13 +109,14 @@ void processMovement(TranslucentSorting ts, CameraMovement movement) { } private void removeGroupInterval(Group group) { - this.groupIntervals.remove(group.distances); - var groups = this.groupsByInterval.get(group.distances); if (groups != null) { groups.remove(group); if (groups.isEmpty()) { this.groupsByInterval.remove(group.distances); + + // only remove from the interval tree if no other sections are also using it + this.intervalTree.remove(group.distances); } else if (groups.size() <= ARRAY_SET_THRESHOLD) { groups = new ReferenceArraySet<>(groups); this.groupsByInterval.put(group.distances, groups); @@ -124,12 +125,13 @@ private void removeGroupInterval(Group group) { } private void addGroupInterval(Group group) { - this.groupIntervals.add(group.distances); - var groups = this.groupsByInterval.get(group.distances); if (groups == null) { groups = new ReferenceArraySet<>(); this.groupsByInterval.put(group.distances, groups); + + // only add to the interval tree if it's a new interval + this.intervalTree.add(group.distances); } else if (groups.size() >= HASH_SET_THRESHOLD) { groups = new ReferenceLinkedOpenHashSet<>(groups); this.groupsByInterval.put(group.distances, groups); From 2d9d7496859b345a61eb9e5803b4e5f17ea308ca Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 24 Nov 2023 18:57:38 +0100 Subject: [PATCH 135/256] remove collector from bsp data constructor --- .../translucent_sorting/TranslucentGeometryCollector.java | 2 +- .../render/chunk/translucent_sorting/data/BSPDynamicData.java | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java index 2c30223080..e4aed5a9cf 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java @@ -418,7 +418,7 @@ private TranslucentData makeNewTranslucentData(BuiltSectionMeshParts translucent if (this.sortType == SortType.DYNAMIC_ALL) { try { - return BSPDynamicData.fromMesh(translucentMesh, cameraPos, quads, sectionPos, this, buffer); + return BSPDynamicData.fromMesh(translucentMesh, cameraPos, quads, sectionPos, buffer); } catch (BSPBuildFailureException e) { System.out.println("BSP build failure: " + sectionPos); return TopoSortDynamicData.fromMesh(translucentMesh, cameraPos, quads, sectionPos, this, buffer); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java index 44ccdaddd0..169fa5ad66 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java @@ -5,7 +5,6 @@ import me.jellysquid.mods.sodium.client.gl.util.VertexRange; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TranslucentGeometryCollector; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree.BSPNode; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree.BSPResult; import me.jellysquid.mods.sodium.client.util.NativeBuffer; @@ -33,7 +32,7 @@ private void sort(Vector3fc cameraPos) { } public static BSPDynamicData fromMesh(BuiltSectionMeshParts translucentMesh, - Vector3fc cameraPos, TQuad[] quads, ChunkSectionPos sectionPos, TranslucentGeometryCollector collector, + Vector3fc cameraPos, TQuad[] quads, ChunkSectionPos sectionPos, NativeBuffer buffer) { var result = BSPNode.buildBSP(quads, sectionPos); From 06152c569f50724f258058fd4ebd33a5b111f6c6 Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 25 Nov 2023 02:23:34 +0100 Subject: [PATCH 136/256] detect and ignore intersecting geometry --- .../chunk/translucent_sorting/TQuad.java | 21 ++++++ .../translucent_sorting/bsp_tree/BSPNode.java | 6 ++ .../bsp_tree/InnerPartitionBSPNode.java | 69 +++++++++++++++---- 3 files changed, 83 insertions(+), 13 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java index bdac22f952..184509a701 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java @@ -27,4 +27,25 @@ int getQuadHash() { result = 31 * result + this.center.hashCode(); return result; } + + public float getAlignedSurfaceArea() { + if (this.facing == ModelQuadFacing.UNASSIGNED) { + return 0; + } + + var dX = this.extents[3] - this.extents[0]; + var dY = this.extents[4] - this.extents[1]; + var dZ = this.extents[5] - this.extents[2]; + + if (dX == 0) { + return (float) (dY * dZ); + } else if (dY == 0) { + return (float) (dX * dZ); + } else if (dZ == 0) { + return (float) (dX * dY); + } else { + // non-flat aligned quad, weird edge case + return 0; + } + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java index 88b623d4e3..b6d5ddc5e2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java @@ -4,6 +4,7 @@ import org.joml.Vector3fc; +import it.unimi.dsi.fastutil.ints.IntArrayList; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; import net.minecraft.util.math.ChunkSectionPos; @@ -36,4 +37,9 @@ static BSPNode build(BSPWorkspace workspace) { return InnerPartitionBSPNode.build(workspace); } } + + static BSPNode buildWithIndexes(BSPWorkspace workspace, IntArrayList indexes) { + workspace.indexes = indexes; + return build(workspace); + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java index 88d2a0e152..e9fbebde18 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java @@ -66,10 +66,12 @@ private static record Partition(float distance, IntArrayList quadsBefore, IntArr } static BSPNode build(BSPWorkspace workspace) { + var indexes = workspace.indexes; + // special case two quads - if (workspace.indexes.size() == 2) { - var quadA = workspace.quads[workspace.indexes.getInt(0)]; - var quadB = workspace.quads[workspace.indexes.getInt(1)]; + if (indexes.size() == 2) { + var quadA = workspace.quads[indexes.getInt(0)]; + var quadB = workspace.quads[indexes.getInt(1)]; // check for coplanar or mutually invisible quads var facingA = quadA.facing(); @@ -95,13 +97,13 @@ static BSPNode build(BSPWorkspace workspace) { && facingB != ModelQuadFacing.UNASSIGNED && !TopoGraphSorting.orthogonalQuadVisibleThrough(quadA, quadB) && !TopoGraphSorting.orthogonalQuadVisibleThrough(quadB, quadA)) { - return new LeafMultiBSPNode(workspace.indexes.toIntArray()); + return new LeafMultiBSPNode(indexes.toIntArray()); } } ReferenceArrayList partitions = new ReferenceArrayList<>(); ReferenceArrayList points = new ReferenceArrayList<>( - (int) (workspace.indexes.size() * 1.5)); + (int) (indexes.size() * 1.5)); // find any aligned partition, search each axis for (int axis = 0; axis < 3; axis++) { @@ -111,7 +113,7 @@ static BSPNode build(BSPWorkspace workspace) { // collect all the geometry's start and end points in this direction points.clear(); - for (int quadIndex : workspace.indexes) { + for (int quadIndex : indexes) { var quad = workspace.quads[quadIndex]; var extents = quad.extents(); var posExtent = extents[axis]; @@ -196,7 +198,7 @@ static BSPNode build(BSPWorkspace workspace) { // check a different axis if everything is in one quadsBefore, // which means there are no gaps - if (quadsBefore != null && quadsBefore.size() == workspace.indexes.size()) { + if (quadsBefore != null && quadsBefore.size() == indexes.size()) { // TODO: reuse the sorted point array for child nodes (add to workspace) continue; } @@ -224,12 +226,10 @@ static BSPNode build(BSPWorkspace workspace) { BSPNode insideNode = null; BSPNode outsideNode = null; if (inside.quadsBefore() != null) { - workspace.indexes = inside.quadsBefore(); - insideNode = BSPNode.build(workspace); + insideNode = BSPNode.buildWithIndexes(workspace,inside.quadsBefore()); } if (outside != null) { - workspace.indexes = outside.quadsBefore(); - outsideNode = BSPNode.build(workspace); + outsideNode = BSPNode.buildWithIndexes(workspace, outside.quadsBefore()); } var onPlane = inside.quadsOn() == null ? null : inside.quadsOn().toIntArray(); @@ -263,8 +263,7 @@ static BSPNode build(BSPWorkspace workspace) { } if (partition.quadsBefore() != null) { - workspace.indexes = partition.quadsBefore(); - partitionNodes[i] = BSPNode.build(workspace); + partitionNodes[i] = BSPNode.buildWithIndexes(workspace, partition.quadsBefore()); } if (partition.quadsOn() != null) { onPlaneQuads[i] = partition.quadsOn().toIntArray(); @@ -277,6 +276,50 @@ static BSPNode build(BSPWorkspace workspace) { // TODO: attempt unaligned partitioning, convex decomposition, etc. + // test if the geometry intersects with itself + // if there is self-intersection, return a multi leaf node to just give up + // sorting this geometry. intersecting geometry is rare but when it does happen, + // it should simply be accepted and rendered as-is. Whatever artifacts this + // causes are considered "ok". + // TODO: also do this test with unaligned quads + for (int quadAIndex = 0; quadAIndex < indexes.size(); quadAIndex++) { + var quadA = workspace.quads[indexes.getInt(quadAIndex)]; + if (quadA.facing() == ModelQuadFacing.UNASSIGNED) { + continue; + } + for (int quadBIndex = quadAIndex + 1; quadBIndex < indexes.size(); quadBIndex++) { + var quadB = workspace.quads[indexes.getInt(quadBIndex)]; + + if (quadB.facing() == ModelQuadFacing.UNASSIGNED) { + continue; + } + + // aligned quads intersect if their bounding boxes intersect + boolean intersects = true; + for (int axis = 0; axis < 3; axis++) { + var opposite = axis + 3; + var extentsA = quadA.extents(); + var extentsB = quadB.extents(); + + if (extentsA[axis] < extentsB[opposite] + || extentsB[axis] < extentsA[opposite]) { + intersects = false; + break; + } + } + + if (intersects) { + // sort quads by size ascending + indexes.sort((a, b) -> { + var quadX = workspace.quads[a]; + var quadY = workspace.quads[b]; + return Float.compare(quadX.getAlignedSurfaceArea(), quadY.getAlignedSurfaceArea()); + }); + return new LeafMultiBSPNode(indexes.toIntArray()); + } + } + } + throw new BSPBuildFailureException("no partition found"); } } From 10456c64b17eac3c3faa466438cc30ab3c92ac08 Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 25 Nov 2023 02:52:31 +0100 Subject: [PATCH 137/256] no need to prefix inner classes --- .../bsp_tree/InnerPartitionBSPNode.java | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java index e9fbebde18..c30bb16bb1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java @@ -5,6 +5,7 @@ import org.joml.Vector3fc; import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntComparator; import it.unimi.dsi.fastutil.objects.ReferenceArrayList; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TopoGraphSorting; @@ -22,6 +23,17 @@ * level: convex hulls (like cuboids where the faces point outwards) don't need * to be sorted. This could be used to optimize the inside of honey blocks, and * other blocks. + * - the section full of honey and slime blocks seems to be sorted ok but when + * the camera moves too fast across the surface near a corner it breaks. My + * theory is that it breaks from the slime blocks having a small inner block + * that produces a plane that the camera passes over first but then it's still + * sorting when the camera crosses over the second so it sorts it with the + * camera between the two and doesn't sort it again when the camera has passed + * over the second. This is fixed by making sure the scheduling of sort tasks + * makes a new pending task with a new camera position if there's a newer + * schedule event. If there's a running task, a new task needs to be scheduled + * with an updated camera position, though I think this already works similarly + * to how rebuilds can be scheduled during a running rebuild. */ abstract class InnerPartitionBSPNode extends BSPNode { final Vector3fc planeNormal; @@ -46,7 +58,7 @@ private static record IntervalPoint(float distance, int quadIndex, byte type) { static final byte SIDE = 1; } - private static final Comparator INTERVAL_POINT_COMPARATOR = (a, b) -> { + private static final Comparator INTERVAL_POINT_COMPARATOR = (a, b) -> { // sort by distance ascending float distanceDiff = a.distance() - b.distance(); if (distanceDiff != 0) { @@ -101,8 +113,8 @@ static BSPNode build(BSPWorkspace workspace) { } } - ReferenceArrayList partitions = new ReferenceArrayList<>(); - ReferenceArrayList points = new ReferenceArrayList<>( + ReferenceArrayList partitions = new ReferenceArrayList<>(); + ReferenceArrayList points = new ReferenceArrayList<>( (int) (indexes.size() * 1.5)); // find any aligned partition, search each axis @@ -134,7 +146,7 @@ static BSPNode build(BSPWorkspace workspace) { IntArrayList quadsBefore = null; IntArrayList quadsOn = null; int thickness = 0; - for (InnerPartitionBSPNode.IntervalPoint point : points) { + for (IntervalPoint point : points) { switch (point.type()) { case IntervalPoint.START -> { // unless at the start, flush if there's a gap @@ -226,7 +238,7 @@ static BSPNode build(BSPWorkspace workspace) { BSPNode insideNode = null; BSPNode outsideNode = null; if (inside.quadsBefore() != null) { - insideNode = BSPNode.buildWithIndexes(workspace,inside.quadsBefore()); + insideNode = BSPNode.buildWithIndexes(workspace, inside.quadsBefore()); } if (outside != null) { outsideNode = BSPNode.buildWithIndexes(workspace, outside.quadsBefore()); From a3fc9f314ca6044e14a27ac32a6adffea521660a Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 25 Nov 2023 02:54:07 +0100 Subject: [PATCH 138/256] move special case for two quads to BSPNode --- .../translucent_sorting/bsp_tree/BSPNode.java | 40 ++++++++++++++++++- .../bsp_tree/InnerPartitionBSPNode.java | 35 ---------------- 2 files changed, 38 insertions(+), 37 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java index b6d5ddc5e2..5d685e220f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java @@ -5,7 +5,9 @@ import org.joml.Vector3fc; import it.unimi.dsi.fastutil.ints.IntArrayList; +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TopoGraphSorting; import net.minecraft.util.math.ChunkSectionPos; /** @@ -33,9 +35,43 @@ static BSPNode build(BSPWorkspace workspace) { return null; } else if (workspace.indexes.size() == 1) { return new LeafSingleBSPNode(workspace.indexes.getInt(0)); - } else { - return InnerPartitionBSPNode.build(workspace); } + + // special case two quads + var indexes = workspace.indexes; + if (indexes.size() == 2) { + var quadA = workspace.quads[indexes.getInt(0)]; + var quadB = workspace.quads[indexes.getInt(1)]; + + // check for coplanar or mutually invisible quads + var facingA = quadA.facing(); + var facingB = quadB.facing(); + var normalA = quadA.normal(); + var normalB = quadB.normal(); + if ( + // coplanar quads + ((facingA == ModelQuadFacing.UNASSIGNED || facingB == ModelQuadFacing.UNASSIGNED) + ? // opposite normal (distance irrelevant) + normalA.x() == -normalB.x() + && normalA.y() == -normalB.y() + && normalA.z() == -normalB.z() + // same normal and same distance + || normalA.equals(quadB.normal()) + && normalA.dot(quadA.center()) == quadB.normal().dot(quadB.center()) + // aligned same distance + : quadA.extents()[facingA.ordinal()] == quadB.extents()[facingB.ordinal()]) + // facing away from eachother + || facingA == facingB.getOpposite() + // otherwise mutually invisible + || facingA != ModelQuadFacing.UNASSIGNED + && facingB != ModelQuadFacing.UNASSIGNED + && !TopoGraphSorting.orthogonalQuadVisibleThrough(quadA, quadB) + && !TopoGraphSorting.orthogonalQuadVisibleThrough(quadB, quadA)) { + return new LeafMultiBSPNode(indexes.toIntArray()); + } + } + + return InnerPartitionBSPNode.build(workspace); } static BSPNode buildWithIndexes(BSPWorkspace workspace, IntArrayList indexes) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java index c30bb16bb1..ecb99b7c46 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java @@ -5,10 +5,8 @@ import org.joml.Vector3fc; import it.unimi.dsi.fastutil.ints.IntArrayList; -import it.unimi.dsi.fastutil.ints.IntComparator; import it.unimi.dsi.fastutil.objects.ReferenceArrayList; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TopoGraphSorting; /** * TODO: @@ -80,39 +78,6 @@ private static record Partition(float distance, IntArrayList quadsBefore, IntArr static BSPNode build(BSPWorkspace workspace) { var indexes = workspace.indexes; - // special case two quads - if (indexes.size() == 2) { - var quadA = workspace.quads[indexes.getInt(0)]; - var quadB = workspace.quads[indexes.getInt(1)]; - - // check for coplanar or mutually invisible quads - var facingA = quadA.facing(); - var facingB = quadB.facing(); - var normalA = quadA.normal(); - var normalB = quadB.normal(); - if ( - // coplanar quads - ((facingA == ModelQuadFacing.UNASSIGNED || facingB == ModelQuadFacing.UNASSIGNED) - ? // opposite normal (distance irrelevant) - normalA.x() == -normalB.x() - && normalA.y() == -normalB.y() - && normalA.z() == -normalB.z() - // same normal and same distance - || normalA.equals(quadB.normal()) - && normalA.dot(quadA.center()) == quadB.normal().dot(quadB.center()) - // aligned same distance - : quadA.extents()[facingA.ordinal()] == quadB.extents()[facingB.ordinal()]) - // facing away from eachother - || facingA == facingB.getOpposite() - // otherwise mutually invisible - || facingA != ModelQuadFacing.UNASSIGNED - && facingB != ModelQuadFacing.UNASSIGNED - && !TopoGraphSorting.orthogonalQuadVisibleThrough(quadA, quadB) - && !TopoGraphSorting.orthogonalQuadVisibleThrough(quadB, quadA)) { - return new LeafMultiBSPNode(indexes.toIntArray()); - } - } - ReferenceArrayList partitions = new ReferenceArrayList<>(); ReferenceArrayList points = new ReferenceArrayList<>( (int) (indexes.size() * 1.5)); From 5257cc838ebdb5a7c3646c2210d4b33cb0a73cdc Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 25 Nov 2023 17:17:57 +0100 Subject: [PATCH 139/256] improve bsp build performance by rotating partitioning axis on each level --- .../chunk/translucent_sorting/bsp_tree/BSPNode.java | 3 ++- .../translucent_sorting/bsp_tree/BSPWorkspace.java | 5 +++++ .../bsp_tree/InnerPartitionBSPNode.java | 10 ++++++---- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java index 5d685e220f..36c504f36a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java @@ -74,8 +74,9 @@ static BSPNode build(BSPWorkspace workspace) { return InnerPartitionBSPNode.build(workspace); } - static BSPNode buildWithIndexes(BSPWorkspace workspace, IntArrayList indexes) { + static BSPNode buildChild(BSPWorkspace workspace, IntArrayList indexes, int currentAxisOffset) { workspace.indexes = indexes; + workspace.axisOffset = (currentAxisOffset + 1) % 3; return build(workspace); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java index 13112dc5d4..598d101b5a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java @@ -19,6 +19,11 @@ class BSPWorkspace { */ IntArrayList indexes; + /** + * The axis to start the next recursive BSP build on. + */ + int axisOffset = 1; + BSPResult result = new BSPResult(); BSPWorkspace(TQuad[] quads, ChunkSectionPos sectionPos) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java index ecb99b7c46..8d6cc0818a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java @@ -83,7 +83,9 @@ static BSPNode build(BSPWorkspace workspace) { (int) (indexes.size() * 1.5)); // find any aligned partition, search each axis - for (int axis = 0; axis < 3; axis++) { + var axisOffset = workspace.axisOffset; + for (int axisCount = 0; axisCount < 3; axisCount++) { + int axis = (axisCount + axisOffset) % 3; var facing = ModelQuadFacing.VALUES[axis]; var oppositeFacing = facing.getOpposite(); var oppositeDirection = oppositeFacing.ordinal(); @@ -203,10 +205,10 @@ static BSPNode build(BSPWorkspace workspace) { BSPNode insideNode = null; BSPNode outsideNode = null; if (inside.quadsBefore() != null) { - insideNode = BSPNode.buildWithIndexes(workspace, inside.quadsBefore()); + insideNode = BSPNode.buildChild(workspace, inside.quadsBefore(), axisOffset); } if (outside != null) { - outsideNode = BSPNode.buildWithIndexes(workspace, outside.quadsBefore()); + outsideNode = BSPNode.buildChild(workspace, outside.quadsBefore(), axisOffset); } var onPlane = inside.quadsOn() == null ? null : inside.quadsOn().toIntArray(); @@ -240,7 +242,7 @@ static BSPNode build(BSPWorkspace workspace) { } if (partition.quadsBefore() != null) { - partitionNodes[i] = BSPNode.buildWithIndexes(workspace, partition.quadsBefore()); + partitionNodes[i] = BSPNode.buildChild(workspace, partition.quadsBefore(), axisOffset); } if (partition.quadsOn() != null) { onPlaneQuads[i] = partition.quadsOn().toIntArray(); From 9c009f8cdee0cf298956f646ae56d1973bd93a81 Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 25 Nov 2023 19:02:07 +0100 Subject: [PATCH 140/256] update render section manager camera position so that sorting tasks have the right camera position when they're created --- .../mods/sodium/client/render/SodiumWorldRenderer.java | 3 ++- .../mods/sodium/client/render/chunk/RenderSectionManager.java | 4 +++- .../render/chunk/compile/tasks/ChunkBuilderSortingTask.java | 3 +++ .../render/chunk/translucent_sorting/bsp_tree/BSPNode.java | 4 ++++ 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index 1531ba64e4..72417fd321 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -196,6 +196,7 @@ public void setupTerrain(Camera camera, profiler.swap("chunk_update"); + this.renderSectionManager.updateCameraState(pos, camera); this.renderSectionManager.updateChunks(updateChunksImmediately); profiler.swap("chunk_upload"); @@ -205,7 +206,7 @@ public void setupTerrain(Camera camera, if (this.renderSectionManager.needsUpdate()) { profiler.swap("chunk_render_lists"); - this.renderSectionManager.update(pos, camera, viewport, frame, spectator); + this.renderSectionManager.update(camera, viewport, frame, spectator); } if (updateChunksImmediately) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index 1d3bdd63aa..8b63f46156 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -117,10 +117,12 @@ public RenderSectionManager(ClientWorld world, int renderDistance, CommandList c } } - public void update(Vector3dc cameraPosition, Camera camera, Viewport viewport, int frame, boolean spectator) { + public void updateCameraState(Vector3dc cameraPosition, Camera camera) { this.cameraBlockPos = camera.getBlockPos(); this.cameraPosition = cameraPosition; + } + public void update(Camera camera, Viewport viewport, int frame, boolean spectator) { this.createTerrainRenderList(camera, viewport, frame, spectator); this.needsGraphUpdate = false; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java index e09bbefbd4..3d4a420ae2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java @@ -19,6 +19,9 @@ public ChunkBuilderSortingTask(RenderSection render, int frame, Vector3dc absolu @Override public ChunkSortOutput execute(ChunkBuildContext context, CancellationToken cancellationToken) { + if (cancellationToken.isCancelled()) { + return null; + } this.render.getTranslucentData().sortOnTrigger(this.cameraPos); return new ChunkSortOutput(this.render, this.submitTime, this.dynamicData); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java index 36c504f36a..74dcbe47de 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java @@ -14,6 +14,10 @@ * A node in the BSP tree. The BSP tree is made up of nodes that split quads * into groups on either side of a plane and those that lie on the plane. * There's also leaf nodes that contain one or more quads. + * + * TODO: + * - historgram of BSP build and sort times on a standard world loading scenario + * (maybe something like hermitcraft?) with some artificial structures too. */ public abstract class BSPNode { public abstract void collectSortedQuads(IntBuffer indexBuffer, Vector3fc cameraPos); From 2ae3c62eb21659297448903a2426535aabeb6a61 Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 25 Nov 2023 19:49:23 +0100 Subject: [PATCH 141/256] better names for job collectors --- .../render/chunk/RenderSectionManager.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index 8b63f46156..34d60482b6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -287,17 +287,17 @@ public void updateChunks(boolean updateImmediately) { this.sectionCache.cleanup(); this.regions.update(); - var blockingRebuilds = new ChunkJobCollector(Integer.MAX_VALUE, this.buildResults::add); - var deferredRebuilds = new ChunkJobCollector(this.builder.getSchedulingBudget(), this.buildResults::add); - var optionallyBlockingCollector = updateImmediately ? blockingRebuilds : deferredRebuilds; + var blockingCollector = new ChunkJobCollector(Integer.MAX_VALUE, this.buildResults::add); + var deferredCollector = new ChunkJobCollector(this.builder.getSchedulingBudget(), this.buildResults::add); + var maybeBlockingCollector = updateImmediately ? blockingCollector : deferredCollector; - this.submitSectionTasks(blockingRebuilds, ChunkUpdateType.IMPORTANT_REBUILD); - this.submitSectionTasks(blockingRebuilds, ChunkUpdateType.IMPORTANT_SORT); - this.submitSectionTasks(optionallyBlockingCollector, ChunkUpdateType.REBUILD); - this.submitSectionTasks(optionallyBlockingCollector, ChunkUpdateType.INITIAL_BUILD); - this.submitSectionTasks(optionallyBlockingCollector, ChunkUpdateType.SORT); + this.submitSectionTasks(blockingCollector, ChunkUpdateType.IMPORTANT_REBUILD); + this.submitSectionTasks(blockingCollector, ChunkUpdateType.IMPORTANT_SORT); + this.submitSectionTasks(maybeBlockingCollector, ChunkUpdateType.REBUILD); + this.submitSectionTasks(maybeBlockingCollector, ChunkUpdateType.INITIAL_BUILD); + this.submitSectionTasks(maybeBlockingCollector, ChunkUpdateType.SORT); - blockingRebuilds.awaitCompletion(this.builder); + blockingCollector.awaitCompletion(this.builder); } public void uploadChunks() { From a1b3862115af6b16676c97256af9e19c5f4bfb84 Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 25 Nov 2023 21:48:18 +0100 Subject: [PATCH 142/256] limit number of intersection tests when bsp partitioning fails --- .../bsp_tree/InnerPartitionBSPNode.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java index 8d6cc0818a..b4e2e490df 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java @@ -261,6 +261,7 @@ static BSPNode build(BSPWorkspace workspace) { // it should simply be accepted and rendered as-is. Whatever artifacts this // causes are considered "ok". // TODO: also do this test with unaligned quads + int testsRemaining = 10000; for (int quadAIndex = 0; quadAIndex < indexes.size(); quadAIndex++) { var quadA = workspace.quads[indexes.getInt(quadAIndex)]; if (quadA.facing() == ModelQuadFacing.UNASSIGNED) { @@ -296,6 +297,14 @@ static BSPNode build(BSPWorkspace workspace) { }); return new LeafMultiBSPNode(indexes.toIntArray()); } + + if (--testsRemaining == 0) { + break; + } + } + + if (testsRemaining == 0) { + break; } } From 53426bd77e3c6a1c4cace0017e4b2563e48b00e2 Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 27 Nov 2023 01:35:02 +0100 Subject: [PATCH 143/256] distance sort method is private --- .../chunk/translucent_sorting/data/TopoSortDynamicData.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java index 6575a7b3a8..13874d9d38 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java @@ -179,7 +179,7 @@ private void sort(Vector3fc cameraPos, boolean isAngleTrigger, boolean initial) private static ThreadLocal distanceSortKeys = new ThreadLocal<>(); - public static int[] distanceSortDirect(int[] indexes, + private static int[] distanceSortDirect(int[] indexes, IntBuffer indexBuffer, TQuad[] quads, Vector3fc cameraPos) { if (indexes == null) { indexes = new int[quads.length]; From 128406c9743eab8ec90dfceeac34af6fe932af97 Mon Sep 17 00:00:00 2001 From: douira Date: Tue, 28 Nov 2023 16:33:31 +0100 Subject: [PATCH 144/256] add two quad special case bsp node to avoid array allocation --- .../translucent_sorting/bsp_tree/BSPNode.java | 8 ++++--- .../bsp_tree/LeafDoubleBSPNode.java | 23 +++++++++++++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafDoubleBSPNode.java diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java index 74dcbe47de..4810d7eab2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java @@ -44,8 +44,10 @@ static BSPNode build(BSPWorkspace workspace) { // special case two quads var indexes = workspace.indexes; if (indexes.size() == 2) { - var quadA = workspace.quads[indexes.getInt(0)]; - var quadB = workspace.quads[indexes.getInt(1)]; + var quadIndexA = indexes.getInt(0); + var quadIndexB = indexes.getInt(1); + var quadA = workspace.quads[quadIndexA]; + var quadB = workspace.quads[quadIndexB]; // check for coplanar or mutually invisible quads var facingA = quadA.facing(); @@ -71,7 +73,7 @@ static BSPNode build(BSPWorkspace workspace) { && facingB != ModelQuadFacing.UNASSIGNED && !TopoGraphSorting.orthogonalQuadVisibleThrough(quadA, quadB) && !TopoGraphSorting.orthogonalQuadVisibleThrough(quadB, quadA)) { - return new LeafMultiBSPNode(indexes.toIntArray()); + return new LeafDoubleBSPNode(quadIndexA, quadIndexB); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafDoubleBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafDoubleBSPNode.java new file mode 100644 index 0000000000..bf5e3ce59b --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafDoubleBSPNode.java @@ -0,0 +1,23 @@ +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; + +import java.nio.IntBuffer; + +import org.joml.Vector3fc; + +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; + +public class LeafDoubleBSPNode extends BSPNode { + private final int quadA; + private final int quadB; + + LeafDoubleBSPNode(int quadA, int quadB) { + this.quadA = quadA; + this.quadB = quadB; + } + + @Override + public void collectSortedQuads(IntBuffer indexBuffer, Vector3fc cameraPos) { + TranslucentData.writeQuadVertexIndexes(indexBuffer, this.quadA); + TranslucentData.writeQuadVertexIndexes(indexBuffer, this.quadB); + } +} From 75217fa60ed066790f13a45c2f3e9d38156ce5b4 Mon Sep 17 00:00:00 2001 From: douira Date: Tue, 28 Nov 2023 17:32:16 +0100 Subject: [PATCH 145/256] note on flat array optimization --- .../bsp_tree/InnerMultiPartitionBSPNode.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerMultiPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerMultiPartitionBSPNode.java index dce56fbd92..407136a103 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerMultiPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerMultiPartitionBSPNode.java @@ -6,6 +6,11 @@ import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; +/** + * Implementation note: Detecting and avoiding the double array when possible + * brings no performance benefit in sorting speed, only a building speed + * detriment. + */ class InnerMultiPartitionBSPNode extends InnerPartitionBSPNode { private final float[] planeDistances; // one less than there are partitions From 2aabb0a7a6a54f139db3cc2beb83881219561678 Mon Sep 17 00:00:00 2001 From: douira Date: Tue, 28 Nov 2023 18:54:13 +0100 Subject: [PATCH 146/256] avoid allocating record objects by compressing interval points into a long --- .../translucent_sorting/bsp_tree/BSPNode.java | 3 + .../bsp_tree/InnerPartitionBSPNode.java | 95 ++++++++++++------- 2 files changed, 64 insertions(+), 34 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java index 4810d7eab2..729af354c2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java @@ -23,6 +23,9 @@ public abstract class BSPNode { public abstract void collectSortedQuads(IntBuffer indexBuffer, Vector3fc cameraPos); public static BSPResult buildBSP(TQuad[] quads, ChunkSectionPos sectionPos) { + // throw if there's too many quads + InnerPartitionBSPNode.validateQuadCount(quads.length); + // create a workspace and then the nodes figure out the recursive building. // throws if the BSP can't be built, null if none is necessary var workspace = new BSPWorkspace(quads, sectionPos); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java index b4e2e490df..9c3deb162e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java @@ -1,10 +1,10 @@ package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; -import java.util.Comparator; - import org.joml.Vector3fc; import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.longs.LongArrayList; +import it.unimi.dsi.fastutil.longs.LongComparator; import it.unimi.dsi.fastutil.objects.ReferenceArrayList; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; @@ -40,31 +40,57 @@ abstract class InnerPartitionBSPNode extends BSPNode { this.planeNormal = planeNormal; } - private static record IntervalPoint(float distance, int quadIndex, byte type) { - // the indices of the type are chosen such that tie-breaking items that have the - // same distance with the type ascending yields a beneficial sort order - // (END of the current interval, on-edge quads, then the START of the next - // interval) + private static long encodeIntervalPoint(float distance, int quadIndex, int type) { + return ((long) Float.floatToRawIntBits(distance) << 32) | ((long) type << 30) | quadIndex; + } - // the start of a quad's extent in this direction - static final byte START = 2; + private static float decodeIntervalPointDistance(long encoded) { + return Float.intBitsToFloat((int) (encoded >>> 32)); + } - // end end of a quad's extent in this direction - static final byte END = 0; + private static int decodeIntervalPointQuadIndex(long encoded) { + return (int) (encoded & 0x3FFFFFFF); + } - // looking at a quad from the side where it has zero thickness - static final byte SIDE = 1; + private static int decodeIntervalPointType(long encoded) { + return (int) (encoded >>> 30) & 0b11; + } + + public static void validateQuadCount(int quadCount) { + if (quadCount * 2 > 0x3FFFFFFF) { + throw new IllegalArgumentException("Too many quads: " + quadCount); + } } - private static final Comparator INTERVAL_POINT_COMPARATOR = (a, b) -> { + // the indices of the type are chosen such that tie-breaking items that have the + // same distance with the type ascending yields a beneficial sort order + // (END of the current interval, on-edge quads, then the START of the next + // interval) + + // the start of a quad's extent in this direction + private static final int INTERVAL_START = 2; + + // end end of a quad's extent in this direction + private static final int INTERVAL_END = 0; + + // looking at a quad from the side where it has zero thickness + private static final int INTERVAL_SIDE = 1; + + private static final LongComparator INTERVAL_POINT_COMPARATOR = (a, b) -> { + // an interval point is encoded in a long as + // distance (32 bits), type (2 bits), quad index (30 bits) + + float aDistance = decodeIntervalPointDistance(a); + float bDistance = decodeIntervalPointDistance(b); + // sort by distance ascending - float distanceDiff = a.distance() - b.distance(); + float distanceDiff = aDistance - bDistance; if (distanceDiff != 0) { return distanceDiff < 0 ? -1 : 1; } // sort by type ascending - return a.type() - b.type(); + return decodeIntervalPointType(a) - decodeIntervalPointType(b); }; /** @@ -79,8 +105,7 @@ static BSPNode build(BSPWorkspace workspace) { var indexes = workspace.indexes; ReferenceArrayList partitions = new ReferenceArrayList<>(); - ReferenceArrayList points = new ReferenceArrayList<>( - (int) (indexes.size() * 1.5)); + LongArrayList points = new LongArrayList((int) (indexes.size() * 1.5)); // find any aligned partition, search each axis var axisOffset = workspace.axisOffset; @@ -98,10 +123,10 @@ static BSPNode build(BSPWorkspace workspace) { var posExtent = extents[axis]; var negExtent = extents[oppositeDirection]; if (posExtent == negExtent) { - points.add(new IntervalPoint(posExtent, quadIndex, IntervalPoint.SIDE)); + points.add(encodeIntervalPoint(posExtent, quadIndex, INTERVAL_SIDE)); } else { - points.add(new IntervalPoint(posExtent, quadIndex, IntervalPoint.END)); - points.add(new IntervalPoint(negExtent, quadIndex, IntervalPoint.START)); + points.add(encodeIntervalPoint(posExtent, quadIndex, INTERVAL_END)); + points.add(encodeIntervalPoint(negExtent, quadIndex, INTERVAL_START)); } } @@ -113,9 +138,9 @@ static BSPNode build(BSPWorkspace workspace) { IntArrayList quadsBefore = null; IntArrayList quadsOn = null; int thickness = 0; - for (IntervalPoint point : points) { - switch (point.type()) { - case IntervalPoint.START -> { + for (long point : points) { + switch (decodeIntervalPointType(point)) { + case INTERVAL_START -> { // unless at the start, flush if there's a gap if (thickness == 0 && (quadsBefore != null || quadsOn != null)) { partitions.add(new Partition(distance, quadsBefore, quadsOn)); @@ -139,36 +164,38 @@ static BSPNode build(BSPWorkspace workspace) { if (quadsBefore == null) { quadsBefore = new IntArrayList(); } - quadsBefore.add(point.quadIndex()); + quadsBefore.add(decodeIntervalPointQuadIndex(point)); } - case IntervalPoint.END -> { + case INTERVAL_END -> { thickness--; if (quadsOn == null) { - distance = point.distance(); + distance = decodeIntervalPointDistance(point); } } - case IntervalPoint.SIDE -> { + case INTERVAL_SIDE -> { // if this point in a gap, it can be put on the plane itself + int pointQuadIndex = decodeIntervalPointQuadIndex(point); if (thickness == 0) { + float pointDistance = decodeIntervalPointDistance(point); if (quadsOn == null) { // no partition end created yet, set here quadsOn = new IntArrayList(); - distance = point.distance(); - } else if (distance != point.distance()) { + distance = pointDistance; + } else if (distance != pointDistance) { // partition end has passed already, flush for new partition plane distance partitions.add(new Partition(distance, quadsBefore, quadsOn)); - distance = point.distance(); + distance = pointDistance; quadsBefore = null; quadsOn = new IntArrayList(); } - quadsOn.add(point.quadIndex()); + quadsOn.add(pointQuadIndex); } else { if (quadsBefore == null) { throw new IllegalStateException("there must be started intervals here"); } - quadsBefore.add(point.quadIndex()); + quadsBefore.add(pointQuadIndex); if (quadsOn == null) { - distance = point.distance(); + distance = decodeIntervalPointDistance(point); } } } From 492503a0b853edbcfd143278ba4efd1c3e5d6299 Mon Sep 17 00:00:00 2001 From: douira Date: Tue, 28 Nov 2023 19:19:12 +0100 Subject: [PATCH 147/256] note that avoiding new points array allocations doesn't help --- .../chunk/translucent_sorting/bsp_tree/BSPWorkspace.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java index 598d101b5a..7af9ce3577 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java @@ -6,6 +6,11 @@ import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; import net.minecraft.util.math.ChunkSectionPos; +/** + * Implementation note: Storing the multi partition node's interval points in a + * global array instead of making a new one at each tree level doesn't appear to + * have any performance benefit. + */ class BSPWorkspace { /** * All the quads in the section. From b5289da174900d534c562dab15bde7a235eb3389 Mon Sep 17 00:00:00 2001 From: douira Date: Tue, 28 Nov 2023 22:32:34 +0100 Subject: [PATCH 148/256] all the axis offset depth --- .../chunk/translucent_sorting/bsp_tree/BSPNode.java | 4 ++-- .../translucent_sorting/bsp_tree/BSPWorkspace.java | 4 ++-- .../bsp_tree/InnerPartitionBSPNode.java | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java index 729af354c2..6df16c0d83 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java @@ -83,9 +83,9 @@ static BSPNode build(BSPWorkspace workspace) { return InnerPartitionBSPNode.build(workspace); } - static BSPNode buildChild(BSPWorkspace workspace, IntArrayList indexes, int currentAxisOffset) { + static BSPNode buildChild(BSPWorkspace workspace, IntArrayList indexes, int currentDepth) { workspace.indexes = indexes; - workspace.axisOffset = (currentAxisOffset + 1) % 3; + workspace.depth = currentDepth + 1; return build(workspace); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java index 7af9ce3577..6ffb59185a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java @@ -25,9 +25,9 @@ class BSPWorkspace { IntArrayList indexes; /** - * The axis to start the next recursive BSP build on. + * The current depth of the recursive BSP building process. */ - int axisOffset = 1; + int depth = 1; BSPResult result = new BSPResult(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java index 9c3deb162e..429174a339 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java @@ -108,9 +108,9 @@ static BSPNode build(BSPWorkspace workspace) { LongArrayList points = new LongArrayList((int) (indexes.size() * 1.5)); // find any aligned partition, search each axis - var axisOffset = workspace.axisOffset; + var depth = workspace.depth; for (int axisCount = 0; axisCount < 3; axisCount++) { - int axis = (axisCount + axisOffset) % 3; + int axis = (axisCount + depth) % 3; var facing = ModelQuadFacing.VALUES[axis]; var oppositeFacing = facing.getOpposite(); var oppositeDirection = oppositeFacing.ordinal(); @@ -232,10 +232,10 @@ static BSPNode build(BSPWorkspace workspace) { BSPNode insideNode = null; BSPNode outsideNode = null; if (inside.quadsBefore() != null) { - insideNode = BSPNode.buildChild(workspace, inside.quadsBefore(), axisOffset); + insideNode = BSPNode.buildChild(workspace, inside.quadsBefore(), depth); } if (outside != null) { - outsideNode = BSPNode.buildChild(workspace, outside.quadsBefore(), axisOffset); + outsideNode = BSPNode.buildChild(workspace, outside.quadsBefore(), depth); } var onPlane = inside.quadsOn() == null ? null : inside.quadsOn().toIntArray(); @@ -269,7 +269,7 @@ static BSPNode build(BSPWorkspace workspace) { } if (partition.quadsBefore() != null) { - partitionNodes[i] = BSPNode.buildChild(workspace, partition.quadsBefore(), axisOffset); + partitionNodes[i] = BSPNode.buildChild(workspace, partition.quadsBefore(), depth); } if (partition.quadsOn() != null) { onPlaneQuads[i] = partition.quadsOn().toIntArray(); From fd8c576ece4a4f4d2f6fd647361ccd5daa8a16c9 Mon Sep 17 00:00:00 2001 From: douira Date: Tue, 28 Nov 2023 22:34:33 +0100 Subject: [PATCH 149/256] better name of trailing plane --- .../bsp_tree/InnerPartitionBSPNode.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java index 429174a339..cc7f6fa284 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java @@ -211,12 +211,12 @@ static BSPNode build(BSPWorkspace workspace) { // check if there's a trailing plane. Otherwise the last plane has distance -1 // since it just holds the trailing quads - boolean trailingPlane = quadsOn != null; + boolean endsWithPlane = quadsOn != null; // flush the last partition, use the -1 distance to indicate the end if it // doesn't use quadsOn (which requires a certain distance to be given) if (quadsBefore != null || quadsOn != null) { - partitions.add(new Partition(trailingPlane ? distance : -1, quadsBefore, quadsOn)); + partitions.add(new Partition(endsWithPlane ? distance : -1, quadsBefore, quadsOn)); } // check if this can be turned into a binary partition node @@ -225,7 +225,7 @@ static BSPNode build(BSPWorkspace workspace) { // get the two partitions var inside = partitions.get(0); var outside = partitions.size() == 2 ? partitions.get(1) : null; - if (outside == null || !trailingPlane) { + if (outside == null || !endsWithPlane) { var partitionDistance = inside.distance(); workspace.addAlignedPartitionPlane(axis, partitionDistance); @@ -246,7 +246,7 @@ static BSPNode build(BSPWorkspace workspace) { } // create a multi-partition node - int planeCount = trailingPlane ? partitions.size() : partitions.size() - 1; + int planeCount = endsWithPlane ? partitions.size() : partitions.size() - 1; float[] planeDistances = new float[planeCount]; BSPNode[] partitionNodes = new BSPNode[planeCount + 1]; int[][] onPlaneQuads = new int[planeCount][]; @@ -256,7 +256,7 @@ static BSPNode build(BSPWorkspace workspace) { var partition = partitions.get(i); // if the partition actually has a plane - if (trailingPlane || i < count - 1) { + if (endsWithPlane || i < count - 1) { var partitionDistance = partition.distance(); workspace.addAlignedPartitionPlane(axis, partitionDistance); From e880b531557fef919e3ccbdf6227b59c7bc6238f Mon Sep 17 00:00:00 2001 From: douira Date: Tue, 28 Nov 2023 23:34:24 +0100 Subject: [PATCH 150/256] note that bucketization doesn't work --- .../translucent_sorting/bsp_tree/InnerPartitionBSPNode.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java index cc7f6fa284..a7a023028e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java @@ -32,6 +32,10 @@ * schedule event. If there's a running task, a new task needs to be scheduled * with an updated camera position, though I think this already works similarly * to how rebuilds can be scheduled during a running rebuild. + * + * Implementation note: + * - Presorting the points in block-sized buckets doesn't help. It seems the + * sort algorithm is just fast enough to handle this. */ abstract class InnerPartitionBSPNode extends BSPNode { final Vector3fc planeNormal; From c600e8cdea4e6f840ee9effd9846f5afd8632070 Mon Sep 17 00:00:00 2001 From: douira Date: Tue, 28 Nov 2023 23:51:18 +0100 Subject: [PATCH 151/256] note on convex box test --- .../translucent_sorting/bsp_tree/BSPNode.java | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java index 6df16c0d83..781f2ad343 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java @@ -15,9 +15,10 @@ * into groups on either side of a plane and those that lie on the plane. * There's also leaf nodes that contain one or more quads. * - * TODO: - * - historgram of BSP build and sort times on a standard world loading scenario - * (maybe something like hermitcraft?) with some artificial structures too. + * Implementation note: + * - Doing a convex box test doesn't seem to bring a performance boost, even if + * it does trigger sometimes with man-made structures. The multi partition node + * probably does most of the work already. */ public abstract class BSPNode { public abstract void collectSortedQuads(IntBuffer indexBuffer, Vector3fc cameraPos); @@ -36,17 +37,14 @@ public static BSPResult buildBSP(TQuad[] quads, ChunkSectionPos sectionPos) { } static BSPNode build(BSPWorkspace workspace) { + var indexes = workspace.indexes; + // pick which type of node to create for the given workspace - // TODO: add more heuristics here - if (workspace.indexes.isEmpty()) { + if (indexes.isEmpty()) { return null; - } else if (workspace.indexes.size() == 1) { - return new LeafSingleBSPNode(workspace.indexes.getInt(0)); - } - - // special case two quads - var indexes = workspace.indexes; - if (indexes.size() == 2) { + } else if (indexes.size() == 1) { + return new LeafSingleBSPNode(indexes.getInt(0)); + } else if (indexes.size() == 2) { var quadIndexA = indexes.getInt(0); var quadIndexB = indexes.getInt(1); var quadA = workspace.quads[quadIndexA]; From 4f1fb35495b3e5adab2bbc9823cbd6cbf2e5b438 Mon Sep 17 00:00:00 2001 From: douira Date: Wed, 29 Nov 2023 21:47:09 +0100 Subject: [PATCH 152/256] improve performance of interval point sorting --- .../bsp_tree/InnerPartitionBSPNode.java | 33 ++++++++----------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java index a7a023028e..75b1d76a24 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java @@ -1,10 +1,11 @@ package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; +import java.util.Arrays; + import org.joml.Vector3fc; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.longs.LongArrayList; -import it.unimi.dsi.fastutil.longs.LongComparator; import it.unimi.dsi.fastutil.objects.ReferenceArrayList; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; @@ -36,6 +37,15 @@ * Implementation note: * - Presorting the points in block-sized buckets doesn't help. It seems the * sort algorithm is just fast enough to handle this. + * - Eliminating the use of partition objects doesn't help. Since there's + * usually just very few partitions, it's not worth it it seems. + * + * The encoding doesn't currently support negative distances (nor does such + * support appear to be required). Their ordering is wrong when sorting them by + * their binary representation. To fix this: "XOR all positive numbers with + * 0x8000... and negative numbers with 0xffff... This should flip the sign bit + * on both (so negative numbers go first), and then reverse the ordering on + * negative numbers." from https://stackoverflow.com/q/43299299 */ abstract class InnerPartitionBSPNode extends BSPNode { final Vector3fc planeNormal; @@ -80,23 +90,6 @@ public static void validateQuadCount(int quadCount) { // looking at a quad from the side where it has zero thickness private static final int INTERVAL_SIDE = 1; - private static final LongComparator INTERVAL_POINT_COMPARATOR = (a, b) -> { - // an interval point is encoded in a long as - // distance (32 bits), type (2 bits), quad index (30 bits) - - float aDistance = decodeIntervalPointDistance(a); - float bDistance = decodeIntervalPointDistance(b); - - // sort by distance ascending - float distanceDiff = aDistance - bDistance; - if (distanceDiff != 0) { - return distanceDiff < 0 ? -1 : 1; - } - - // sort by type ascending - return decodeIntervalPointType(a) - decodeIntervalPointType(b); - }; - /** * models a partition of the space into a set of quads that lie inside or on the * plane with the specified distance. If the distance is -1 this is the "end" @@ -134,7 +127,9 @@ static BSPNode build(BSPWorkspace workspace) { } } - points.sort(INTERVAL_POINT_COMPARATOR); + // sort interval points by distance ascending and then by type. Sorting the + // longs directly has the same effect because of the encoding. + Arrays.sort(points.elements(), 0, points.size()); // find gaps partitions.clear(); From 437f768d53d0aae375780df7f1e084190d6467af Mon Sep 17 00:00:00 2001 From: douira Date: Thu, 30 Nov 2023 03:30:36 +0100 Subject: [PATCH 153/256] make size conversion methods more accessible --- .../translucent_sorting/data/TranslucentData.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TranslucentData.java index 9036b69c31..41324d7fff 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TranslucentData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TranslucentData.java @@ -45,16 +45,20 @@ public void prepareTrigger(boolean isAngleTrigger) { // no-op for other translucent data than GFNI dynamic } - static int vertexCountToIndexBytes(int vertexCount) { + public static int vertexCountToIndexBytes(int vertexCount) { // convert vertex count to quads, and then to indices, and then to bytes return vertexCount / VERTICES_PER_QUAD * BYTES_PER_QUAD; } - static int quadCountToIndexBytes(int quadCount) { + public static int quadCountToIndexBytes(int quadCount) { return quadCount * BYTES_PER_QUAD; } - static int indexBytesToQuadCount(int indexBytes) { + public static int quadCountToIndexCount(int quadCount) { + return quadCount * INDICES_PER_QUAD; + } + + public static int indexBytesToQuadCount(int indexBytes) { return indexBytes / BYTES_PER_QUAD; } From a4d8473e8fdb3855e756714a11118c9cde924062 Mon Sep 17 00:00:00 2001 From: douira Date: Thu, 30 Nov 2023 20:39:17 +0100 Subject: [PATCH 154/256] remove unused class --- .../render/chunk/data/IndexedPrimitives.java | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/IndexedPrimitives.java diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/IndexedPrimitives.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/IndexedPrimitives.java deleted file mode 100644 index 5233dfcd54..0000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/IndexedPrimitives.java +++ /dev/null @@ -1,16 +0,0 @@ -package me.jellysquid.mods.sodium.client.render.chunk.data; - -import org.joml.Vector3f; - -public class IndexedPrimitives { - public final Vector3f[] centers; - public int[] indexes; - - public IndexedPrimitives(Vector3f[] centers) { - this.centers = centers; - this.indexes = new int[centers.length]; - for (int i = 0; i < centers.length; i++) { - this.indexes[i] = i; - } - } -} From 06ae489d6fe9eceda1d109de447ded2627fe1c6d Mon Sep 17 00:00:00 2001 From: douira Date: Thu, 30 Nov 2023 20:43:24 +0100 Subject: [PATCH 155/256] remove unused file --- .../client/gl/buffer/IndexedVertexData.java | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/IndexedVertexData.java diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/IndexedVertexData.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/IndexedVertexData.java deleted file mode 100644 index e70b82c64f..0000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/IndexedVertexData.java +++ /dev/null @@ -1,18 +0,0 @@ -package me.jellysquid.mods.sodium.client.gl.buffer; - -import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexFormat; -import me.jellysquid.mods.sodium.client.util.NativeBuffer; - -/** - * Helper type for tagging the vertex format alongside the raw buffer data. - * - * TODO: this file is unused? - */ -public record IndexedVertexData(GlVertexFormat vertexFormat, - NativeBuffer vertexBuffer, - NativeBuffer indexBuffer) { - public void delete() { - this.vertexBuffer.free(); - this.indexBuffer.free(); - } -} From 3493b89a225973b2c39ec4b124b56472975c2233 Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 1 Dec 2023 00:57:38 +0100 Subject: [PATCH 156/256] deduplicate createRegionTessellation method --- .../render/chunk/DefaultChunkRenderer.java | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java index c41ec330c5..eb9b67bdbc 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java @@ -249,7 +249,7 @@ private GlTessellation prepareTessellation(CommandList commandList, RenderRegion GlTessellation tessellation = resources.getTessellation(); if (tessellation == null) { - tessellation = this.createRegionTessellation(commandList, resources); + tessellation = this.createRegionTessellation(commandList, resources, true); resources.updateTessellation(commandList, tessellation); } @@ -261,30 +261,22 @@ private GlTessellation prepareIndexedTessellation(CommandList commandList, Rende GlTessellation tessellation = resources.getIndexedTessellation(); if (tessellation == null) { - tessellation = this.createIndexedRegionTessellation(commandList, resources); + tessellation = this.createRegionTessellation(commandList, resources, false); resources.updateIndexedTessellation(commandList, tessellation); } return tessellation; } - private GlTessellation createRegionTessellation(CommandList commandList, RenderRegion.DeviceResources resources) { + private GlTessellation createRegionTessellation(CommandList commandList, RenderRegion.DeviceResources resources, boolean useSharedIndexBuffer) { return commandList.createTessellation(GlPrimitiveType.TRIANGLES, new TessellationBinding[] { TessellationBinding.forVertexBuffer(resources.getGeometryBuffer(), new GlVertexAttributeBinding[] { new GlVertexAttributeBinding(ChunkShaderBindingPoints.ATTRIBUTE_PACKED_DATA, this.vertexFormat.getAttribute(ChunkMeshAttribute.VERTEX_DATA)) }), - TessellationBinding.forElementBuffer(this.sharedIndexBuffer.getBufferObject()) - }); - } - - private GlTessellation createIndexedRegionTessellation(CommandList commandList, RenderRegion.DeviceResources resources) { - return commandList.createTessellation(GlPrimitiveType.TRIANGLES, new TessellationBinding[] { - TessellationBinding.forVertexBuffer(resources.getGeometryBuffer(), new GlVertexAttributeBinding[] { - new GlVertexAttributeBinding(ChunkShaderBindingPoints.ATTRIBUTE_PACKED_DATA, - this.vertexFormat.getAttribute(ChunkMeshAttribute.VERTEX_DATA)) - }), - TessellationBinding.forElementBuffer(resources.getIndexBuffer()) + TessellationBinding.forElementBuffer(useSharedIndexBuffer + ? this.sharedIndexBuffer.getBufferObject() + : resources.getIndexBuffer()) }); } From 75b473354a7cddfb6673293c567dd881de9e20ef Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 1 Dec 2023 01:15:26 +0100 Subject: [PATCH 157/256] fix model quad facing code alignment --- .../model/quad/properties/ModelQuadFacing.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java index 226d5d3660..7ee3745c56 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java @@ -36,12 +36,12 @@ public enum ModelQuadFacing { public static ModelQuadFacing fromDirection(Direction dir) { return switch (dir) { - case DOWN -> NEG_Y; - case UP -> POS_Y; - case NORTH -> NEG_Z; - case SOUTH -> POS_Z; - case WEST -> NEG_X; - case EAST -> POS_X; + case DOWN -> NEG_Y; + case UP -> POS_Y; + case NORTH -> NEG_Z; + case SOUTH -> POS_Z; + case WEST -> NEG_X; + case EAST -> POS_X; }; } From 0d9cb834cc4e87fe6ebdfd26203fe3aacd75498a Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 1 Dec 2023 01:24:52 +0100 Subject: [PATCH 158/256] change the setting states off/reduced/accurate --- .../jellysquid/mods/sodium/client/gui/SodiumGameOptions.java | 4 ++-- src/main/resources/assets/sodium/lang/en_us.json | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java index 9d37a40a7a..1c4ba5c1ae 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java @@ -51,8 +51,8 @@ public static class PerformanceSettings { public enum SortBehavior implements TextProvider { OFF("options.off"), - STATIC("options.clouds.fast"), - DYNAMIC("options.clouds.fancy"); + STATIC("sodium.options.sort_behavior.reduced"), + DYNAMIC("sodium.options.sort_behavior.accurate"); private final Text name; diff --git a/src/main/resources/assets/sodium/lang/en_us.json b/src/main/resources/assets/sodium/lang/en_us.json index d0685f7c28..abcaaffe17 100644 --- a/src/main/resources/assets/sodium/lang/en_us.json +++ b/src/main/resources/assets/sodium/lang/en_us.json @@ -61,5 +61,7 @@ "sodium.console.core_shaders_warn": "The following resource packs may be incompatible with Sodium:", "sodium.console.core_shaders_info": "Check the game log for detailed information.", "sodium.options.sort_behavior.name": "Translucency Sorting", - "sodium.options.sort_behavior.tooltip": "Controls when and with how much effort translucency sorting is performed. Fancy attempts correct sorting everywhere while in Fast mode there may be glitches. More sorting has a performance impact on chunk loading speeds, but usually not frame rates." + "sodium.options.sort_behavior.tooltip": "Controls when and with how much effort translucency sorting is performed. Accurate mode attempts correct sorting everywhere while in Reduced mode there will be glitches. More sorting has a performance impact on chunk loading and update speeds, but usually not frame rates.", + "sodium.options.sort_behavior.reduced": "Reduced", + "sodium.options.sort_behavior.accurate": "Accurate" } From 83aaf4299c2ddfa048137aed50af7c3a64c793f6 Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 1 Dec 2023 02:53:32 +0100 Subject: [PATCH 159/256] update notes with findings --- .../bsp_tree/InnerPartitionBSPNode.java | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java index 75b1d76a24..0a58320c00 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java @@ -22,23 +22,15 @@ * level: convex hulls (like cuboids where the faces point outwards) don't need * to be sorted. This could be used to optimize the inside of honey blocks, and * other blocks. - * - the section full of honey and slime blocks seems to be sorted ok but when - * the camera moves too fast across the surface near a corner it breaks. My - * theory is that it breaks from the slime blocks having a small inner block - * that produces a plane that the camera passes over first but then it's still - * sorting when the camera crosses over the second so it sorts it with the - * camera between the two and doesn't sort it again when the camera has passed - * over the second. This is fixed by making sure the scheduling of sort tasks - * makes a new pending task with a new camera position if there's a newer - * schedule event. If there's a running task, a new task needs to be scheduled - * with an updated camera position, though I think this already works similarly - * to how rebuilds can be scheduled during a running rebuild. * * Implementation note: * - Presorting the points in block-sized buckets doesn't help. It seems the * sort algorithm is just fast enough to handle this. * - Eliminating the use of partition objects doesn't help. Since there's * usually just very few partitions, it's not worth it it seems. + * - Using fastutil's LongArrays sorting options (radix and quicksort) is slower + * than using Arrays.sort (which uses DualPivotQuicksort internally), even on + * worlds with player-built structures. * * The encoding doesn't currently support negative distances (nor does such * support appear to be required). Their ordering is wrong when sorting them by From ae539a8404428b227efa278e93d1f776f06e9028 Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 2 Dec 2023 04:48:53 +0100 Subject: [PATCH 160/256] replace quantization with quad shrinking which avoids identical quad sorting errors but also avoids intersecting geometry --- .../TranslucentGeometryCollector.java | 39 ++++++++++++------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java index e4aed5a9cf..6c07a8b825 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java @@ -75,10 +75,6 @@ public TranslucentGeometryCollector(ChunkSectionPos sectionPos) { } } - private static float quantizeEpsilon(float value) { - return (float) Math.floor(value * INV_QUANTIZE_EPSILON + 0.5) * QUANTIZE_EPSILON; - } - public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] vertices, ModelQuadFacing facing, boolean flipNormal) { float xSum = 0; @@ -124,17 +120,34 @@ public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] verti } } - var centerX = quantizeEpsilon(xSum / uniqueQuads); - var centerY = quantizeEpsilon(ySum / uniqueQuads); - var centerZ = quantizeEpsilon(zSum / uniqueQuads); + var centerX = xSum / uniqueQuads; + var centerY = ySum / uniqueQuads; + var centerZ = zSum / uniqueQuads; var center = new Vector3f(centerX, centerY, centerZ); - posXExtent = quantizeEpsilon(posXExtent); - posYExtent = quantizeEpsilon(posYExtent); - posZExtent = quantizeEpsilon(posZExtent); - negXExtent = quantizeEpsilon(negXExtent); - negYExtent = quantizeEpsilon(negYExtent); - negZExtent = quantizeEpsilon(negZExtent); + // shrink quad in non-normal directions to prevent intersections caused by + // epsilon offsets applied by FluidRenderer + if (facing != ModelQuadFacing.POS_X && facing != ModelQuadFacing.NEG_X) { + posXExtent -= QUANTIZE_EPSILON; + negXExtent += QUANTIZE_EPSILON; + if (negXExtent > posXExtent) { + negXExtent = posXExtent; + } + } + if (facing != ModelQuadFacing.POS_Y && facing != ModelQuadFacing.NEG_Y) { + posYExtent -= QUANTIZE_EPSILON; + negYExtent += QUANTIZE_EPSILON; + if (negYExtent > posYExtent) { + negYExtent = posYExtent; + } + } + if (facing != ModelQuadFacing.POS_Z && facing != ModelQuadFacing.NEG_Z) { + posZExtent -= QUANTIZE_EPSILON; + negZExtent += QUANTIZE_EPSILON; + if (negZExtent > posZExtent) { + negZExtent = posZExtent; + } + } if (facing != ModelQuadFacing.UNASSIGNED && this.unalignedDistances == null) { maxBounds.x = Math.max(maxBounds.x, posXExtent); From 2d5ee2c48806a406bc6a349f0d43c849e67f91b7 Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 2 Dec 2023 23:19:15 +0100 Subject: [PATCH 161/256] impl notes, lazy sort doesn't work well --- .../translucent_sorting/bsp_tree/InnerPartitionBSPNode.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java index 0a58320c00..aa7f838976 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java @@ -31,6 +31,9 @@ * - Using fastutil's LongArrays sorting options (radix and quicksort) is slower * than using Arrays.sort (which uses DualPivotQuicksort internally), even on * worlds with player-built structures. + * - A simple attempt at lazily writing index data to the buffer didn't yield a + * performance improvement. Maybe applying it to the multi partition node would + * be more effective (but also much more complex and slower). * * The encoding doesn't currently support negative distances (nor does such * support appear to be required). Their ordering is wrong when sorting them by From 96b41f24dd1ae49b3fa76c13a7069db11771ce5d Mon Sep 17 00:00:00 2001 From: douira Date: Tue, 5 Dec 2023 02:50:13 +0100 Subject: [PATCH 162/256] implement partial bsp tree updates --- .../chunk/translucent_sorting/TQuad.java | 16 +- .../TranslucentGeometryCollector.java | 7 +- .../translucent_sorting/bsp_tree/BSPNode.java | 34 ++-- .../bsp_tree/BSPSortState.java | 74 ++++++++ .../bsp_tree/BSPWorkspace.java | 20 +- .../bsp_tree/InnerBinaryPartitionBSPNode.java | 60 ++++-- .../bsp_tree/InnerMultiPartitionBSPNode.java | 99 ++++++++-- .../bsp_tree/InnerPartitionBSPNode.java | 177 +++++++++++------- .../bsp_tree/LeafDoubleBSPNode.java | 10 +- .../bsp_tree/LeafMultiBSPNode.java | 8 +- .../bsp_tree/LeafSingleBSPNode.java | 8 +- .../bsp_tree/Partition.java | 11 ++ .../data/BSPDynamicData.java | 12 +- 13 files changed, 377 insertions(+), 159 deletions(-) create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/Partition.java diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java index 184509a701..1aef4c7225 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java @@ -10,9 +10,6 @@ /** * Represents a quad for the purposes of translucency sorting. Called TQuad to * avoid confusion with other quad classes. - * - * @implNote Autogenerated hashcode and equals methods to ensure the arrays are - * correctly compared.. */ public record TQuad(ModelQuadFacing facing, Vector3fc normal, Vector3f center, float[] extents) { int getQuadHash() { @@ -48,4 +45,17 @@ public float getAlignedSurfaceArea() { return 0; } } + + public boolean extentsEqual(float[] other) { + return extentsEqual(this.extents, other); + } + + public static boolean extentsEqual(float[] a, float[] b) { + for (int i = 0; i < 6; i++) { + if (a[i] != b[i]) { + return false; + } + } + return true; + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java index 6c07a8b825..5d90bb9d20 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java @@ -401,7 +401,8 @@ public SortType finishRendering() { return this.sortType; } - private TranslucentData makeNewTranslucentData(BuiltSectionMeshParts translucentMesh, Vector3fc cameraPos) { + private TranslucentData makeNewTranslucentData(BuiltSectionMeshParts translucentMesh, Vector3fc cameraPos, + TranslucentData oldData) { if (this.sortType == SortType.NONE) { return AnyOrderData.fromMesh(translucentMesh, quads, sectionPos, null); } @@ -431,7 +432,7 @@ private TranslucentData makeNewTranslucentData(BuiltSectionMeshParts translucent if (this.sortType == SortType.DYNAMIC_ALL) { try { - return BSPDynamicData.fromMesh(translucentMesh, cameraPos, quads, sectionPos, buffer); + return BSPDynamicData.fromMesh(translucentMesh, cameraPos, quads, sectionPos, buffer, oldData); } catch (BSPBuildFailureException e) { System.out.println("BSP build failure: " + sectionPos); return TopoSortDynamicData.fromMesh(translucentMesh, cameraPos, quads, sectionPos, this, buffer); @@ -486,7 +487,7 @@ public TranslucentData getTranslucentData( } } - var newData = makeNewTranslucentData(translucentMesh, cameraPos); + var newData = makeNewTranslucentData(translucentMesh, cameraPos, oldData); if (newData instanceof PresentTranslucentData presentData) { presentData.setQuadHash(getQuadHash(this.quads)); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java index 781f2ad343..0893474721 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java @@ -1,13 +1,12 @@ package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; -import java.nio.IntBuffer; - import org.joml.Vector3fc; import it.unimi.dsi.fastutil.ints.IntArrayList; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TopoGraphSorting; +import me.jellysquid.mods.sodium.client.util.NativeBuffer; import net.minecraft.util.math.ChunkSectionPos; /** @@ -21,23 +20,36 @@ * probably does most of the work already. */ public abstract class BSPNode { - public abstract void collectSortedQuads(IntBuffer indexBuffer, Vector3fc cameraPos); - public static BSPResult buildBSP(TQuad[] quads, ChunkSectionPos sectionPos) { + abstract void collectSortedQuads(BSPSortState sortState, Vector3fc cameraPos); + + public void collectSortedQuads(NativeBuffer nativeBuffer, Vector3fc cameraPos) { + this.collectSortedQuads(new BSPSortState(nativeBuffer), cameraPos); + } + + public static BSPResult buildBSP(TQuad[] quads, ChunkSectionPos sectionPos, BSPNode oldRoot) { // throw if there's too many quads InnerPartitionBSPNode.validateQuadCount(quads.length); // create a workspace and then the nodes figure out the recursive building. // throws if the BSP can't be built, null if none is necessary var workspace = new BSPWorkspace(quads, sectionPos); - var rootNode = BSPNode.build(workspace); + + // initialize the indexes to all quads + int[] initialIndexes = new int[quads.length]; + for (int i = 0; i < quads.length; i++) { + initialIndexes[i] = i; + } + var allIndexes = new IntArrayList(initialIndexes); + + var rootNode = BSPNode.build(workspace, allIndexes, -1, oldRoot); var result = workspace.result; result.rootNode = rootNode; return result; } - static BSPNode build(BSPWorkspace workspace) { - var indexes = workspace.indexes; + static BSPNode build(BSPWorkspace workspace, IntArrayList indexes, int depth, BSPNode oldNode) { + depth++; // pick which type of node to create for the given workspace if (indexes.isEmpty()) { @@ -78,12 +90,6 @@ static BSPNode build(BSPWorkspace workspace) { } } - return InnerPartitionBSPNode.build(workspace); - } - - static BSPNode buildChild(BSPWorkspace workspace, IntArrayList indexes, int currentDepth) { - workspace.indexes = indexes; - workspace.depth = currentDepth + 1; - return build(workspace); + return InnerPartitionBSPNode.build(workspace, indexes, depth, oldNode); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java new file mode 100644 index 0000000000..9cb55bddc9 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java @@ -0,0 +1,74 @@ +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; + +import java.nio.IntBuffer; + +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; +import me.jellysquid.mods.sodium.client.util.NativeBuffer; + +class BSPSortState { + static final int NO_FIXED_OFFSET = Integer.MIN_VALUE; + + private final IntBuffer indexBuffer; + + private int indexModificationsRemaining; + private int[] indexMap; + private int fixedIndexOffset = NO_FIXED_OFFSET; + + BSPSortState(NativeBuffer nativeBuffer) { + this.indexBuffer = nativeBuffer.getDirectBuffer().asIntBuffer(); + } + + void startNode(InnerPartitionBSPNode node) { + if (node.indexMap != null) { + if (this.indexMap != null || this.fixedIndexOffset != NO_FIXED_OFFSET) { + throw new IllegalStateException("Index modification already in progress"); + } + + this.indexMap = node.indexMap; + this.indexModificationsRemaining = node.reuseData.indexes().length; + } else if (node.fixedIndexOffset != NO_FIXED_OFFSET) { + if (this.indexMap != null || this.fixedIndexOffset != NO_FIXED_OFFSET) { + throw new IllegalStateException("Index modification already in progress"); + } + + this.fixedIndexOffset = node.fixedIndexOffset; + this.indexModificationsRemaining = node.reuseData.indexes().length; + } + } + + private void checkModificationCounter(int reduceBy) { + this.indexModificationsRemaining -= reduceBy; + if (this.indexModificationsRemaining <= 0) { + this.indexMap = null; + this.fixedIndexOffset = NO_FIXED_OFFSET; + } + } + + void writeIndexes(int[] indexes) { + if (this.indexMap != null) { + for (int i = 0; i < indexes.length; i++) { + TranslucentData.writeQuadVertexIndexes(this.indexBuffer, this.indexMap[indexes[i]]); + } + checkModificationCounter(indexes.length); + } else if (this.fixedIndexOffset != NO_FIXED_OFFSET) { + for (int i = 0; i < indexes.length; i++) { + TranslucentData.writeQuadVertexIndexes(this.indexBuffer, this.fixedIndexOffset + indexes[i]); + } + checkModificationCounter(indexes.length); + } else { + TranslucentData.writeQuadVertexIndexes(this.indexBuffer, indexes); + } + } + + void writeIndex(int index) { + if (this.indexMap != null) { + TranslucentData.writeQuadVertexIndexes(this.indexBuffer, this.indexMap[index]); + checkModificationCounter(1); + } else if (this.fixedIndexOffset != NO_FIXED_OFFSET) { + TranslucentData.writeQuadVertexIndexes(this.indexBuffer, this.fixedIndexOffset + index); + checkModificationCounter(1); + } else { + TranslucentData.writeQuadVertexIndexes(this.indexBuffer, index); + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java index 6ffb59185a..7971845044 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java @@ -1,6 +1,5 @@ package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; -import it.unimi.dsi.fastutil.ints.IntArrayList; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.AccumulationGroup; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; @@ -19,28 +18,11 @@ class BSPWorkspace { final ChunkSectionPos sectionPos; - /** - * A list of all the quad indexes to process in the next build invocation. - */ - IntArrayList indexes; - - /** - * The current depth of the recursive BSP building process. - */ - int depth = 1; - - BSPResult result = new BSPResult(); + final BSPResult result = new BSPResult(); BSPWorkspace(TQuad[] quads, ChunkSectionPos sectionPos) { this.quads = quads; this.sectionPos = sectionPos; - - // initialize the indexes to all quads - int[] initialIndexes = new int[quads.length]; - for (int i = 0; i < quads.length; i++) { - initialIndexes[i] = i; - } - this.indexes = new IntArrayList(initialIndexes); } // TODO: better bidirectional triggering: integrate bidirectionality in GFNI if diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java index 3136386492..cec9832844 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java @@ -1,10 +1,8 @@ package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; -import java.nio.IntBuffer; - import org.joml.Vector3fc; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; +import it.unimi.dsi.fastutil.ints.IntArrayList; class InnerBinaryPartitionBSPNode extends InnerPartitionBSPNode { private final float planeDistance; @@ -14,42 +12,74 @@ class InnerBinaryPartitionBSPNode extends InnerPartitionBSPNode { private final BSPNode outside; // nullable private final int[] onPlaneQuads; - InnerBinaryPartitionBSPNode(float planeDistance, Vector3fc planeNormal, + InnerBinaryPartitionBSPNode(NodeReuseData reuseData, float planeDistance, int axis, BSPNode inside, BSPNode outside, int[] onPlaneQuads) { - super(planeNormal); + super(reuseData, axis); this.planeDistance = planeDistance; this.inside = inside; this.outside = outside; this.onPlaneQuads = onPlaneQuads; } - private void collectInside(IntBuffer indexBuffer, Vector3fc cameraPos) { + private void collectInside(BSPSortState sortState, Vector3fc cameraPos) { if (this.inside != null) { - this.inside.collectSortedQuads(indexBuffer, cameraPos); + this.inside.collectSortedQuads(sortState, cameraPos); } } - private void collectOutside(IntBuffer indexBuffer, Vector3fc cameraPos) { + private void collectOutside(BSPSortState sortState, Vector3fc cameraPos) { if (this.outside != null) { - this.outside.collectSortedQuads(indexBuffer, cameraPos); + this.outside.collectSortedQuads(sortState, cameraPos); } } @Override - public void collectSortedQuads(IntBuffer indexBuffer, Vector3fc cameraPos) { + void collectSortedQuads(BSPSortState sortState, Vector3fc cameraPos) { + sortState.startNode(this); + var cameraInside = this.planeNormal.dot(cameraPos) < this.planeDistance; if (cameraInside) { - this.collectOutside(indexBuffer, cameraPos); + this.collectOutside(sortState, cameraPos); } else { - this.collectInside(indexBuffer, cameraPos); + this.collectInside(sortState, cameraPos); } if (this.onPlaneQuads != null) { - TranslucentData.writeQuadVertexIndexes(indexBuffer, this.onPlaneQuads); + sortState.writeIndexes(this.onPlaneQuads); } if (cameraInside) { - this.collectInside(indexBuffer, cameraPos); + this.collectInside(sortState, cameraPos); } else { - this.collectOutside(indexBuffer, cameraPos); + this.collectOutside(sortState, cameraPos); + } + } + + static BSPNode build(BSPWorkspace workspace, IntArrayList indexes, int depth, BSPNode oldNode, + Partition inside, Partition outside, int axis) { + var partitionDistance = inside.distance(); + workspace.addAlignedPartitionPlane(axis, partitionDistance); + + BSPNode oldInsideNode = null; + BSPNode oldOutsideNode = null; + if (oldNode instanceof InnerBinaryPartitionBSPNode binaryNode + && binaryNode.axis == axis + && binaryNode.planeDistance == partitionDistance) { + oldInsideNode = binaryNode.inside; + oldOutsideNode = binaryNode.outside; + } + + BSPNode insideNode = null; + BSPNode outsideNode = null; + if (inside.quadsBefore() != null) { + insideNode = BSPNode.build(workspace, inside.quadsBefore(), depth, oldInsideNode); } + if (outside != null) { + outsideNode = BSPNode.build(workspace, outside.quadsBefore(), depth, oldOutsideNode); + } + var onPlane = inside.quadsOn() == null ? null : inside.quadsOn().toIntArray(); + + return new InnerBinaryPartitionBSPNode( + prepareNodeReuse(workspace, indexes, depth), + partitionDistance, axis, + insideNode, outsideNode, onPlane); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerMultiPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerMultiPartitionBSPNode.java index 407136a103..d915c21c83 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerMultiPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerMultiPartitionBSPNode.java @@ -1,10 +1,9 @@ package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; -import java.nio.IntBuffer; - import org.joml.Vector3fc; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.objects.ReferenceArrayList; /** * Implementation note: Detecting and avoiding the double array when possible @@ -17,28 +16,30 @@ class InnerMultiPartitionBSPNode extends InnerPartitionBSPNode { private final BSPNode[] partitions; private final int[][] onPlaneQuads; - InnerMultiPartitionBSPNode(float[] planeDistances, Vector3fc planeNormal, + InnerMultiPartitionBSPNode(NodeReuseData reuseData, int axis, float[] planeDistances, BSPNode[] partitions, int[][] onPlaneQuads) { - super(planeNormal); + super(reuseData, axis); this.planeDistances = planeDistances; this.partitions = partitions; this.onPlaneQuads = onPlaneQuads; } - private void collectPlaneQuads(IntBuffer indexBuffer, int planeIndex) { + private void collectPlaneQuads(BSPSortState sortState, int planeIndex) { if (this.onPlaneQuads[planeIndex] != null) { - TranslucentData.writeQuadVertexIndexes(indexBuffer, this.onPlaneQuads[planeIndex]); + sortState.writeIndexes(this.onPlaneQuads[planeIndex]); } } - private void collectPartitionQuads(IntBuffer indexBuffer, int partitionIndex, Vector3fc cameraPos) { + private void collectPartitionQuads(BSPSortState sortState, int partitionIndex, Vector3fc cameraPos) { if (this.partitions[partitionIndex] != null) { - this.partitions[partitionIndex].collectSortedQuads(indexBuffer, cameraPos); + this.partitions[partitionIndex].collectSortedQuads(sortState, cameraPos); } } @Override - public void collectSortedQuads(IntBuffer indexBuffer, Vector3fc cameraPos) { + void collectSortedQuads(BSPSortState sortState, Vector3fc cameraPos) { + sortState.startNode(this); + // calculate the camera's distance. Then render the partitions in order of // distance to the partition the camera is in. var cameraDistance = this.planeNormal.dot(cameraPos); @@ -49,28 +50,92 @@ public void collectSortedQuads(IntBuffer indexBuffer, Vector3fc cameraPos) { // collect the plane the camera is in var isOnPlane = cameraDistance == this.planeDistances[i]; if (isOnPlane) { - this.collectPartitionQuads(indexBuffer, i, cameraPos); + this.collectPartitionQuads(sortState, i, cameraPos); } // backwards sweep: collect all partitions backwards until the camera is reached for (int j = this.planeDistances.length; j > i; j--) { - this.collectPartitionQuads(indexBuffer, j, cameraPos); - this.collectPlaneQuads(indexBuffer, j - 1); + this.collectPartitionQuads(sortState, j, cameraPos); + this.collectPlaneQuads(sortState, j - 1); } if (!isOnPlane) { - this.collectPartitionQuads(indexBuffer, i, cameraPos); + this.collectPartitionQuads(sortState, i, cameraPos); } return; } // collect the quads in the partition and on the plane - this.collectPartitionQuads(indexBuffer, i, cameraPos); - this.collectPlaneQuads(indexBuffer, i); + this.collectPartitionQuads(sortState, i, cameraPos); + this.collectPlaneQuads(sortState, i); } // collect the last partition - this.collectPartitionQuads(indexBuffer, this.planeDistances.length, cameraPos); + this.collectPartitionQuads(sortState, this.planeDistances.length, cameraPos); + } + + static BSPNode build(BSPWorkspace workspace, IntArrayList indexes, int depth, BSPNode oldNode, + ReferenceArrayList partitions, int axis, boolean endsWithPlane) { + int planeCount = endsWithPlane ? partitions.size() : partitions.size() - 1; + float[] planeDistances = new float[planeCount]; + BSPNode[] partitionNodes = new BSPNode[planeCount + 1]; + int[][] onPlaneQuads = new int[planeCount][]; + + BSPNode[] oldPartitionNodes = null; + float[] oldPlaneDistances = null; + int oldChildIndex = 0; + float oldPartitionDistance = 0; + if (oldNode instanceof InnerMultiPartitionBSPNode multiNode + && multiNode.axis == axis && multiNode.partitions.length > 0) { + oldPartitionNodes = multiNode.partitions; + oldPlaneDistances = multiNode.planeDistances; + oldPartitionDistance = multiNode.planeDistances[0]; + } + + // write the partition planes and nodes + for (int i = 0, count = partitions.size(); i < count; i++) { + var partition = partitions.get(i); + + // if the partition actually has a plane + float partitionDistance = -1; + if (endsWithPlane || i < count - 1) { + partitionDistance = partition.distance(); + workspace.addAlignedPartitionPlane(axis, partitionDistance); + + // TODO: remove + if (partitionDistance == -1) { + throw new IllegalStateException("partition distance not set"); + } + + planeDistances[i] = partitionDistance; + } + + if (partition.quadsBefore() != null) { + BSPNode oldChild = null; + + if (oldPartitionNodes != null) { + // if there's a node that matches the partition's distance, use it as the old + // node. Search forwards through the old plane distances to find a candidate + while (oldChildIndex < oldPartitionNodes.length && oldPartitionDistance < partitionDistance) { + oldChildIndex++; + oldPartitionDistance = oldChildIndex < oldPlaneDistances.length + ? oldPlaneDistances[oldChildIndex] + : -1; + } + if (oldChildIndex < oldPartitionNodes.length && oldPartitionDistance == partitionDistance) { + oldChild = oldPartitionNodes[oldChildIndex]; + } + } + + partitionNodes[i] = BSPNode.build(workspace, partition.quadsBefore(), depth, oldChild); + } + if (partition.quadsOn() != null) { + onPlaneQuads[i] = partition.quadsOn().toIntArray(); + } + } + + return new InnerMultiPartitionBSPNode(prepareNodeReuse(workspace, indexes, depth), + axis, planeDistances, partitionNodes, onPlaneQuads); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java index aa7f838976..5d031985fd 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java @@ -43,10 +43,106 @@ * negative numbers." from https://stackoverflow.com/q/43299299 */ abstract class InnerPartitionBSPNode extends BSPNode { + private static int NODE_REUSE_THRESHOLD = 0; + final Vector3fc planeNormal; + final int axis; + + int[] indexMap; + int fixedIndexOffset = BSPSortState.NO_FIXED_OFFSET; + final NodeReuseData reuseData; // nullable + + /** + * Stores data required for testing if the node can be re-used. This data is + * only generated for select candidate nodes. + * + * It only stores the set of indexes that this node was constructed from and + * their extents since the BSP construction only cares about the "opaque" quad + * geometry and not the normal or facing. + */ + record NodeReuseData(float[][] quadExtents, int[] indexes, int maxIndex) { + } + + InnerPartitionBSPNode(NodeReuseData reuseData, int axis) { + this.planeNormal = ModelQuadFacing.NORMALS[axis]; + this.axis = axis; + this.reuseData = reuseData; + } + + static NodeReuseData prepareNodeReuse(BSPWorkspace workspace, IntArrayList indexes, int depth) { + // if node reuse is enabled, only enable on the first level of children (not the + // root node and not anything deeper than its children) + // TODO: more sophisticated reuse scheduling (make uset configurable, and only + // do once the section has been modified at least once already to avoid making + // this data on terrain sections that are never touched) + if (depth == 1 && indexes.size() > NODE_REUSE_THRESHOLD) { + // collect the extents of the indexed quads and hash them + var quadExtents = new float[indexes.size()][]; + int maxIndex = -1; + for (int i = 0; i < indexes.size(); i++) { + var index = indexes.getInt(i); + var quad = workspace.quads[index]; + var extents = quad.extents(); + quadExtents[i] = extents; + maxIndex = Math.max(maxIndex, index); + } + return new NodeReuseData(quadExtents, indexes.toIntArray(), maxIndex); + } + return null; + } + + static InnerPartitionBSPNode attemptNodeReuse(BSPWorkspace workspace, IntArrayList newIndexes, int depth, + InnerPartitionBSPNode oldNode) { + if (oldNode == null) { + return null; + } + + oldNode.indexMap = null; + oldNode.fixedIndexOffset = BSPSortState.NO_FIXED_OFFSET; + + var reuseData = oldNode.reuseData; + if (reuseData == null) { + return null; + } + + var oldExtents = reuseData.quadExtents; + if (oldExtents.length != newIndexes.size()) { + return null; + } + + for (int i = 0; i < newIndexes.size(); i++) { + if (!workspace.quads[newIndexes.getInt(i)].extentsEqual(oldExtents[i])) { + return null; + } + } - InnerPartitionBSPNode(Vector3fc planeNormal) { - this.planeNormal = planeNormal; + // reuse old node and either apply a fixed offset or calculate an index map to + // map from old to new indices + var oldIndexes = reuseData.indexes; + var indexMap = new int[reuseData.maxIndex + 1]; + final int OFFSET_CHANGED = Integer.MIN_VALUE; + int lastOffset = 0; + for (int i = 0; i < oldIndexes.length; i++) { + var oldIndex = oldIndexes[i]; + var newIndex = newIndexes.getInt(i); + indexMap[oldIndex] = newIndex; + var newOffset = newIndex - oldIndex; + if (i == 0) { + lastOffset = newOffset; + } else if (lastOffset != newOffset) { + lastOffset = OFFSET_CHANGED; + } + } + + // use a fixed offset if possible (if all old indices differ from the new ones + // by the same amount) + if (lastOffset != OFFSET_CHANGED) { + oldNode.fixedIndexOffset = lastOffset; + } else { + oldNode.indexMap = indexMap; + } + + return oldNode; } private static long encodeIntervalPoint(float distance, int quadIndex, int type) { @@ -85,27 +181,22 @@ public static void validateQuadCount(int quadCount) { // looking at a quad from the side where it has zero thickness private static final int INTERVAL_SIDE = 1; - /** - * models a partition of the space into a set of quads that lie inside or on the - * plane with the specified distance. If the distance is -1 this is the "end" - * partition after the last partition plane. - */ - private static record Partition(float distance, IntArrayList quadsBefore, IntArrayList quadsOn) { - } - - static BSPNode build(BSPWorkspace workspace) { - var indexes = workspace.indexes; + static BSPNode build(BSPWorkspace workspace, IntArrayList indexes, int depth, BSPNode oldNode) { + // attempt reuse of the old node if possible + if (oldNode instanceof InnerPartitionBSPNode oldInnerNode) { + var reusedNode = InnerPartitionBSPNode.attemptNodeReuse(workspace, indexes, depth, oldInnerNode); + if (reusedNode != null) { + return reusedNode; + } + } ReferenceArrayList partitions = new ReferenceArrayList<>(); LongArrayList points = new LongArrayList((int) (indexes.size() * 1.5)); // find any aligned partition, search each axis - var depth = workspace.depth; for (int axisCount = 0; axisCount < 3; axisCount++) { - int axis = (axisCount + depth) % 3; - var facing = ModelQuadFacing.VALUES[axis]; - var oppositeFacing = facing.getOpposite(); - var oppositeDirection = oppositeFacing.ordinal(); + int axis = (axisCount + depth) % 3; // TODO: depth + 1 to start with Y axis + var oppositeDirection = axis + 3; // collect all the geometry's start and end points in this direction points.clear(); @@ -220,58 +311,14 @@ static BSPNode build(BSPWorkspace workspace) { var inside = partitions.get(0); var outside = partitions.size() == 2 ? partitions.get(1) : null; if (outside == null || !endsWithPlane) { - var partitionDistance = inside.distance(); - workspace.addAlignedPartitionPlane(axis, partitionDistance); - - BSPNode insideNode = null; - BSPNode outsideNode = null; - if (inside.quadsBefore() != null) { - insideNode = BSPNode.buildChild(workspace, inside.quadsBefore(), depth); - } - if (outside != null) { - outsideNode = BSPNode.buildChild(workspace, outside.quadsBefore(), depth); - } - var onPlane = inside.quadsOn() == null ? null : inside.quadsOn().toIntArray(); - - return new InnerBinaryPartitionBSPNode( - partitionDistance, ModelQuadFacing.NORMALS[axis], - insideNode, outsideNode, onPlane); + return InnerBinaryPartitionBSPNode.build(workspace, indexes, depth, oldNode, + inside, outside, axis); } } // create a multi-partition node - int planeCount = endsWithPlane ? partitions.size() : partitions.size() - 1; - float[] planeDistances = new float[planeCount]; - BSPNode[] partitionNodes = new BSPNode[planeCount + 1]; - int[][] onPlaneQuads = new int[planeCount][]; - - // write the partition planes and nodes - for (int i = 0, count = partitions.size(); i < count; i++) { - var partition = partitions.get(i); - - // if the partition actually has a plane - if (endsWithPlane || i < count - 1) { - var partitionDistance = partition.distance(); - workspace.addAlignedPartitionPlane(axis, partitionDistance); - - // TODO: remove - if (partitionDistance == -1) { - throw new IllegalStateException("partition distance not set"); - } - - planeDistances[i] = partitionDistance; - } - - if (partition.quadsBefore() != null) { - partitionNodes[i] = BSPNode.buildChild(workspace, partition.quadsBefore(), depth); - } - if (partition.quadsOn() != null) { - onPlaneQuads[i] = partition.quadsOn().toIntArray(); - } - } - - return new InnerMultiPartitionBSPNode(planeDistances, ModelQuadFacing.NORMALS[axis], - partitionNodes, onPlaneQuads); + return InnerMultiPartitionBSPNode.build(workspace, indexes, depth, oldNode, + partitions, axis, endsWithPlane); } // TODO: attempt unaligned partitioning, convex decomposition, etc. diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafDoubleBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafDoubleBSPNode.java index bf5e3ce59b..5db07d4929 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafDoubleBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafDoubleBSPNode.java @@ -1,11 +1,7 @@ package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; -import java.nio.IntBuffer; - import org.joml.Vector3fc; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; - public class LeafDoubleBSPNode extends BSPNode { private final int quadA; private final int quadB; @@ -16,8 +12,8 @@ public class LeafDoubleBSPNode extends BSPNode { } @Override - public void collectSortedQuads(IntBuffer indexBuffer, Vector3fc cameraPos) { - TranslucentData.writeQuadVertexIndexes(indexBuffer, this.quadA); - TranslucentData.writeQuadVertexIndexes(indexBuffer, this.quadB); + void collectSortedQuads(BSPSortState sortState, Vector3fc cameraPos) { + sortState.writeIndex(this.quadA); + sortState.writeIndex(this.quadB); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafMultiBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafMultiBSPNode.java index e59757a7da..6a1262b727 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafMultiBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafMultiBSPNode.java @@ -1,11 +1,7 @@ package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; -import java.nio.IntBuffer; - import org.joml.Vector3fc; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; - class LeafMultiBSPNode extends BSPNode { private final int[] quads; @@ -14,7 +10,7 @@ class LeafMultiBSPNode extends BSPNode { } @Override - public void collectSortedQuads(IntBuffer indexBuffer, Vector3fc cameraPos) { - TranslucentData.writeQuadVertexIndexes(indexBuffer, this.quads); + void collectSortedQuads(BSPSortState sortState, Vector3fc cameraPos) { + sortState.writeIndexes(this.quads); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafSingleBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafSingleBSPNode.java index 9b6815bcb7..6c328563a0 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafSingleBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafSingleBSPNode.java @@ -1,11 +1,7 @@ package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; -import java.nio.IntBuffer; - import org.joml.Vector3fc; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; - class LeafSingleBSPNode extends BSPNode { private final int quad; @@ -14,7 +10,7 @@ class LeafSingleBSPNode extends BSPNode { } @Override - public void collectSortedQuads(IntBuffer indexBuffer, Vector3fc cameraPos) { - TranslucentData.writeQuadVertexIndexes(indexBuffer, this.quad); + void collectSortedQuads(BSPSortState sortState, Vector3fc cameraPos) { + sortState.writeIndex(this.quad); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/Partition.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/Partition.java new file mode 100644 index 0000000000..b4d38c899d --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/Partition.java @@ -0,0 +1,11 @@ +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; + +import it.unimi.dsi.fastutil.ints.IntArrayList; + +/** + * models a partition of the space into a set of quads that lie inside or on the + * plane with the specified distance. If the distance is -1 this is the "end" + * partition after the last partition plane. + */ +record Partition(float distance, IntArrayList quadsBefore, IntArrayList quadsOn) { +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java index 169fa5ad66..b9b08c8fd8 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java @@ -27,14 +27,18 @@ public void sortOnTrigger(Vector3fc cameraPos) { private void sort(Vector3fc cameraPos) { this.unsetReuseUploadedData(); - this.rootNode.collectSortedQuads( - this.getBuffer().getDirectBuffer().asIntBuffer(), cameraPos); + this.rootNode.collectSortedQuads(getBuffer(), cameraPos); } public static BSPDynamicData fromMesh(BuiltSectionMeshParts translucentMesh, Vector3fc cameraPos, TQuad[] quads, ChunkSectionPos sectionPos, - NativeBuffer buffer) { - var result = BSPNode.buildBSP(quads, sectionPos); + NativeBuffer buffer, TranslucentData oldData) { + BSPNode oldRoot = null; + if (oldData instanceof BSPDynamicData oldBSPData) { + oldRoot = oldBSPData.rootNode; + } + + var result = BSPNode.buildBSP(quads, sectionPos, oldRoot); VertexRange range = TranslucentData.getUnassignedVertexRange(translucentMesh); buffer = PresentTranslucentData.nativeBufferForQuads(buffer, quads); From a25ee3888fdf34e81ce4a27154168eccbc8c0f84 Mon Sep 17 00:00:00 2001 From: douira Date: Tue, 5 Dec 2023 03:05:34 +0100 Subject: [PATCH 163/256] start partition on the y axis --- .../translucent_sorting/bsp_tree/InnerPartitionBSPNode.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java index 5d031985fd..50613c0362 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java @@ -195,7 +195,7 @@ static BSPNode build(BSPWorkspace workspace, IntArrayList indexes, int depth, BS // find any aligned partition, search each axis for (int axisCount = 0; axisCount < 3; axisCount++) { - int axis = (axisCount + depth) % 3; // TODO: depth + 1 to start with Y axis + int axis = (axisCount + depth + 1) % 3; var oppositeDirection = axis + 3; // collect all the geometry's start and end points in this direction From 07ba70921509b73b57e932ad174355ecbf1e5024 Mon Sep 17 00:00:00 2001 From: douira Date: Tue, 5 Dec 2023 03:35:21 +0100 Subject: [PATCH 164/256] reinstane minimum node reuse threshold --- .../translucent_sorting/bsp_tree/InnerPartitionBSPNode.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java index 50613c0362..aa4cd4fa17 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java @@ -43,7 +43,7 @@ * negative numbers." from https://stackoverflow.com/q/43299299 */ abstract class InnerPartitionBSPNode extends BSPNode { - private static int NODE_REUSE_THRESHOLD = 0; + private static int NODE_REUSE_THRESHOLD = 30; final Vector3fc planeNormal; final int axis; From bb6b623a346c969446d0b1b9eae149ff77401f02 Mon Sep 17 00:00:00 2001 From: douira Date: Tue, 5 Dec 2023 04:02:18 +0100 Subject: [PATCH 165/256] fix quad hash code --- .../sodium/client/render/chunk/translucent_sorting/TQuad.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java index 1aef4c7225..4eab6d9f9e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java @@ -17,9 +17,9 @@ int getQuadHash() { int result = 1; result = 31 * result + Arrays.hashCode(this.extents); if (facing == ModelQuadFacing.UNASSIGNED) { - result = 31 * result + this.facing.hashCode(); - } else { result = 31 * result + this.normal.hashCode(); + } else { + result = 31 * result + this.facing.hashCode(); } result = 31 * result + this.center.hashCode(); return result; From 7563bdd50a0063df1dd34cfae679ac1d3f755013 Mon Sep 17 00:00:00 2001 From: douira Date: Tue, 5 Dec 2023 04:14:56 +0100 Subject: [PATCH 166/256] only start preparing node reuse on the second build of a section --- .../bsp_tree/BSPWorkspace.java | 5 ++++- .../bsp_tree/InnerPartitionBSPNode.java | 2 +- .../data/BSPDynamicData.java | 18 ++++++++++++++---- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java index 7971845044..ae5f580b0b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java @@ -20,9 +20,12 @@ class BSPWorkspace { final BSPResult result = new BSPResult(); - BSPWorkspace(TQuad[] quads, ChunkSectionPos sectionPos) { + final boolean prepareNodeReuse; + + BSPWorkspace(TQuad[] quads, ChunkSectionPos sectionPos, boolean prepareNodeReuse) { this.quads = quads; this.sectionPos = sectionPos; + this.prepareNodeReuse = prepareNodeReuse; } // TODO: better bidirectional triggering: integrate bidirectionality in GFNI if diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java index aa4cd4fa17..1fe04c03de 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java @@ -75,7 +75,7 @@ static NodeReuseData prepareNodeReuse(BSPWorkspace workspace, IntArrayList index // TODO: more sophisticated reuse scheduling (make uset configurable, and only // do once the section has been modified at least once already to avoid making // this data on terrain sections that are never touched) - if (depth == 1 && indexes.size() > NODE_REUSE_THRESHOLD) { + if (workspace.prepareNodeReuse && depth == 1 && indexes.size() > NODE_REUSE_THRESHOLD) { // collect the extents of the indexed quads and hash them var quadExtents = new float[indexes.size()][]; int maxIndex = -1; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java index b9b08c8fd8..093a9205d0 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java @@ -11,12 +11,16 @@ import net.minecraft.util.math.ChunkSectionPos; public class BSPDynamicData extends DynamicData { + private static final int NODE_REUSE_MIN_GENERATION = 1; + private final BSPNode rootNode; + private final int generation; private BSPDynamicData(ChunkSectionPos sectionPos, - NativeBuffer buffer, VertexRange range, BSPResult result) { + NativeBuffer buffer, VertexRange range, BSPResult result, int generation) { super(sectionPos, buffer, range, result); this.rootNode = result.getRootNode(); + this.generation = generation; } @Override @@ -34,16 +38,22 @@ public static BSPDynamicData fromMesh(BuiltSectionMeshParts translucentMesh, Vector3fc cameraPos, TQuad[] quads, ChunkSectionPos sectionPos, NativeBuffer buffer, TranslucentData oldData) { BSPNode oldRoot = null; + int generation = 0; + boolean prepareNodeReuse = false; if (oldData instanceof BSPDynamicData oldBSPData) { + generation = oldBSPData.generation + 1; oldRoot = oldBSPData.rootNode; - } - var result = BSPNode.buildBSP(quads, sectionPos, oldRoot); + // only enable partial updates after a certain number of generations + // (times the section has been built) + prepareNodeReuse = generation >= NODE_REUSE_MIN_GENERATION; + } + var result = BSPNode.buildBSP(quads, sectionPos, oldRoot, prepareNodeReuse); VertexRange range = TranslucentData.getUnassignedVertexRange(translucentMesh); buffer = PresentTranslucentData.nativeBufferForQuads(buffer, quads); - var dynamicData = new BSPDynamicData(sectionPos, buffer, range, result); + var dynamicData = new BSPDynamicData(sectionPos, buffer, range, result, generation); dynamicData.sort(cameraPos); // prepare accumulation groups for integration into GFNI triggering From 9cefff3452bd2bb6d3d62de450083e5988b63eb0 Mon Sep 17 00:00:00 2001 From: douira Date: Tue, 5 Dec 2023 04:15:11 +0100 Subject: [PATCH 167/256] note for a rare bug --- .../render/chunk/translucent_sorting/TranslucentSorting.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentSorting.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentSorting.java index e9f9e91bd2..cda3890e18 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentSorting.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentSorting.java @@ -29,6 +29,11 @@ * - determine the right distance for angle/distance triggering. It seems just * the diagonal of a section is too small, angle triggering is broken at close * distances. + * - Bug: adding a slime block onto one of the corners of the monster cube makes + * it invisible. Is this because there's nothing else in this section than just + * that one block? Might have something to do with NONE mode behaving weirdly in + * that situation. Possibly related to index buffer reuse, since it only happens + * after the block has been replaced at least once. * * @author douira */ From 1cd003bffac4168626cc5ad418e93b911ceff0e1 Mon Sep 17 00:00:00 2001 From: douira Date: Tue, 5 Dec 2023 04:15:29 +0100 Subject: [PATCH 168/256] add missing prepare node reuse flag --- .../render/chunk/translucent_sorting/bsp_tree/BSPNode.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java index 0893474721..0a88446cfd 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java @@ -27,13 +27,13 @@ public void collectSortedQuads(NativeBuffer nativeBuffer, Vector3fc cameraPos) { this.collectSortedQuads(new BSPSortState(nativeBuffer), cameraPos); } - public static BSPResult buildBSP(TQuad[] quads, ChunkSectionPos sectionPos, BSPNode oldRoot) { + public static BSPResult buildBSP(TQuad[] quads, ChunkSectionPos sectionPos, BSPNode oldRoot, boolean prepareNodeReuse) { // throw if there's too many quads InnerPartitionBSPNode.validateQuadCount(quads.length); // create a workspace and then the nodes figure out the recursive building. // throws if the BSP can't be built, null if none is necessary - var workspace = new BSPWorkspace(quads, sectionPos); + var workspace = new BSPWorkspace(quads, sectionPos, prepareNodeReuse); // initialize the indexes to all quads int[] initialIndexes = new int[quads.length]; From 1dc97f3fa7f0a74e791ab08c0ab93dc4f73df813 Mon Sep 17 00:00:00 2001 From: douira Date: Wed, 6 Dec 2023 04:46:13 +0100 Subject: [PATCH 169/256] index array compression --- .../bsp_tree/BSPSortState.java | 219 ++++++++++++++++-- .../bsp_tree/InnerBinaryPartitionBSPNode.java | 2 +- .../bsp_tree/InnerMultiPartitionBSPNode.java | 2 +- .../bsp_tree/InnerPartitionBSPNode.java | 4 +- 4 files changed, 207 insertions(+), 20 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java index 9cb55bddc9..af5eda2395 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java @@ -1,7 +1,9 @@ package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; import java.nio.IntBuffer; +import java.lang.Math; +import it.unimi.dsi.fastutil.ints.IntArrayList; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; import me.jellysquid.mods.sodium.client.util.NativeBuffer; @@ -44,22 +46,6 @@ private void checkModificationCounter(int reduceBy) { } } - void writeIndexes(int[] indexes) { - if (this.indexMap != null) { - for (int i = 0; i < indexes.length; i++) { - TranslucentData.writeQuadVertexIndexes(this.indexBuffer, this.indexMap[indexes[i]]); - } - checkModificationCounter(indexes.length); - } else if (this.fixedIndexOffset != NO_FIXED_OFFSET) { - for (int i = 0; i < indexes.length; i++) { - TranslucentData.writeQuadVertexIndexes(this.indexBuffer, this.fixedIndexOffset + indexes[i]); - } - checkModificationCounter(indexes.length); - } else { - TranslucentData.writeQuadVertexIndexes(this.indexBuffer, indexes); - } - } - void writeIndex(int index) { if (this.indexMap != null) { TranslucentData.writeQuadVertexIndexes(this.indexBuffer, this.indexMap[index]); @@ -71,4 +57,205 @@ void writeIndex(int index) { TranslucentData.writeQuadVertexIndexes(this.indexBuffer, index); } } + + private static final int INDEX_COMPRESSION_MIN_LENGTH = 50; + private static final int HEADER_LENGTH = 2; + + private static final int[] WIDTHS = new int[] { 1, 2, 3, 4, 5, 6, 8, 10, 16, 32 }; + + private static final int CONSTANT_DELTA_WIDTH_INDEX = 15; + + /** + * ceilDiv was introduced to the JDK in Java 18 but is not available in Java 17. + */ + private static int ceilDiv(int x, int y) { + return -Math.floorDiv(-x, y); + } + + /** + * Compress a list of quad indexes by applying run length encoding or bit + * packing to their deltas. + * + * Format: 32 bits, elements described as [length in bits: description] + * header at position 0: 0b1[4: width index][10: delta count][17: first index] + * header at position 1: 0b[32: base delta] + * deltas at position 2..n: 0b[width: delta]... + * + * delta bit widths: + * 1x32b, 2x16b, 3x10b, 4x8b, 5x6b, + * 6x5b, 8x4b, 10x3b, 16x2b, 32x1b + */ + static int[] compressIndexes(IntArrayList indexes) { + // bail on short lists + if (indexes.size() < INDEX_COMPRESSION_MIN_LENGTH || indexes.size() > 1 << 10) { + return indexes.toIntArray(); + } + + IntArrayList workingList = new IntArrayList(indexes); + + // sort for better compression, this also ensures that deltas are positive but + // as small as possible. + workingList.sort(null); + + // replace indexes with deltas + int last = workingList.getInt(0); + int minDelta = Integer.MAX_VALUE; + int maxDelta = 0; + for (int i = 1; i < workingList.size(); i++) { + int current = workingList.getInt(i); + int delta = current - last; + workingList.set(i, delta); + last = current; + if (delta < minDelta) { + minDelta = delta; + } + if (delta > maxDelta) { + maxDelta = delta; + } + } + int deltaRangeWidth = Integer.SIZE - Integer.numberOfLeadingZeros(maxDelta - minDelta); + + // stop if the first index is too large + int firstIndex = workingList.getInt(0); + if (firstIndex > 1 << 17) { + return indexes.toIntArray(); + } + + int deltaCount = workingList.size() - 1; + + // special case 0 bit delta + if (deltaRangeWidth == 0) { + // this means there's just a sequential list of indexes with each one +1 + var compressed = new int[HEADER_LENGTH]; + + // signal with special width index + compressed[0] = 1 << 31 | CONSTANT_DELTA_WIDTH_INDEX << 27 | deltaCount << 17 | firstIndex; + compressed[1] = minDelta; + + // System.out.println( + // "Compressed " + indexes.size() + " indexes to 2 ints, compression ratio " + (indexes.size() / 2)); + return compressed; + } + + // stop if the width is too large (and compression would make no sense) + if (deltaRangeWidth > 16) { + return indexes.toIntArray(); + } + + // find the smallest bit width that can represent the deltas + int widthIndex = 0; + while (WIDTHS[widthIndex] < deltaRangeWidth) { + widthIndex++; + } + int width = WIDTHS[widthIndex]; + int countPerInt = WIDTHS[WIDTHS.length - widthIndex - 1]; + + // figure out the size of the compressed index array + int size = HEADER_LENGTH + ceilDiv(deltaCount, countPerInt); + int[] compressed = new int[size]; + + // write the header + compressed[0] = 1 << 31 | widthIndex << 27 | deltaCount << 17 | firstIndex; + compressed[1] = minDelta; + + // write the deltas + int outputIndex = HEADER_LENGTH; + int gatherInt = 0; + int bitPosition = 0; + for (int i = 1; i < workingList.size(); i++) { + int shiftedDelta = workingList.getInt(i) - minDelta; + gatherInt |= shiftedDelta << bitPosition; + bitPosition += width; + if (bitPosition >= Integer.SIZE) { + compressed[outputIndex++] = gatherInt; + gatherInt = 0; + bitPosition = 0; + } + } + + // System.out.println("Compressed " + indexes.size() + " indexes to " + size + " ints, compression ratio " + // + (indexes.size() / size)); + return compressed; + } + + void writeIndexes(int[] indexes) { + boolean useIndexMap = this.indexMap != null; + boolean useFixedIndexOffset = this.fixedIndexOffset != NO_FIXED_OFFSET; + int header1 = indexes[0]; + + if (header1 < 0) { + // read compression header + int widthIndex = (header1 >> 27) & 0b1111; + int currentValue = header1 & 0b11111111111111111; + int valueCount = ((header1 >> 17) & 0b1111111111) + 1; + int baseDelta = indexes[1]; + if (useFixedIndexOffset) { + currentValue += this.fixedIndexOffset; + } + + // handle special case of width index 0, this means there's no delta data + if (widthIndex == CONSTANT_DELTA_WIDTH_INDEX) { + for (int i = 0; i < valueCount; i++) { + int writeValue = currentValue; + if (useIndexMap) { + writeValue = this.indexMap[currentValue]; + } + TranslucentData.writeQuadVertexIndexes(this.indexBuffer, writeValue); + currentValue += baseDelta; + } + + if (useIndexMap || useFixedIndexOffset) { + checkModificationCounter(valueCount); + } + return; + } + + int width = WIDTHS[widthIndex]; + int mask = (1 << width) - 1; + + // write value (optionally map), read deltas, apply base delta and loop + int readIndex = HEADER_LENGTH; + int splitInt = indexes[readIndex++]; + int splitIntBitPosition = 0; + while (valueCount-- > 0) { + int writeValue = currentValue; + if (useIndexMap) { + writeValue = this.indexMap[currentValue]; + } + TranslucentData.writeQuadVertexIndexes(this.indexBuffer, writeValue); + + // read the next delta if there is one + if (valueCount == 0) { + break; + } + + int delta = (splitInt >> splitIntBitPosition) & mask; + splitIntBitPosition += width; + if (splitIntBitPosition >= Integer.SIZE && valueCount > 1) { + splitInt = indexes[readIndex++]; + splitIntBitPosition = 0; + } + + // update the current value with the delta and base delta + currentValue += baseDelta + delta; + } + } else { + // uncompressed indexes + if (useIndexMap) { + for (int i = 0; i < indexes.length; i++) { + TranslucentData.writeQuadVertexIndexes(this.indexBuffer, this.indexMap[indexes[i]]); + } + } else if (useFixedIndexOffset) { + for (int i = 0; i < indexes.length; i++) { + TranslucentData.writeQuadVertexIndexes(this.indexBuffer, this.fixedIndexOffset + indexes[i]); + } + } else { + TranslucentData.writeQuadVertexIndexes(this.indexBuffer, indexes); + } + } + + if (useIndexMap || useFixedIndexOffset) { + checkModificationCounter(indexes.length); + } + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java index cec9832844..ab8d882518 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java @@ -75,7 +75,7 @@ static BSPNode build(BSPWorkspace workspace, IntArrayList indexes, int depth, BS if (outside != null) { outsideNode = BSPNode.build(workspace, outside.quadsBefore(), depth, oldOutsideNode); } - var onPlane = inside.quadsOn() == null ? null : inside.quadsOn().toIntArray(); + var onPlane = inside.quadsOn() == null ? null : BSPSortState.compressIndexes(inside.quadsOn()); return new InnerBinaryPartitionBSPNode( prepareNodeReuse(workspace, indexes, depth), diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerMultiPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerMultiPartitionBSPNode.java index d915c21c83..24ade6bbce 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerMultiPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerMultiPartitionBSPNode.java @@ -131,7 +131,7 @@ static BSPNode build(BSPWorkspace workspace, IntArrayList indexes, int depth, BS partitionNodes[i] = BSPNode.build(workspace, partition.quadsBefore(), depth, oldChild); } if (partition.quadsOn() != null) { - onPlaneQuads[i] = partition.quadsOn().toIntArray(); + onPlaneQuads[i] = BSPSortState.compressIndexes(partition.quadsOn()); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java index 1fe04c03de..207adbb3e7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java @@ -86,7 +86,7 @@ static NodeReuseData prepareNodeReuse(BSPWorkspace workspace, IntArrayList index quadExtents[i] = extents; maxIndex = Math.max(maxIndex, index); } - return new NodeReuseData(quadExtents, indexes.toIntArray(), maxIndex); + return new NodeReuseData(quadExtents, BSPSortState.compressIndexes(indexes), maxIndex); } return null; } @@ -363,7 +363,7 @@ static BSPNode build(BSPWorkspace workspace, IntArrayList indexes, int depth, BS var quadY = workspace.quads[b]; return Float.compare(quadX.getAlignedSurfaceArea(), quadY.getAlignedSurfaceArea()); }); - return new LeafMultiBSPNode(indexes.toIntArray()); + return new LeafMultiBSPNode(BSPSortState.compressIndexes(indexes)); } if (--testsRemaining == 0) { From c18520a899beb02f1acb9f2d15b7dd11b79686da Mon Sep 17 00:00:00 2001 From: douira Date: Thu, 7 Dec 2023 22:12:55 +0100 Subject: [PATCH 170/256] fix compression of indexes in node reuse --- .../TranslucentSorting.java | 3 + .../bsp_tree/BSPSortState.java | 137 +++++++++++------- .../bsp_tree/InnerPartitionBSPNode.java | 64 +++++--- 3 files changed, 130 insertions(+), 74 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentSorting.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentSorting.java index cda3890e18..737a8adb73 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentSorting.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentSorting.java @@ -34,6 +34,9 @@ * that one block? Might have something to do with NONE mode behaving weirdly in * that situation. Possibly related to index buffer reuse, since it only happens * after the block has been replaced at least once. + * - Incompatible with rendering anything through Indium because it doesn't run + * the translucent geometry collector properly. It doesn't run Sodium's + * BlockRenderer which is required for lines 166-167 of BlockRenderer to work. * * @author douira */ diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java index af5eda2395..a8d85084d9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java @@ -4,13 +4,14 @@ import java.lang.Math; import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntConsumer; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; import me.jellysquid.mods.sodium.client.util.NativeBuffer; class BSPSortState { static final int NO_FIXED_OFFSET = Integer.MIN_VALUE; - private final IntBuffer indexBuffer; + private IntBuffer indexBuffer; private int indexModificationsRemaining; private int[] indexMap; @@ -133,7 +134,8 @@ static int[] compressIndexes(IntArrayList indexes) { compressed[1] = minDelta; // System.out.println( - // "Compressed " + indexes.size() + " indexes to 2 ints, compression ratio " + (indexes.size() / 2)); + // "Compressed " + indexes.size() + " indexes to 2 ints, compression ratio " + + // (indexes.size() / 2)); return compressed; } @@ -173,71 +175,94 @@ static int[] compressIndexes(IntArrayList indexes) { } } - // System.out.println("Compressed " + indexes.size() + " indexes to " + size + " ints, compression ratio " - // + (indexes.size() / size)); + // System.out.println("Compressed " + indexes.size() + " indexes to " + size + " + // ints, compression ratio " + // + (indexes.size() / size)); return compressed; } - void writeIndexes(int[] indexes) { - boolean useIndexMap = this.indexMap != null; - boolean useFixedIndexOffset = this.fixedIndexOffset != NO_FIXED_OFFSET; - int header1 = indexes[0]; + static int decompressOrRead(int[] indexes, IntConsumer consumer) { + if (isCompressed(indexes)) { + return decompress(indexes, consumer); + } else { + for (int i = 0; i < indexes.length; i++) { + consumer.accept(indexes[i]); + } + return indexes.length; + } + } - if (header1 < 0) { - // read compression header - int widthIndex = (header1 >> 27) & 0b1111; - int currentValue = header1 & 0b11111111111111111; - int valueCount = ((header1 >> 17) & 0b1111111111) + 1; - int baseDelta = indexes[1]; - if (useFixedIndexOffset) { - currentValue += this.fixedIndexOffset; + static int decompress(int[] indexes, IntConsumer consumer) { + return decompressWithOffset(indexes, 0, consumer); + } + + static int decompressWithOffset(int[] indexes, int fixedIndexOffset, IntConsumer consumer) { + // read compression header + int header1 = indexes[0]; + int widthIndex = (header1 >> 27) & 0b1111; + int currentValue = header1 & 0b11111111111111111 + fixedIndexOffset; + int valueCount = ((header1 >> 17) & 0b1111111111) + 1; + int baseDelta = indexes[1]; + + // handle special case of width index 0, this means there's no delta data + if (widthIndex == CONSTANT_DELTA_WIDTH_INDEX) { + for (int i = 0; i < valueCount; i++) { + consumer.accept(currentValue); + currentValue += baseDelta; } - // handle special case of width index 0, this means there's no delta data - if (widthIndex == CONSTANT_DELTA_WIDTH_INDEX) { - for (int i = 0; i < valueCount; i++) { - int writeValue = currentValue; - if (useIndexMap) { - writeValue = this.indexMap[currentValue]; - } - TranslucentData.writeQuadVertexIndexes(this.indexBuffer, writeValue); - currentValue += baseDelta; - } + return valueCount; + } - if (useIndexMap || useFixedIndexOffset) { - checkModificationCounter(valueCount); - } - return; + int width = WIDTHS[widthIndex]; + int mask = (1 << width) - 1; + + // write value (optionally map), read deltas, apply base delta and loop + int readIndex = HEADER_LENGTH; + int splitInt = indexes[readIndex++]; + int splitIntBitPosition = 0; + while (valueCount-- > 0) { + consumer.accept(currentValue); + + // read the next delta if there is one + if (valueCount == 0) { + break; } - int width = WIDTHS[widthIndex]; - int mask = (1 << width) - 1; - - // write value (optionally map), read deltas, apply base delta and loop - int readIndex = HEADER_LENGTH; - int splitInt = indexes[readIndex++]; - int splitIntBitPosition = 0; - while (valueCount-- > 0) { - int writeValue = currentValue; - if (useIndexMap) { - writeValue = this.indexMap[currentValue]; - } - TranslucentData.writeQuadVertexIndexes(this.indexBuffer, writeValue); + int delta = (splitInt >> splitIntBitPosition) & mask; + splitIntBitPosition += width; + if (splitIntBitPosition >= Integer.SIZE && valueCount > 1) { + splitInt = indexes[readIndex++]; + splitIntBitPosition = 0; + } - // read the next delta if there is one - if (valueCount == 0) { - break; - } + // update the current value with the delta and base delta + currentValue += baseDelta + delta; + } - int delta = (splitInt >> splitIntBitPosition) & mask; - splitIntBitPosition += width; - if (splitIntBitPosition >= Integer.SIZE && valueCount > 1) { - splitInt = indexes[readIndex++]; - splitIntBitPosition = 0; - } + return valueCount; + } + + static boolean isCompressed(int[] indexes) { + return indexes[0] < 0; + } - // update the current value with the delta and base delta - currentValue += baseDelta + delta; + private IntConsumer indexConsumer = (int index) -> TranslucentData.writeQuadVertexIndexes( + this.indexBuffer, index); + + private IntConsumer indexMapConsumer = (int index) -> TranslucentData.writeQuadVertexIndexes( + this.indexBuffer, this.indexMap[index]); + + void writeIndexes(int[] indexes) { + boolean useIndexMap = this.indexMap != null; + boolean useFixedIndexOffset = this.fixedIndexOffset != NO_FIXED_OFFSET; + + if (isCompressed(indexes)) { + var consumer = useIndexMap ? this.indexMapConsumer : this.indexConsumer; + if (useFixedIndexOffset) { + decompressWithOffset(indexes, this.fixedIndexOffset, consumer); + } else { + decompress(indexes, consumer); } } else { // uncompressed indexes @@ -254,6 +279,8 @@ void writeIndexes(int[] indexes) { } } + // check if the index modification session is over. this is very important or + // there's an exception if (useIndexMap || useFixedIndexOffset) { checkModificationCounter(indexes.length); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java index 207adbb3e7..926c069608 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java @@ -5,6 +5,7 @@ import org.joml.Vector3fc; import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntConsumer; import it.unimi.dsi.fastutil.longs.LongArrayList; import it.unimi.dsi.fastutil.objects.ReferenceArrayList; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; @@ -86,11 +87,46 @@ static NodeReuseData prepareNodeReuse(BSPWorkspace workspace, IntArrayList index quadExtents[i] = extents; maxIndex = Math.max(maxIndex, index); } - return new NodeReuseData(quadExtents, BSPSortState.compressIndexes(indexes), maxIndex); + + // TODO: this could use compression, but then attemptNodeReuse also needs to be + // able to decompress it + // return new NodeReuseData(quadExtents, BSPSortState.compressIndexes(indexes), maxIndex); + return new NodeReuseData(quadExtents, indexes.toIntArray(), maxIndex); } return null; } + private static class IndexRemapper implements IntConsumer { + private final int[] indexMap; + private final IntArrayList newIndexes; + private int index = 0; + private int lastOffset = 0; + + private static final int OFFSET_CHANGED = Integer.MIN_VALUE; + + IndexRemapper(int length, IntArrayList newIndexes) { + this.indexMap = new int[length]; + this.newIndexes = newIndexes; + } + + @Override + public void accept(int oldIndex) { + var newIndex = newIndexes.getInt(index); + indexMap[oldIndex] = newIndex; + var newOffset = newIndex - oldIndex; + if (index == 0) { + lastOffset = newOffset; + } else if (lastOffset != newOffset) { + lastOffset = OFFSET_CHANGED; + } + index++; + } + + boolean hasFixedOffset() { + return lastOffset != OFFSET_CHANGED; + } + } + static InnerPartitionBSPNode attemptNodeReuse(BSPWorkspace workspace, IntArrayList newIndexes, int depth, InnerPartitionBSPNode oldNode) { if (oldNode == null) { @@ -118,28 +154,18 @@ static InnerPartitionBSPNode attemptNodeReuse(BSPWorkspace workspace, IntArrayLi // reuse old node and either apply a fixed offset or calculate an index map to // map from old to new indices - var oldIndexes = reuseData.indexes; - var indexMap = new int[reuseData.maxIndex + 1]; - final int OFFSET_CHANGED = Integer.MIN_VALUE; - int lastOffset = 0; - for (int i = 0; i < oldIndexes.length; i++) { - var oldIndex = oldIndexes[i]; - var newIndex = newIndexes.getInt(i); - indexMap[oldIndex] = newIndex; - var newOffset = newIndex - oldIndex; - if (i == 0) { - lastOffset = newOffset; - } else if (lastOffset != newOffset) { - lastOffset = OFFSET_CHANGED; - } - } + // TODO: placing and removing a block from the death cube of slime and honey is + // still broken. Did decompression broke when the compression was properly added + // on reuse data? + var remapper = new IndexRemapper(reuseData.maxIndex + 1, newIndexes); + BSPSortState.decompressOrRead(reuseData.indexes, remapper); // use a fixed offset if possible (if all old indices differ from the new ones // by the same amount) - if (lastOffset != OFFSET_CHANGED) { - oldNode.fixedIndexOffset = lastOffset; + if (remapper.hasFixedOffset()) { + oldNode.fixedIndexOffset = remapper.lastOffset; } else { - oldNode.indexMap = indexMap; + oldNode.indexMap = remapper.indexMap; } return oldNode; From f1cff7629784af8c27081910f60bc25d207bdd6e Mon Sep 17 00:00:00 2001 From: JellySquid <1363084+jellysquid3@users.noreply.github.com> Date: Fri, 8 Dec 2023 16:00:04 -0600 Subject: [PATCH 171/256] Update fabric.mod.json --- src/main/resources/fabric.mod.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 32eafbab16..cdda9bd672 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -86,7 +86,7 @@ "farsight": "<1.20.1-4.0", "fluidvoidfading": "<1.1.2", "iceberg": "<1.1.14", - "iris": "<1.6.7", + "iris": "*", "immersive_portals": "<=3.2.5", "indium": "<1.0.24", "notenoughcrashes": "<4.4.6", From 1a447b8155f1dc2faf2f3d3389da2be6cd307b26 Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 11 Dec 2023 00:04:06 +0100 Subject: [PATCH 172/256] fix translucent rendering in previously empty sections --- .../sodium/client/render/chunk/RenderSectionManager.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index a5bfdf20ba..bedfe8f467 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -31,6 +31,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.CameraMovement; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TranslucentSorting; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.NoData; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TopoSortDynamicData; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkMeshFormats; @@ -422,9 +423,11 @@ private void submitSectionTasks(ChunkJobCollector collector, ChunkUpdateType typ } else { // if the section is empty, doesn't exist or no sort task needs to be created // for non-dynamic data, submit this null-task to set the built flag on the - // render section + // render section. + // It's important to use a NoData instead of null translucency data here in + // order for it to clear the old data from the translucency sorting system var result = ChunkJobResult.successfully(new ChunkBuildOutput( - section, frame, null, + section, frame, new NoData(section.getPosition()), BuiltSectionInfo.EMPTY, Collections.emptyMap())); this.buildResults.add(result); From d2c3167add3f6637427dd1acce6576d57c98354c Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 11 Dec 2023 00:08:00 +0100 Subject: [PATCH 173/256] use euclidean distance for vertex sorting, fixes regression with entities --- .../mods/sodium/client/util/sorting/VertexSorters.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/VertexSorters.java b/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/VertexSorters.java index 2f96189b1d..1be7fca4a3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/VertexSorters.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/VertexSorters.java @@ -43,10 +43,8 @@ private SortByDistance(Vector3f origin) { @Override protected float getKey(Vector3f position) { - float distance = Math.abs(position.x - this.origin.x); - distance += Math.abs(position.y - this.origin.y); - distance += Math.abs(position.z - this.origin.z); - return distance; + // requires euclidean distance, manhattan distance doesn't work + return this.origin.distanceSquared(position); } } From 81e65139629e1b035a1731f61ea0a5014f51987f Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 11 Dec 2023 00:37:50 +0100 Subject: [PATCH 174/256] fix trigger planes of reused nodes missing from the new bsp workspace result --- .../bsp_tree/InnerBinaryPartitionBSPNode.java | 5 +++++ .../bsp_tree/InnerMultiPartitionBSPNode.java | 7 +++++++ .../bsp_tree/InnerPartitionBSPNode.java | 5 +++++ 3 files changed, 17 insertions(+) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java index ab8d882518..d2d82ee991 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java @@ -21,6 +21,11 @@ class InnerBinaryPartitionBSPNode extends InnerPartitionBSPNode { this.onPlaneQuads = onPlaneQuads; } + @Override + void addPartitionPlanes(BSPWorkspace workspace) { + workspace.addAlignedPartitionPlane(this.axis, this.planeDistance); + } + private void collectInside(BSPSortState sortState, Vector3fc cameraPos) { if (this.inside != null) { this.inside.collectSortedQuads(sortState, cameraPos); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerMultiPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerMultiPartitionBSPNode.java index 24ade6bbce..e9ffefc410 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerMultiPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerMultiPartitionBSPNode.java @@ -24,6 +24,13 @@ class InnerMultiPartitionBSPNode extends InnerPartitionBSPNode { this.onPlaneQuads = onPlaneQuads; } + @Override + void addPartitionPlanes(BSPWorkspace workspace) { + for (int i = 0; i < this.planeDistances.length; i++) { + workspace.addAlignedPartitionPlane(this.axis, this.planeDistances[i]); + } + } + private void collectPlaneQuads(BSPSortState sortState, int planeIndex) { if (this.onPlaneQuads[planeIndex] != null) { sortState.writeIndexes(this.onPlaneQuads[planeIndex]); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java index 926c069608..be7ad552ff 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java @@ -70,6 +70,8 @@ record NodeReuseData(float[][] quadExtents, int[] indexes, int maxIndex) { this.reuseData = reuseData; } + abstract void addPartitionPlanes(BSPWorkspace workspace); + static NodeReuseData prepareNodeReuse(BSPWorkspace workspace, IntArrayList indexes, int depth) { // if node reuse is enabled, only enable on the first level of children (not the // root node and not anything deeper than its children) @@ -168,6 +170,9 @@ static InnerPartitionBSPNode attemptNodeReuse(BSPWorkspace workspace, IntArrayLi oldNode.indexMap = remapper.indexMap; } + // import the triggering data from the old node to ensure it still triggers at the right time + oldNode.addPartitionPlanes(workspace); + return oldNode; } From f446ea15e911a870218175c4b353bcb17a910906 Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 11 Dec 2023 00:37:58 +0100 Subject: [PATCH 175/256] formatting --- .../translucent_sorting/bsp_tree/InnerPartitionBSPNode.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java index be7ad552ff..97c3511af5 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java @@ -92,7 +92,8 @@ static NodeReuseData prepareNodeReuse(BSPWorkspace workspace, IntArrayList index // TODO: this could use compression, but then attemptNodeReuse also needs to be // able to decompress it - // return new NodeReuseData(quadExtents, BSPSortState.compressIndexes(indexes), maxIndex); + // return new NodeReuseData(quadExtents, BSPSortState.compressIndexes(indexes), + // maxIndex); return new NodeReuseData(quadExtents, indexes.toIntArray(), maxIndex); } return null; @@ -170,7 +171,8 @@ static InnerPartitionBSPNode attemptNodeReuse(BSPWorkspace workspace, IntArrayLi oldNode.indexMap = remapper.indexMap; } - // import the triggering data from the old node to ensure it still triggers at the right time + // import the triggering data from the old node to ensure it still triggers at + // the right time oldNode.addPartitionPlanes(workspace); return oldNode; From 8268ef6ab7fab4a2d3f43dffbd780904f45e502a Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 11 Dec 2023 03:20:11 +0100 Subject: [PATCH 176/256] fix various small compression related bugs --- .../bsp_tree/BSPSortState.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java index a8d85084d9..1d2ce9e5b7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java @@ -161,6 +161,7 @@ static int[] compressIndexes(IntArrayList indexes) { compressed[1] = minDelta; // write the deltas + final int positionLimit = Integer.SIZE - width; int outputIndex = HEADER_LENGTH; int gatherInt = 0; int bitPosition = 0; @@ -168,16 +169,20 @@ static int[] compressIndexes(IntArrayList indexes) { int shiftedDelta = workingList.getInt(i) - minDelta; gatherInt |= shiftedDelta << bitPosition; bitPosition += width; - if (bitPosition >= Integer.SIZE) { + if (bitPosition > positionLimit) { compressed[outputIndex++] = gatherInt; gatherInt = 0; bitPosition = 0; } } - // System.out.println("Compressed " + indexes.size() + " indexes to " + size + " - // ints, compression ratio " - // + (indexes.size() / size)); + // flush the last int if it hasn't been written yet + if (bitPosition > 0) { + compressed[outputIndex++] = gatherInt; + } + + System.out.println("Compressed " + indexes.size() + " indexes to " + size + " ints, compression ratio " + + (indexes.size() / size)); return compressed; } @@ -218,6 +223,7 @@ static int decompressWithOffset(int[] indexes, int fixedIndexOffset, IntConsumer int mask = (1 << width) - 1; // write value (optionally map), read deltas, apply base delta and loop + final int positionLimit = Integer.SIZE - width; int readIndex = HEADER_LENGTH; int splitInt = indexes[readIndex++]; int splitIntBitPosition = 0; @@ -231,7 +237,7 @@ static int decompressWithOffset(int[] indexes, int fixedIndexOffset, IntConsumer int delta = (splitInt >> splitIntBitPosition) & mask; splitIntBitPosition += width; - if (splitIntBitPosition >= Integer.SIZE && valueCount > 1) { + if (splitIntBitPosition > positionLimit && valueCount > 1) { splitInt = indexes[readIndex++]; splitIntBitPosition = 0; } From 1409949af5f1bcad53e3970a02cd8d630edda73d Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 11 Dec 2023 03:21:26 +0100 Subject: [PATCH 177/256] remove debug logging --- .../chunk/translucent_sorting/bsp_tree/BSPSortState.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java index 1d2ce9e5b7..f6888f5600 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java @@ -181,8 +181,8 @@ static int[] compressIndexes(IntArrayList indexes) { compressed[outputIndex++] = gatherInt; } - System.out.println("Compressed " + indexes.size() + " indexes to " + size + " ints, compression ratio " - + (indexes.size() / size)); + // System.out.println("Compressed " + indexes.size() + " indexes to " + size + " ints, compression ratio " + // + (indexes.size() / size)); return compressed; } From 8f244a1f62df0a03007aeab6e5955b4552d18edd Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 11 Dec 2023 03:24:03 +0100 Subject: [PATCH 178/256] enable compression on reuse index data --- .../translucent_sorting/bsp_tree/InnerPartitionBSPNode.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java index 97c3511af5..3a556087dd 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java @@ -92,9 +92,8 @@ static NodeReuseData prepareNodeReuse(BSPWorkspace workspace, IntArrayList index // TODO: this could use compression, but then attemptNodeReuse also needs to be // able to decompress it - // return new NodeReuseData(quadExtents, BSPSortState.compressIndexes(indexes), - // maxIndex); - return new NodeReuseData(quadExtents, indexes.toIntArray(), maxIndex); + return new NodeReuseData(quadExtents, BSPSortState.compressIndexes(indexes), + maxIndex); } return null; } From 3bfe91d448f54b0f273732c0c0ba4bc88ca04b87 Mon Sep 17 00:00:00 2001 From: douira Date: Tue, 12 Dec 2023 04:02:25 +0100 Subject: [PATCH 179/256] fix more issues with compression and node reuse. --- .../bsp_tree/BSPSortState.java | 34 ++++++++++------- .../bsp_tree/InnerPartitionBSPNode.java | 37 ++++++++++--------- 2 files changed, 41 insertions(+), 30 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java index f6888f5600..0bbf210e84 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java @@ -28,14 +28,14 @@ void startNode(InnerPartitionBSPNode node) { } this.indexMap = node.indexMap; - this.indexModificationsRemaining = node.reuseData.indexes().length; + this.indexModificationsRemaining = node.reuseData.indexCount(); } else if (node.fixedIndexOffset != NO_FIXED_OFFSET) { if (this.indexMap != null || this.fixedIndexOffset != NO_FIXED_OFFSET) { throw new IllegalStateException("Index modification already in progress"); } this.fixedIndexOffset = node.fixedIndexOffset; - this.indexModificationsRemaining = node.reuseData.indexes().length; + this.indexModificationsRemaining = node.reuseData.indexCount(); } } @@ -73,6 +73,10 @@ private static int ceilDiv(int x, int y) { return -Math.floorDiv(-x, y); } + static int[] compressIndexes(IntArrayList indexes) { + return compressIndexes(indexes, true); + } + /** * Compress a list of quad indexes by applying run length encoding or bit * packing to their deltas. @@ -86,7 +90,7 @@ private static int ceilDiv(int x, int y) { * 1x32b, 2x16b, 3x10b, 4x8b, 5x6b, * 6x5b, 8x4b, 10x3b, 16x2b, 32x1b */ - static int[] compressIndexes(IntArrayList indexes) { + static int[] compressIndexes(IntArrayList indexes, boolean doSort) { // bail on short lists if (indexes.size() < INDEX_COMPRESSION_MIN_LENGTH || indexes.size() > 1 << 10) { return indexes.toIntArray(); @@ -96,7 +100,9 @@ static int[] compressIndexes(IntArrayList indexes) { // sort for better compression, this also ensures that deltas are positive but // as small as possible. - workingList.sort(null); + if (doSort) { + workingList.sort(null); + } // replace indexes with deltas int last = workingList.getInt(0); @@ -134,8 +140,8 @@ static int[] compressIndexes(IntArrayList indexes) { compressed[1] = minDelta; // System.out.println( - // "Compressed " + indexes.size() + " indexes to 2 ints, compression ratio " + - // (indexes.size() / 2)); + // "Densely compressed " + indexes.size() + " indexes to 2 ints, compression ratio " + + // (indexes.size() / 2)); return compressed; } @@ -197,11 +203,11 @@ static int decompressOrRead(int[] indexes, IntConsumer consumer) { } } - static int decompress(int[] indexes, IntConsumer consumer) { + private static int decompress(int[] indexes, IntConsumer consumer) { return decompressWithOffset(indexes, 0, consumer); } - static int decompressWithOffset(int[] indexes, int fixedIndexOffset, IntConsumer consumer) { + private static int decompressWithOffset(int[] indexes, int fixedIndexOffset, IntConsumer consumer) { // read compression header int header1 = indexes[0]; int widthIndex = (header1 >> 27) & 0b1111; @@ -227,6 +233,7 @@ static int decompressWithOffset(int[] indexes, int fixedIndexOffset, IntConsumer int readIndex = HEADER_LENGTH; int splitInt = indexes[readIndex++]; int splitIntBitPosition = 0; + int totalValueCount = valueCount; while (valueCount-- > 0) { consumer.accept(currentValue); @@ -246,7 +253,7 @@ static int decompressWithOffset(int[] indexes, int fixedIndexOffset, IntConsumer currentValue += baseDelta + delta; } - return valueCount; + return totalValueCount; } static boolean isCompressed(int[] indexes) { @@ -263,12 +270,12 @@ void writeIndexes(int[] indexes) { boolean useIndexMap = this.indexMap != null; boolean useFixedIndexOffset = this.fixedIndexOffset != NO_FIXED_OFFSET; + int valueCount; if (isCompressed(indexes)) { - var consumer = useIndexMap ? this.indexMapConsumer : this.indexConsumer; if (useFixedIndexOffset) { - decompressWithOffset(indexes, this.fixedIndexOffset, consumer); + valueCount = decompressWithOffset(indexes, this.fixedIndexOffset, this.indexConsumer); } else { - decompress(indexes, consumer); + valueCount = decompress(indexes, useIndexMap ? this.indexMapConsumer : this.indexConsumer); } } else { // uncompressed indexes @@ -283,12 +290,13 @@ void writeIndexes(int[] indexes) { } else { TranslucentData.writeQuadVertexIndexes(this.indexBuffer, indexes); } + valueCount = indexes.length; } // check if the index modification session is over. this is very important or // there's an exception if (useIndexMap || useFixedIndexOffset) { - checkModificationCounter(indexes.length); + checkModificationCounter(valueCount); } } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java index 3a556087dd..4947af9bf7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java @@ -60,8 +60,11 @@ abstract class InnerPartitionBSPNode extends BSPNode { * It only stores the set of indexes that this node was constructed from and * their extents since the BSP construction only cares about the "opaque" quad * geometry and not the normal or facing. + * + * Since the indexes might be compressed, the count needs to be stored + * separately from before compression. */ - record NodeReuseData(float[][] quadExtents, int[] indexes, int maxIndex) { + record NodeReuseData(float[][] quadExtents, int[] indexes, int indexCount, int maxIndex) { } InnerPartitionBSPNode(NodeReuseData reuseData, int axis) { @@ -90,10 +93,13 @@ static NodeReuseData prepareNodeReuse(BSPWorkspace workspace, IntArrayList index maxIndex = Math.max(maxIndex, index); } - // TODO: this could use compression, but then attemptNodeReuse also needs to be - // able to decompress it - return new NodeReuseData(quadExtents, BSPSortState.compressIndexes(indexes), - maxIndex); + // compress indexes but without sorting them, as the order needs to be the same + // for the extents comparison loop to work + return new NodeReuseData( + quadExtents, + BSPSortState.compressIndexes(indexes, false), + indexes.size(), + maxIndex); } return null; } @@ -102,7 +108,7 @@ private static class IndexRemapper implements IntConsumer { private final int[] indexMap; private final IntArrayList newIndexes; private int index = 0; - private int lastOffset = 0; + private int firstOffset = 0; private static final int OFFSET_CHANGED = Integer.MIN_VALUE; @@ -113,19 +119,19 @@ private static class IndexRemapper implements IntConsumer { @Override public void accept(int oldIndex) { - var newIndex = newIndexes.getInt(index); + var newIndex = newIndexes.getInt(this.index); indexMap[oldIndex] = newIndex; var newOffset = newIndex - oldIndex; - if (index == 0) { - lastOffset = newOffset; - } else if (lastOffset != newOffset) { - lastOffset = OFFSET_CHANGED; + if (this.index == 0) { + this.firstOffset = newOffset; + } else if (this.firstOffset != newOffset) { + this.firstOffset = OFFSET_CHANGED; } - index++; + this.index++; } boolean hasFixedOffset() { - return lastOffset != OFFSET_CHANGED; + return this.firstOffset != OFFSET_CHANGED; } } @@ -156,16 +162,13 @@ static InnerPartitionBSPNode attemptNodeReuse(BSPWorkspace workspace, IntArrayLi // reuse old node and either apply a fixed offset or calculate an index map to // map from old to new indices - // TODO: placing and removing a block from the death cube of slime and honey is - // still broken. Did decompression broke when the compression was properly added - // on reuse data? var remapper = new IndexRemapper(reuseData.maxIndex + 1, newIndexes); BSPSortState.decompressOrRead(reuseData.indexes, remapper); // use a fixed offset if possible (if all old indices differ from the new ones // by the same amount) if (remapper.hasFixedOffset()) { - oldNode.fixedIndexOffset = remapper.lastOffset; + oldNode.fixedIndexOffset = remapper.firstOffset; } else { oldNode.indexMap = remapper.indexMap; } From cccb206bec116d2b2da2e3f6c0f36fe9009ba7f4 Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 15 Dec 2023 03:18:50 +0100 Subject: [PATCH 180/256] notes on possible optimization to direct sorting --- .../translucent_sorting/data/TopoSortDynamicData.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java index 13874d9d38..ac6cd80f13 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java @@ -179,6 +179,13 @@ private void sort(Vector3fc cameraPos, boolean isAngleTrigger, boolean initial) private static ThreadLocal distanceSortKeys = new ThreadLocal<>(); + // TODO: encode the quad key into the lower half of a long and the distance into + // the upper half. since it's all positive distances, it should be able to just + // sort the longs by value using Arrays.sort (or fastutil's sort) which is very + // fast. In order to re-use the sort order the sorted array would need to be + // iterated, each quad index extracted and then the distance computed and + // written back into the upper part of the long. This uses more memory to keep + // around the sort result, but requires less repeated iteration of the data. private static int[] distanceSortDirect(int[] indexes, IntBuffer indexBuffer, TQuad[] quads, Vector3fc cameraPos) { if (indexes == null) { From 90c3632c9d0d3ba9ee3d21417d46a103cfcd0b0a Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 15 Dec 2023 03:19:22 +0100 Subject: [PATCH 181/256] also add the child nodes partition distances to the workspace for triggering on node reuse --- .../bsp_tree/InnerBinaryPartitionBSPNode.java | 8 ++++++++ .../bsp_tree/InnerMultiPartitionBSPNode.java | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java index d2d82ee991..51ca2a59a2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java @@ -24,6 +24,14 @@ class InnerBinaryPartitionBSPNode extends InnerPartitionBSPNode { @Override void addPartitionPlanes(BSPWorkspace workspace) { workspace.addAlignedPartitionPlane(this.axis, this.planeDistance); + + // also add the planes of the children + if (this.inside instanceof InnerPartitionBSPNode inside) { + inside.addPartitionPlanes(workspace); + } + if (this.outside instanceof InnerPartitionBSPNode outside) { + outside.addPartitionPlanes(workspace); + } } private void collectInside(BSPSortState sortState, Vector3fc cameraPos) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerMultiPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerMultiPartitionBSPNode.java index e9ffefc410..92c5e0d378 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerMultiPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerMultiPartitionBSPNode.java @@ -29,6 +29,13 @@ void addPartitionPlanes(BSPWorkspace workspace) { for (int i = 0; i < this.planeDistances.length; i++) { workspace.addAlignedPartitionPlane(this.axis, this.planeDistances[i]); } + + // recurse on children to also add their planes + for (var partition : this.partitions) { + if (partition instanceof InnerPartitionBSPNode inner) { + inner.addPartitionPlanes(workspace); + } + } } private void collectPlaneQuads(BSPSortState sortState, int planeIndex) { From 60e121646797698cb108d3c5b2812c772dff8453 Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 16 Dec 2023 03:12:53 +0100 Subject: [PATCH 182/256] note that coplanar quad detection doesn't work --- .../render/chunk/translucent_sorting/bsp_tree/BSPNode.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java index 0a88446cfd..36c1ec25ca 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java @@ -18,6 +18,10 @@ * - Doing a convex box test doesn't seem to bring a performance boost, even if * it does trigger sometimes with man-made structures. The multi partition node * probably does most of the work already. + * - Checking if the given quads are all coplanar doesn't recoup the cost of + * iterating through all the quads. It also doesn't significantly reduce the + * number of triggering planes (which would have a performance and memory usage + * benefit). */ public abstract class BSPNode { @@ -27,7 +31,8 @@ public void collectSortedQuads(NativeBuffer nativeBuffer, Vector3fc cameraPos) { this.collectSortedQuads(new BSPSortState(nativeBuffer), cameraPos); } - public static BSPResult buildBSP(TQuad[] quads, ChunkSectionPos sectionPos, BSPNode oldRoot, boolean prepareNodeReuse) { + public static BSPResult buildBSP(TQuad[] quads, ChunkSectionPos sectionPos, BSPNode oldRoot, + boolean prepareNodeReuse) { // throw if there's too many quads InnerPartitionBSPNode.validateQuadCount(quads.length); From c5ff99a8aa156a41172e2ea0e900439791a45d23 Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 16 Dec 2023 15:24:36 +0100 Subject: [PATCH 183/256] note on why there is compression min length --- .../bsp_tree/BSPSortState.java | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java index 0bbf210e84..4d5612e874 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java @@ -59,11 +59,17 @@ void writeIndex(int index) { } } - private static final int INDEX_COMPRESSION_MIN_LENGTH = 50; - private static final int HEADER_LENGTH = 2; + /** + * The minimum size of an index array that will be compressed. This value is + * non-zero to avoid wasting work on compressing arrays that won't benefit from + * it and the overhead in setting up the compression. Empirically, the + * compression ratio is only high for the very largest arrays and largely + * useless for smaller ones. + */ + private static final int INDEX_COMPRESSION_MIN_LENGTH = 32; + private static final int HEADER_LENGTH = 2; private static final int[] WIDTHS = new int[] { 1, 2, 3, 4, 5, 6, 8, 10, 16, 32 }; - private static final int CONSTANT_DELTA_WIDTH_INDEX = 15; /** @@ -140,8 +146,9 @@ static int[] compressIndexes(IntArrayList indexes, boolean doSort) { compressed[1] = minDelta; // System.out.println( - // "Densely compressed " + indexes.size() + " indexes to 2 ints, compression ratio " + - // (indexes.size() / 2)); + // "Densely compressed " + indexes.size() + " indexes to 2 ints, compression + // ratio " + + // (indexes.size() / 2)); return compressed; } @@ -187,8 +194,9 @@ static int[] compressIndexes(IntArrayList indexes, boolean doSort) { compressed[outputIndex++] = gatherInt; } - // System.out.println("Compressed " + indexes.size() + " indexes to " + size + " ints, compression ratio " - // + (indexes.size() / size)); + // System.out.println("Compressed " + indexes.size() + " indexes to " + size + " + // ints, compression ratio " + // + (indexes.size() / size)); return compressed; } From 94a52a033ab9f2d84dd36ab2003ced181de1bf57 Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 16 Dec 2023 19:05:11 +0100 Subject: [PATCH 184/256] fix direct trigger angle calculation, tune thresholds --- .../chunk/translucent_sorting/DirectTriggers.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/DirectTriggers.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/DirectTriggers.java index b72b491a65..727719b46b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/DirectTriggers.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/DirectTriggers.java @@ -41,9 +41,9 @@ class DirectTriggers implements SectionTriggers { * Degrees of movement from last sort position before the section is sorted * again. */ - private static final double TRIGGER_ANGLE = Math.toRadians(20); + private static final double TRIGGER_ANGLE = Math.toRadians(10); private static final double EARLY_TRIGGER_ANGLE_COS = Math.cos(TRIGGER_ANGLE * EARLY_TRIGGER_FACTOR); - private static final double SECTION_CENTER_DIST_SQUARED = 40 * 3 * Math.pow(16 / 2, 2); + private static final double SECTION_CENTER_DIST_SQUARED = 3 * Math.pow(16 / 2, 2) + 1; private static final double SECTION_CENTER_DIST = Math.sqrt(SECTION_CENTER_DIST_SQUARED); /** @@ -104,12 +104,11 @@ boolean isAngleTriggering(Vector3dc vector) { } } - // TODO: use faster code for this private static double angleCos(double ax, double ay, double az, double bx, double by, double bz) { - double length1Squared = Math.fma(ax, ax, Math.fma(ay, ay, az * az)); - double length2Squared = Math.fma(bx, bx, Math.fma(by, by, bz * bz)); + double lengthA = Math.sqrt(Math.fma(ax, ax, Math.fma(ay, ay, az * az))); + double lengthB = Math.sqrt(Math.fma(bx, bx, Math.fma(by, by, bz * bz))); double dot = Math.fma(ax, bx, Math.fma(ay, by, az * bz)); - return dot / Math.sqrt(length1Squared * length2Squared); + return dot / (lengthA * lengthB); } private void insertDirectAngleTrigger(DirectTriggerData data, Vector3dc cameraPos, double remainingAngle) { From 1907cdd0f834a2ef052b121d1e7f727b575e9c3a Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 16 Dec 2023 19:05:32 +0100 Subject: [PATCH 185/256] clarify comments and todos --- .../TranslucentGeometryCollector.java | 2 +- .../TranslucentSorting.java | 19 +------------------ .../bsp_tree/BSPSortState.java | 3 ++- 3 files changed, 4 insertions(+), 20 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java index 5d90bb9d20..64641fe513 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java @@ -413,7 +413,6 @@ private TranslucentData makeNewTranslucentData(BuiltSectionMeshParts translucent // from this point on we know the estimated sort type requires direction mixing // (no backface culling) and all vertices are in the UNASSIGNED direction. - // TODO: don't attempt static topo sorting if BSP sorting works well. NativeBuffer buffer = PresentTranslucentData.nativeBufferForQuads(this.quads); if (this.sortType == SortType.STATIC_TOPO_ACYCLIC) { var result = StaticTopoAcyclicData.fromMesh(translucentMesh, this.quads, sectionPos, buffer); @@ -434,6 +433,7 @@ private TranslucentData makeNewTranslucentData(BuiltSectionMeshParts translucent try { return BSPDynamicData.fromMesh(translucentMesh, cameraPos, quads, sectionPos, buffer, oldData); } catch (BSPBuildFailureException e) { + // TODO: investigate existing BSP build failures, then remove this logging System.out.println("BSP build failure: " + sectionPos); return TopoSortDynamicData.fromMesh(translucentMesh, cameraPos, quads, sectionPos, this, buffer); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentSorting.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentSorting.java index 737a8adb73..8bcd7024eb 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentSorting.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentSorting.java @@ -17,28 +17,11 @@ * sections for dynamic sorting to the trigger components. * * TODO: - * - many sections can be marked as needing an update but they are only actually - * scheduled for sorting when the RenderSectionManager makes them visible. This - * may result in many sections suddenly needing sorting when the camera moves. - * Maybe it's better to schedule them to be sorted gradually even if not - * visible, if there are idle threads. - * - Movement prediction and preemptive task scheduling to avoid needing to - * perform blocking sorts of close sections. Maybe not an issue? Might reduce - * stutter in high fps situations. However, high complexity with regards to - * processing the results of preemptive sorts. - * - determine the right distance for angle/distance triggering. It seems just - * the diagonal of a section is too small, angle triggering is broken at close - * distances. - * - Bug: adding a slime block onto one of the corners of the monster cube makes - * it invisible. Is this because there's nothing else in this section than just - * that one block? Might have something to do with NONE mode behaving weirdly in - * that situation. Possibly related to index buffer reuse, since it only happens - * after the block has been replaced at least once. * - Incompatible with rendering anything through Indium because it doesn't run * the translucent geometry collector properly. It doesn't run Sodium's * BlockRenderer which is required for lines 166-167 of BlockRenderer to work. * - * @author douira + * @author douira (the translucent_sorting package) */ public class TranslucentSorting { /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java index 4d5612e874..d21fd8da30 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java @@ -73,7 +73,8 @@ void writeIndex(int index) { private static final int CONSTANT_DELTA_WIDTH_INDEX = 15; /** - * ceilDiv was introduced to the JDK in Java 18 but is not available in Java 17. + * ceilDiv was introduced to the JDK in Java 18 but is not available in the here + * used Java 17. */ private static int ceilDiv(int x, int y) { return -Math.floorDiv(-x, y); From 97b38545055a7e73318409da076558e36c33a546 Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 16 Dec 2023 21:06:56 +0100 Subject: [PATCH 186/256] make the intersecting quad test more lenient --- .../render/chunk/translucent_sorting/TQuad.java | 4 ++-- .../bsp_tree/InnerPartitionBSPNode.java | 12 +++--------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java index 4eab6d9f9e..b1048484d2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java @@ -27,7 +27,7 @@ int getQuadHash() { public float getAlignedSurfaceArea() { if (this.facing == ModelQuadFacing.UNASSIGNED) { - return 0; + return 100; } var dX = this.extents[3] - this.extents[0]; @@ -42,7 +42,7 @@ public float getAlignedSurfaceArea() { return (float) (dX * dY); } else { // non-flat aligned quad, weird edge case - return 0; + return 90; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java index 4947af9bf7..d3b410ef61 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java @@ -367,16 +367,10 @@ static BSPNode build(BSPWorkspace workspace, IntArrayList indexes, int depth, BS int testsRemaining = 10000; for (int quadAIndex = 0; quadAIndex < indexes.size(); quadAIndex++) { var quadA = workspace.quads[indexes.getInt(quadAIndex)]; - if (quadA.facing() == ModelQuadFacing.UNASSIGNED) { - continue; - } + for (int quadBIndex = quadAIndex + 1; quadBIndex < indexes.size(); quadBIndex++) { var quadB = workspace.quads[indexes.getInt(quadBIndex)]; - if (quadB.facing() == ModelQuadFacing.UNASSIGNED) { - continue; - } - // aligned quads intersect if their bounding boxes intersect boolean intersects = true; for (int axis = 0; axis < 3; axis++) { @@ -384,8 +378,8 @@ static BSPNode build(BSPWorkspace workspace, IntArrayList indexes, int depth, BS var extentsA = quadA.extents(); var extentsB = quadB.extents(); - if (extentsA[axis] < extentsB[opposite] - || extentsB[axis] < extentsA[opposite]) { + if (extentsA[axis] <= extentsB[opposite] + || extentsB[axis] <= extentsA[opposite]) { intersects = false; break; } From 7b192495ed77fe1ca9a29d1dce953bd2e377ec08 Mon Sep 17 00:00:00 2001 From: douira Date: Sun, 17 Dec 2023 19:07:09 +0100 Subject: [PATCH 187/256] cleanup resolved todos and todos that are tracked elsewhere --- .../TranslucentGeometryCollector.java | 4 ---- .../bsp_tree/InnerPartitionBSPNode.java | 20 ------------------- .../data/BSPDynamicData.java | 1 - .../data/TopoSortDynamicData.java | 4 +--- 4 files changed, 1 insertion(+), 28 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java index 64641fe513..ff10b90e8a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java @@ -161,10 +161,6 @@ public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] verti // POS_X, POS_Y, POS_Z, NEG_X, NEG_Y, NEG_Z float[] extents = new float[] { posXExtent, posYExtent, posZExtent, negXExtent, negYExtent, negZExtent }; - // TODO: does it make a difference if we compute the center as the average of - // the unique vertices or as the center of the extents? (the latter would be - // less work) - // TODO: some of these things should probably only be computed on demand, and an // allocation of a Quad object should be avoided AccumulationGroup accGroup; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java index d3b410ef61..8c3d10d52e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java @@ -11,19 +11,6 @@ import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; /** - * TODO: - * - make partition finding more sophisticated by using distancesByNormal - * and other information. - * - pass partition information to child nodes instead of discarding if - * partition didn't work - * - detect many coplanar quads and avoid partitioning sorting alltogether. Try - * to partition so that large groups of coplanar quads are kept together and - * then not sorted at all. - * - sort the quads inside a node using the same heuristics as in the global - * level: convex hulls (like cuboids where the faces point outwards) don't need - * to be sorted. This could be used to optimize the inside of honey blocks, and - * other blocks. - * * Implementation note: * - Presorting the points in block-sized buckets doesn't help. It seems the * sort algorithm is just fast enough to handle this. @@ -78,9 +65,6 @@ record NodeReuseData(float[][] quadExtents, int[] indexes, int indexCount, int m static NodeReuseData prepareNodeReuse(BSPWorkspace workspace, IntArrayList indexes, int depth) { // if node reuse is enabled, only enable on the first level of children (not the // root node and not anything deeper than its children) - // TODO: more sophisticated reuse scheduling (make uset configurable, and only - // do once the section has been modified at least once already to avoid making - // this data on terrain sections that are never touched) if (workspace.prepareNodeReuse && depth == 1 && indexes.size() > NODE_REUSE_THRESHOLD) { // collect the extents of the indexed quads and hash them var quadExtents = new float[indexes.size()][]; @@ -325,7 +309,6 @@ static BSPNode build(BSPWorkspace workspace, IntArrayList indexes, int depth, BS // check a different axis if everything is in one quadsBefore, // which means there are no gaps if (quadsBefore != null && quadsBefore.size() == indexes.size()) { - // TODO: reuse the sorted point array for child nodes (add to workspace) continue; } @@ -356,14 +339,11 @@ static BSPNode build(BSPWorkspace workspace, IntArrayList indexes, int depth, BS partitions, axis, endsWithPlane); } - // TODO: attempt unaligned partitioning, convex decomposition, etc. - // test if the geometry intersects with itself // if there is self-intersection, return a multi leaf node to just give up // sorting this geometry. intersecting geometry is rare but when it does happen, // it should simply be accepted and rendered as-is. Whatever artifacts this // causes are considered "ok". - // TODO: also do this test with unaligned quads int testsRemaining = 10000; for (int quadAIndex = 0; quadAIndex < indexes.size(); quadAIndex++) { var quadA = workspace.quads[indexes.getInt(quadAIndex)]; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java index 093a9205d0..2e62d4ec66 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java @@ -57,7 +57,6 @@ public static BSPDynamicData fromMesh(BuiltSectionMeshParts translucentMesh, dynamicData.sort(cameraPos); // prepare accumulation groups for integration into GFNI triggering - // TODO: combine this and the similar code in TopoSortDynamicData var aligned = result.getAlignedDistances(); if (aligned != null) { for (var accGroup : aligned) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java index ac6cd80f13..4f7a990f95 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java @@ -219,8 +219,7 @@ public static TopoSortDynamicData fromMesh(BuiltSectionMeshParts translucentMesh var distancesByNormal = new Object2ReferenceOpenHashMap(size); if (collector.getAlignedDistances() != null) { - for (int direction = 0; direction < ModelQuadFacing.DIRECTIONS; direction++) { - var accGroup = collector.getAlignedDistances()[direction]; + for (var accGroup : collector.getAlignedDistances()) { if (accGroup != null) { accGroup.prepareAndInsert(distancesByNormal); } @@ -228,7 +227,6 @@ public static TopoSortDynamicData fromMesh(BuiltSectionMeshParts translucentMesh } if (collector.getUnalignedDistanceCount() > 0) { for (var accGroup : collector.getUnalignedDistances()) { - // TODO: get rid of collector key and just use the normal vector's hash code accGroup.prepareAndInsert(distancesByNormal); } } From 4ae774eb3d2910625209ea7e3392fc041f451daf Mon Sep 17 00:00:00 2001 From: douira Date: Sun, 17 Dec 2023 19:07:24 +0100 Subject: [PATCH 188/256] fix imports --- .../chunk/translucent_sorting/data/TopoSortDynamicData.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java index 4f7a990f95..cfff267068 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java @@ -6,7 +6,6 @@ import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; import me.jellysquid.mods.sodium.client.gl.util.VertexRange; -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TopoGraphSorting; From 11d2bc6b9be82fd42bebca2ef5a8cbc295362c19 Mon Sep 17 00:00:00 2001 From: douira Date: Sun, 17 Dec 2023 23:41:45 +0100 Subject: [PATCH 189/256] remove reuse of index data (doesn't appear to help) and add long-packed distance sorting (not indirect anymore) --- .../data/TopoSortDynamicData.java | 49 ++++++------------- 1 file changed, 16 insertions(+), 33 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java index cfff267068..94a565d533 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java @@ -1,6 +1,7 @@ package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data; import java.nio.IntBuffer; +import java.util.Arrays; import org.joml.Vector3fc; @@ -11,9 +12,15 @@ import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TopoGraphSorting; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TranslucentGeometryCollector; import me.jellysquid.mods.sodium.client.util.NativeBuffer; -import me.jellysquid.mods.sodium.client.util.sorting.MergeSort; import net.minecraft.util.math.ChunkSectionPos; +/** + * Implementation note: + * - Reusing the output of previous distance sorting job doesn't make a + * difference or makes things slower in some cases. It's unclear why exactly + * this happens, I suspect weird memory behavior or the reuse is not actually + * that helpful to the sorting algorithm. + */ public class TopoSortDynamicData extends DynamicData { private final TQuad[] quads; private boolean GFNITrigger = true; @@ -25,7 +32,6 @@ public class TopoSortDynamicData extends DynamicData { private int consecutiveTopoSortFailures = 0; private boolean pendingTriggerIsAngle; private Object2ReferenceOpenHashMap distancesByNormal; - private int[] distanceSortIndexes; private static final int MAX_TOPO_SORT_QUADS = 1000; private static final int MAX_TOPO_SORT_TIME_NS = 1_000_000; @@ -76,7 +82,6 @@ private void turnDirectTriggerOff() { this.directTrigger = false; this.turnDirectTriggerOff = true; } - this.distanceSortIndexes = null; } public boolean getAndFlushTurnGFNITriggerOff() { @@ -170,44 +175,23 @@ private void sort(Vector3fc cameraPos, boolean isAngleTrigger, boolean initial) if (this.directTrigger) { indexBuffer.rewind(); - this.distanceSortIndexes = distanceSortDirect( - this.distanceSortIndexes, indexBuffer, this.quads, cameraPos); + distanceSortDirect(indexBuffer, this.quads, cameraPos); return; } } - private static ThreadLocal distanceSortKeys = new ThreadLocal<>(); - - // TODO: encode the quad key into the lower half of a long and the distance into - // the upper half. since it's all positive distances, it should be able to just - // sort the longs by value using Arrays.sort (or fastutil's sort) which is very - // fast. In order to re-use the sort order the sorted array would need to be - // iterated, each quad index extracted and then the distance computed and - // written back into the upper part of the long. This uses more memory to keep - // around the sort result, but requires less repeated iteration of the data. - private static int[] distanceSortDirect(int[] indexes, - IntBuffer indexBuffer, TQuad[] quads, Vector3fc cameraPos) { - if (indexes == null) { - indexes = new int[quads.length]; - for (int i = 0; i < quads.length; i++) { - indexes[i] = i; - } + private static void distanceSortDirect(IntBuffer indexBuffer, TQuad[] quads, Vector3fc cameraPos) { + var data = new long[quads.length]; + for (int i = 0; i < quads.length; i++) { + float distance = cameraPos.distanceSquared(quads[i].center()); + data[i] = (long) Float.floatToRawIntBits(distance) << 32 | i; } - float[] keys = distanceSortKeys.get(); - if (keys == null || keys.length < quads.length) { - keys = new float[quads.length]; - distanceSortKeys.set(keys); - } + Arrays.sort(data); for (int i = 0; i < quads.length; i++) { - keys[i] = cameraPos.distanceSquared(quads[i].center()); + TranslucentData.writeQuadVertexIndexes(indexBuffer, (int) data[i]); } - - MergeSort.mergeSort(indexes, keys); - TranslucentData.writeQuadVertexIndexes(indexBuffer, indexes); - - return indexes; } public static TopoSortDynamicData fromMesh(BuiltSectionMeshParts translucentMesh, @@ -241,5 +225,4 @@ public static TopoSortDynamicData fromMesh(BuiltSectionMeshParts translucentMesh return dynamicData; } - } From db94236294e174dc56fc9f7f7b57d2c519628ce9 Mon Sep 17 00:00:00 2001 From: douira Date: Sun, 17 Dec 2023 23:58:29 +0100 Subject: [PATCH 190/256] remove scanning topo sort, this is a nice and interesting algorithm but it often runs into tricky cases where it fails --- .../translucent_sorting/TopoGraphSorting.java | 207 ------------------ 1 file changed, 207 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TopoGraphSorting.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TopoGraphSorting.java index 9970e532d0..c9ed2c2b13 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TopoGraphSorting.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TopoGraphSorting.java @@ -8,7 +8,6 @@ import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; import me.jellysquid.mods.sodium.client.util.collections.BitArray; -import me.jellysquid.mods.sodium.client.util.sorting.MergeSort; /** * This class contains the sorting algorithms that do topological or distance @@ -59,212 +58,6 @@ public static boolean orthogonalQuadVisibleThrough(TQuad halfspace, TQuad otherQ && !(otherSign * otherQuad.extents()[od] >= otherSign * halfspace.extents()[od]); } - /** - * The index in each node's array in the graph where the number of outgoing - * edges is stored. - */ - private static final int OUTGOING_EDGES = ModelQuadFacing.DIRECTIONS; - - private static void makeEdge(int[][] graph, BitArray leafQuads, - int fromQuadIndex, int toQuadIndex, int direction) { - graph[toQuadIndex][direction] = fromQuadIndex; - - // increment outgoing edges and clear from the no outgoing edges set if it had - // no outgoing edges beforehand - if (graph[fromQuadIndex][OUTGOING_EDGES]++ == 0) { - leafQuads.unset(fromQuadIndex); - } - } - - /** - * This scanning topo sort algorithm assumes that a number of invariants about - * the quads hold: - * - quads are planar and actually have the normal of their facing - * - quads don't intersect - * - quads aren't shaped weirdly - * - quads are axis-aligned - * - * If a camera position is provided, the algorithm will only sort visible quads - * and just render the other quads first without any particular ordering. - * - * Sometimes this algorithm will fail even if a topological sort is possible due - * to how it compresses the graph. - * - * @param indexBuffer the buffer to write the topo sort result to - * @param allQuads the quads to sort - * @param cameraPos the camera position, or null if not visibility check - * should be performed - * @return true if the quads were sorted, false if there was a cycle - */ - public static boolean topoSortAlignedScanningCyclic(IntBuffer indexBuffer, TQuad[] allQuads, Vector3fc cameraPos) { - // if enabled, check for visibility and produce a mapping of indices - TQuad[] quads = null; - int[] activeToRealIndex = null; - int activeQuads = 0; - if (cameraPos != null) { - // allocate the working quads and index map at the full size to avoid needing to - // iterate the quads again after checking visibility - quads = new TQuad[allQuads.length]; - activeToRealIndex = new int[allQuads.length]; - - for (int i = 0; i < allQuads.length; i++) { - TQuad quad = allQuads[i]; - if (pointOutsideHalfspace(quad.center(), quad.normal(), cameraPos)) { - activeToRealIndex[activeQuads] = i; - quads[activeQuads] = quad; - activeQuads++; - } else { - // write the invisible quads right away - TranslucentData.writeQuadVertexIndexes(indexBuffer, i); - } - } - } else { - quads = allQuads; - activeQuads = allQuads.length; - } - - /** - * The translucent quad visibility graph is stored as an array for each quad. - * Each quad's array stores the indexes of the quads that can see this quad - * through them. The edges are stored backwards to avoid using dynamically - * sized-lists for outgoing edges. - * - * The last entry stores the number of *outgoing* edges. - */ - int[][] graph = new int[activeQuads][ModelQuadFacing.DIRECTIONS + 1]; - - // the set of quads that have no outgoing edges - BitArray leafQuads = new BitArray(activeQuads); - leafQuads.set(0, activeQuads); - - // a bitfield of the directions that have quads - int activeDirections = 0; - - // initialize the graph with -1 to represent no edge - for (int i = 0; i < activeQuads; i++) { - activeDirections |= 1 << quads[i].facing().ordinal(); - - for (int j = 0; j < ModelQuadFacing.DIRECTIONS; j++) { - graph[i][j] = -1; - } - } - - // the stash of quads that have not yet been visible to the scanned quads - BitArray stashedOrthoQuads = new BitArray(activeQuads); - - // keep around the allocation of the keys array - float[] keys = new float[activeQuads]; - - // to build the graph, perform scans for each direction - for (int direction = 0; direction < ModelQuadFacing.DIRECTIONS; direction++) { - // skip directions that have no quads - if ((activeDirections & (1 << direction)) == 0) { - continue; - } - - ModelQuadFacing facing = ModelQuadFacing.VALUES[direction]; - ModelQuadFacing oppositeFacing = facing.getOpposite(); - int oppositeDirection = oppositeFacing.ordinal(); - int sign = facing.getSign(); - - // generate keys for this direction - for (int i = 0; i < activeQuads; i++) { - // get the extent in the opposite direction of the scan because quads that are - // visible from a scanning quad should be before it - TQuad quad = quads[i]; - keys[i] = quad.extents()[oppositeDirection] * sign * -1; - } - - int[] sortedQuads = MergeSort.mergeSort(keys); - - // the index of the last quad facing in scan direction (scanning quad) in the - // sorted quad array - int lastScanQuadPos = -1; - - // perform a scan by going through the sorted quads and making edges between the - // scanning quads and the quads that precede them in the sort order - stashedOrthoQuads.unset(); - for (int quadIndexPos = 0; quadIndexPos < activeQuads; quadIndexPos++) { - int quadIndex = sortedQuads[quadIndexPos]; - TQuad quad = quads[quadIndex]; - if (quad.facing() != facing) { - continue; - } - - // connect to the last scan quad if it exists - if (lastScanQuadPos != -1) { - makeEdge(graph, leafQuads, quadIndex, sortedQuads[lastScanQuadPos], direction); - } - - // check if any of the stashed quads are now visible - for (int stashedQuadIndex = stashedOrthoQuads - .nextSetBit(0); stashedQuadIndex != -1; stashedQuadIndex = stashedOrthoQuads - .nextSetBit(stashedQuadIndex + 1)) { - TQuad stashedOrthoQuad = quads[stashedQuadIndex]; - - // if it's visible through the current quad, unstash and connect - if (orthogonalQuadVisibleThrough(quad, stashedOrthoQuad)) { - stashedOrthoQuads.unset(stashedQuadIndex); - makeEdge(graph, leafQuads, quadIndex, stashedQuadIndex, direction); - } - } - - // check the quads facing in other directions than the scan facing. - // initially increment to skip the last scan quad. - for (++lastScanQuadPos; lastScanQuadPos < quadIndexPos; lastScanQuadPos++) { - int otherQuadIndex = sortedQuads[lastScanQuadPos]; - TQuad otherQuad = quads[otherQuadIndex]; - - // discard quads that face in the opposite direction, they are never visible - if (otherQuad.facing() == oppositeFacing) { - continue; - } - - // if it's visible through the current quad, add an edge. - // the quad has a direction that is orthogonal to the scan direction, since - // opposite quads were just ruled out and same facing quads are handled by the - // scan. - if (orthogonalQuadVisibleThrough(quad, otherQuad)) { - makeEdge(graph, leafQuads, quadIndex, otherQuadIndex, direction); - } else { - // otherwise stash it to check if it's visible by later quads in the scan - stashedOrthoQuads.set(otherQuadIndex); - } - } - - // lastScanQuadPos is now at quadIndexPos - } - } - - // iterate through the set of quads with no outgoing edges until there are none - // left to produce a topological sort of the graph - for (int topoSortPos = 0; topoSortPos < activeQuads; topoSortPos++) { - int nextLeafQuadIndex = leafQuads.nextSetBit(0); - - // if there are no leaf quads but not yet all quads have been processed, - // there must be a cycle! - if (nextLeafQuadIndex == -1) { - return false; - } - - leafQuads.unset(nextLeafQuadIndex); - - // add it to the topo sort result - TranslucentData.writeMappedQuadVertexIndexes(indexBuffer, nextLeafQuadIndex, activeToRealIndex); - - // remove the edges to this quad and mark them as leaves if that was the last - // outgoing edge they had - for (int direction = 0; direction < ModelQuadFacing.DIRECTIONS; direction++) { - int otherQuadIndex = graph[nextLeafQuadIndex][direction]; - if (otherQuadIndex != -1 && --graph[otherQuadIndex][OUTGOING_EDGES] == 0) { - leafQuads.set(otherQuadIndex); - } - } - } - - return true; - } - private static boolean testSeparatorRange(Object2ReferenceOpenHashMap distancesByNormal, Vector3fc normal, float start, float end) { var distances = distancesByNormal.get(normal); From 58b7b34acb22cb246ebce0e4779b116a149e593a Mon Sep 17 00:00:00 2001 From: douira Date: Wed, 20 Dec 2023 04:58:17 +0100 Subject: [PATCH 191/256] refactor translucent geometry collection and remove unnecessary changes, this reduces the amount of work done during rebuilds and instead performs this work only as needed when certain sort types require it. Also removes a few trivial changes that aren't necessary in the PR. WIP: there might be regressions compared to before this commit given that it touches a lot of important code. --- .../mods/sodium/api/util/NormI8.java | 39 ++- .../client/model/quad/BakedQuadView.java | 4 +- .../sodium/client/model/quad/ModelQuad.java | 28 +- .../client/model/quad/ModelQuadView.java | 75 +---- .../quad/properties/ModelQuadFacing.java | 95 ++++-- .../client/render/SodiumWorldRenderer.java | 2 +- .../render/chunk/RenderSectionManager.java | 4 +- .../chunk/compile/ChunkBuildContext.java | 1 - .../compile/pipeline/BlockRenderContext.java | 7 + .../chunk/compile/pipeline/BlockRenderer.java | 2 +- .../chunk/compile/pipeline/FluidRenderer.java | 14 +- .../render/chunk/data/BuiltSectionInfo.java | 3 +- .../translucent_sorting/AccGroupResult.java | 38 --- .../translucent_sorting/AlignableNormal.java | 88 +++++ .../chunk/translucent_sorting/TQuad.java | 119 ++++++- .../TranslucentGeometryCollector.java | 301 +++++++++--------- .../translucent_sorting/bsp_tree/BSPNode.java | 67 ++-- .../bsp_tree/BSPResult.java | 42 +-- .../bsp_tree/BSPWorkspace.java | 17 +- .../bsp_tree/InnerBinaryPartitionBSPNode.java | 2 +- .../bsp_tree/InnerPartitionBSPNode.java | 12 +- .../data/AnyOrderData.java | 4 +- .../data/BSPDynamicData.java | 19 +- .../translucent_sorting/data/DynamicData.java | 16 +- .../data/StaticNormalRelativeData.java | 77 ++--- .../data/StaticTopoAcyclicData.java | 1 - .../{ => data}/TopoGraphSorting.java | 53 ++- .../data/TopoSortDynamicData.java | 30 +- .../data/TranslucentData.java | 4 + .../{ => trigger}/CameraMovement.java | 2 +- .../{ => trigger}/DirectTriggers.java | 4 +- .../{ => trigger}/GFNITriggers.java | 40 +-- .../trigger/GeometryPlanes.java | 129 ++++++++ .../{ => trigger}/Group.java | 59 ++-- .../{ => trigger}/NormalList.java | 50 ++- .../NormalPlanes.java} | 32 +- .../{ => trigger}/TranslucentSorting.java | 24 +- .../sodium/client/util/ModelQuadUtil.java | 35 -- .../sodium/client/util/sorting/MergeSort.java | 2 +- .../mixin/core/model/quad/BakedQuadMixin.java | 39 +-- 40 files changed, 867 insertions(+), 713 deletions(-) delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AccGroupResult.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AlignableNormal.java rename src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/{ => data}/TopoGraphSorting.java (86%) rename src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/{ => trigger}/CameraMovement.java (90%) rename src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/{ => trigger}/DirectTriggers.java (99%) rename src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/{ => trigger}/GFNITriggers.java (77%) create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GeometryPlanes.java rename src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/{ => trigger}/Group.java (50%) rename src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/{ => trigger}/NormalList.java (79%) rename src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/{AccumulationGroup.java => trigger/NormalPlanes.java} (75%) rename src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/{ => trigger}/TranslucentSorting.java (90%) diff --git a/src/api/java/net/caffeinemc/mods/sodium/api/util/NormI8.java b/src/api/java/net/caffeinemc/mods/sodium/api/util/NormI8.java index 4ed46a98fe..9636960cfd 100644 --- a/src/api/java/net/caffeinemc/mods/sodium/api/util/NormI8.java +++ b/src/api/java/net/caffeinemc/mods/sodium/api/util/NormI8.java @@ -1,7 +1,7 @@ package net.caffeinemc.mods.sodium.api.util; import net.minecraft.util.math.MathHelper; -import org.joml.Vector3f; +import org.joml.Vector3fc; /** * Provides some utilities for working with packed normal vectors. Each normal component provides 8 bits of @@ -27,7 +27,7 @@ public class NormI8 { */ private static final float NORM = 1.0f / COMPONENT_RANGE; - public static int pack(Vector3f normal) { + public static int pack(Vector3fc normal) { return pack(normal.x(), normal.y(), normal.z()); } @@ -78,4 +78,39 @@ public static float unpackY(int norm) { public static float unpackZ(int norm) { return ((byte) ((norm >> Z_COMPONENT_OFFSET) & 0xFF)) * NORM; } + + /** + * Flips the direction of a packed normal by negating each component. (multiplication by -1) + * @param norm The packed normal + */ + public static int flipPacked(int norm) { + int normX = (((norm >> X_COMPONENT_OFFSET) & 0xFF) * -1) & 0xFF; + int normY = (((norm >> Y_COMPONENT_OFFSET) & 0xFF) * -1) & 0xFF; + int normZ = (((norm >> Z_COMPONENT_OFFSET) & 0xFF) * -1) & 0xFF; + + return (normZ << Z_COMPONENT_OFFSET) | (normY << Y_COMPONENT_OFFSET) | (normX << X_COMPONENT_OFFSET); + } + + /** + * Returns true if the two packed normals are opposite directions. + * + * TODO: this could possibly be faster by using normA == (~normB + 0x010101) but + * that has to special case when a component is zero since that wouldn't + * overflow correctly back to zero. (~0+1 == 0 but not if it's somewhere inside + * th int) + * + * @param normA The first packed normal + * @param normB The second packed normal + */ + public static boolean isOpposite(int normA, int normB) { + int normAX = (normA >> X_COMPONENT_OFFSET) & 0xFF; + int normAY = (normA >> Y_COMPONENT_OFFSET) & 0xFF; + int normAZ = (normA >> Z_COMPONENT_OFFSET) & 0xFF; + + int normBX = (normB >> X_COMPONENT_OFFSET) & 0xFF; + int normBY = (normB >> Y_COMPONENT_OFFSET) & 0xFF; + int normBZ = (normB >> Z_COMPONENT_OFFSET) & 0xFF; + + return normAX == -normBX && normAY == -normBY && normAZ == -normBZ; + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/BakedQuadView.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/BakedQuadView.java index 247e7a23fc..e6ee280d62 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/BakedQuadView.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/BakedQuadView.java @@ -5,6 +5,8 @@ public interface BakedQuadView extends ModelQuadView { ModelQuadFacing getNormalFace(); - + + int getNormal(); + boolean hasShade(); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuad.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuad.java index 578d7701e7..50028467f1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuad.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuad.java @@ -6,8 +6,7 @@ import static me.jellysquid.mods.sodium.client.util.ModelQuadUtil.*; /** - * A simple implementation of the {@link ModelQuadViewMutable} interface which - * can provide an on-heap scratch area + * A simple implementation of the {@link ModelQuadViewMutable} interface which can provide an on-heap scratch area * for storing quad vertex data. */ public class ModelQuad implements ModelQuadViewMutable { @@ -18,9 +17,6 @@ public class ModelQuad implements ModelQuadViewMutable { private Direction direction; private int colorIdx; - private int GFNINormX; - private int GFNINormY; - private int GFNINormZ; @Override public void setX(int idx, float x) { @@ -126,26 +122,4 @@ public Sprite getSprite() { public Direction getLightFace() { return this.direction; } - - @Override - public int getGFNINormX() { - return this.GFNINormX; - } - - @Override - public int getGFNINormY() { - return this.GFNINormY; - } - - @Override - public int getGFNINormZ() { - return this.GFNINormZ; - } - - @Override - public void setGFNINormal(int x, int y, int z) { - this.GFNINormX = x; - this.GFNINormY = y; - this.GFNINormZ = z; - } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java index ff14353b7f..141097dd33 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java @@ -1,14 +1,12 @@ package me.jellysquid.mods.sodium.client.model.quad; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFlags; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TranslucentSorting; import net.caffeinemc.mods.sodium.api.util.NormI8; import net.minecraft.client.texture.Sprite; import net.minecraft.util.math.Direction; /** - * Provides a read-only view of a model quad. For mutable access to a model - * quad, see {@link ModelQuadViewMutable}. + * Provides a read-only view of a model quad. For mutable access to a model quad, see {@link ModelQuadViewMutable}. */ public interface ModelQuadView { /** @@ -42,8 +40,7 @@ public interface ModelQuadView { float getTexV(int idx); /** - * @return The integer bit flags containing the {@link ModelQuadFlags} for this - * quad + * @return The integer bit flags containing the {@link ModelQuadFlags} for this quad */ int getFlags(); @@ -62,31 +59,11 @@ public interface ModelQuadView { */ Direction getLightFace(); - /** - * @return The x coordinate of the unit normal vector - */ - int getGFNINormX(); - - /** - * @return The y coordinate of the unit normal vector - */ - int getGFNINormY(); - - /** - * @return The z coordinate of the unit normal vector - */ - int getGFNINormZ(); - - /** - * Sets an accurate normal vector for this quad. This is used for GFNI. - * - * @param x The normal's x component - * @param y The normal's y component - * @param z The normal's z component - */ - void setGFNINormal(int x, int y, int z); + default boolean hasColor() { + return this.getColorIndex() != -1; + } - default int calculateNormals(boolean calculateUnitNormal) { + default int calculateNormal() { final float x0 = getX(0); final float y0 = getY(0); final float z0 = getZ(0); @@ -114,40 +91,14 @@ default int calculateNormals(boolean calculateUnitNormal) { float normY = dz0 * dx1 - dx0 * dz1; float normZ = dx0 * dy1 - dy0 * dx1; - int packedNormal = -1; - if (calculateUnitNormal) { - // normalize by length for the packed normal - float length = (float) Math.sqrt(normX * normX + normY * normY + normZ * normZ); - if (length != 0.0 && length != 1.0) { - normX /= length; - normY /= length; - normZ /= length; - } - - packedNormal = NormI8.pack(normX, normY, normZ); - } - - // normalize onto the surface of a cube by dividing by the length of the longest - // component - float infNormLength = Math.max(Math.abs(normX), Math.max(Math.abs(normY), Math.abs(normZ))); - if (infNormLength != 0 && infNormLength != 1) { - normX /= infNormLength; - normY /= infNormLength; - normZ /= infNormLength; + // normalize by length for the packed normal + float length = (float) Math.sqrt(normX * normX + normY * normY + normZ * normZ); + if (length != 0.0 && length != 1.0) { + normX /= length; + normY /= length; + normZ /= length; } - // quantize the coordinates on the surface of the cube. - // in each axis the number of values is 2 * QUANTIZATION_FACTOR + 1. - // the total number of normals is the number of points on that cube's surface. - this.setGFNINormal( - (int) (normX * TranslucentSorting.QUANTIZATION_FACTOR), - (int) (normY * TranslucentSorting.QUANTIZATION_FACTOR), - (int) (normZ * TranslucentSorting.QUANTIZATION_FACTOR)); - - return packedNormal; - } - - default boolean hasColor() { - return this.getColorIndex() != -1; + return NormI8.pack(normX, normY, normZ); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java index 7ee3745c56..6d0f535dc8 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java @@ -1,9 +1,14 @@ package me.jellysquid.mods.sodium.client.model.quad.properties; +import java.util.Arrays; + import org.joml.Vector3f; import org.joml.Vector3fc; +import me.jellysquid.mods.sodium.client.util.DirectionUtil; +import net.caffeinemc.mods.sodium.api.util.NormI8; import net.minecraft.util.math.Direction; +import net.minecraft.util.math.MathHelper; public enum ModelQuadFacing { POS_X, @@ -22,13 +27,18 @@ public enum ModelQuadFacing { public static final int NONE = 0; public static final int ALL = (1 << COUNT) - 1; - public static final Vector3fc[] NORMALS = new Vector3fc[ModelQuadFacing.DIRECTIONS]; + public static final Vector3fc[] ALIGNED_NORMALS = new Vector3fc[] { + new Vector3f(1, 0, 0), + new Vector3f(0, 1, 0), + new Vector3f(0, 0, 1), + new Vector3f(-1, 0, 0), + new Vector3f(0, -1, 0), + new Vector3f(0, 0, -1), + }; - static { - for (int i = 0; i < ModelQuadFacing.DIRECTIONS; i++) { - NORMALS[i] = new Vector3f(ModelQuadFacing.VALUES[i].toDirection().getUnitVector()); - } - } + public static final int[] PACKED_ALIGNED_NORMALS = Arrays.stream(ALIGNED_NORMALS) + .mapToInt(NormI8::pack) + .toArray(); public static final int OPPOSING_X = 1 << ModelQuadFacing.POS_X.ordinal() | 1 << ModelQuadFacing.NEG_X.ordinal(); public static final int OPPOSING_Y = 1 << ModelQuadFacing.POS_Y.ordinal() | 1 << ModelQuadFacing.NEG_Y.ordinal(); @@ -36,12 +46,12 @@ public enum ModelQuadFacing { public static ModelQuadFacing fromDirection(Direction dir) { return switch (dir) { - case DOWN -> NEG_Y; - case UP -> POS_Y; - case NORTH -> NEG_Z; - case SOUTH -> POS_Z; - case WEST -> NEG_X; - case EAST -> POS_X; + case DOWN -> NEG_Y; + case UP -> POS_Y; + case NORTH -> NEG_Z; + case SOUTH -> POS_Z; + case WEST -> NEG_X; + case EAST -> POS_X; }; } @@ -65,15 +75,60 @@ public int getSign() { }; } - public Direction toDirection() { + public int getAxis() { return switch (this) { - case POS_Y -> Direction.UP; - case NEG_Y -> Direction.DOWN; - case POS_X -> Direction.EAST; - case NEG_X -> Direction.WEST; - case POS_Z -> Direction.SOUTH; - case NEG_Z -> Direction.NORTH; - default -> Direction.UP; + case POS_X, NEG_X -> 0; + case POS_Y, NEG_Y -> 1; + case POS_Z, NEG_Z -> 2; + default -> -1; }; } + + public boolean isAligned() { + return this != UNASSIGNED; + } + + public Vector3fc getAlignedNormal() { + if (!this.isAligned()) { + throw new IllegalStateException("Cannot get aligned normal for unassigned facing"); + } + return ALIGNED_NORMALS[this.ordinal()]; + } + + public int getPackedAlignedNormal() { + if (!this.isAligned()) { + throw new IllegalStateException("Cannot get packed aligned normal for unassigned facing"); + } + return PACKED_ALIGNED_NORMALS[this.ordinal()]; + } + + public static ModelQuadFacing fromPackedNormal(float x, float y, float z) { + Vector3f normal = new Vector3f(x, y, z); + + if (!normal.isFinite()) { + return ModelQuadFacing.UNASSIGNED; + } + + float maxDot = 0; + Direction closestFace = null; + + for (Direction face : DirectionUtil.ALL_DIRECTIONS) { + float dot = normal.dot(face.getUnitVector()); + + if (dot > maxDot) { + maxDot = dot; + closestFace = face; + } + } + + if (closestFace != null && MathHelper.approximatelyEquals(maxDot, 1.0f)) { + return ModelQuadFacing.fromDirection(closestFace); + } + + return ModelQuadFacing.UNASSIGNED; + } + + public static ModelQuadFacing fromPackedNormal(int normal) { + return fromPackedNormal(NormI8.unpackX(normal), NormI8.unpackY(normal), NormI8.unpackZ(normal)); + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index 72417fd321..77a9135b56 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -12,7 +12,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.map.ChunkTracker; import me.jellysquid.mods.sodium.client.render.chunk.map.ChunkTrackerHolder; import me.jellysquid.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.CameraMovement; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger.CameraMovement; import me.jellysquid.mods.sodium.client.render.viewport.Viewport; import me.jellysquid.mods.sodium.client.util.NativeBuffer; import me.jellysquid.mods.sodium.client.world.WorldRendererExtended; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index bedfe8f467..977f8097f4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -29,11 +29,11 @@ import me.jellysquid.mods.sodium.client.render.chunk.region.RenderRegion; import me.jellysquid.mods.sodium.client.render.chunk.region.RenderRegionManager; import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.CameraMovement; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TranslucentSorting; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.NoData; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TopoSortDynamicData; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger.CameraMovement; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger.TranslucentSorting; import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkMeshFormats; import me.jellysquid.mods.sodium.client.render.texture.SpriteUtil; import me.jellysquid.mods.sodium.client.render.util.RenderAsserts; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildContext.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildContext.java index 91295dd32f..b3fec8d16a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildContext.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildContext.java @@ -4,7 +4,6 @@ import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.BlockRenderCache; import net.minecraft.client.MinecraftClient; import net.minecraft.client.world.ClientWorld; -import net.minecraft.world.World; public class ChunkBuildContext { public final ChunkBuildBuffers buffers; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderContext.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderContext.java index 9741ae8923..87ce85df41 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderContext.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderContext.java @@ -37,6 +37,13 @@ public void update(BlockPos pos, BlockPos origin, BlockState state, BakedModel m this.seed = seed; } + /** + * @return The collector for translucent geometry sorting + */ + public TranslucentGeometryCollector collector() { + return this.collector; + } + /** * @return The position (in world space) of the block being rendered */ diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java index 017a05b03b..7dc5336173 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java @@ -164,7 +164,7 @@ private void writeGeometry(BlockRenderContext ctx, } if (material == DefaultMaterials.TRANSLUCENT && ctx.collector != null) { - ctx.collector.appendQuad(quad, vertices, normalFace, false); + ctx.collector.appendQuad(quad.getNormal(), vertices, normalFace); } var vertexBuffer = builder.getVertexBuffer(normalFace); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java index f7693d69c6..867af954d8 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java @@ -21,6 +21,7 @@ import me.jellysquid.mods.sodium.client.world.WorldSlice; import me.jellysquid.mods.sodium.client.util.DirectionUtil; import net.caffeinemc.mods.sodium.api.util.ColorABGR; +import net.caffeinemc.mods.sodium.api.util.NormI8; import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandler; import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandlerRegistry; import net.minecraft.block.BlockState; @@ -428,11 +429,16 @@ private void writeQuad(ChunkModelBuilder builder, TranslucentGeometryCollector c } if (material == DefaultMaterials.TRANSLUCENT && collector != null) { - if (facing == ModelQuadFacing.UNASSIGNED) { - // calculate the current GFNI normal but not the unit normal - quad.calculateNormals(false); + int normal; + if (facing.isAligned()) { + normal = facing.getPackedAlignedNormal(); + } else { + normal = quad.calculateNormal(); + } + if (flip) { + normal = NormI8.flipPacked(normal); } - collector.appendQuad(quad, vertices, facing, flip); + collector.appendQuad(normal, vertices, facing); } var vertexBuffer = builder.getVertexBuffer(facing); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/BuiltSectionInfo.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/BuiltSectionInfo.java index b757f12544..1e764cc48c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/BuiltSectionInfo.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/BuiltSectionInfo.java @@ -104,6 +104,7 @@ private static BuiltSectionInfo createEmptyData() { BuiltSectionInfo.Builder meshInfo = new BuiltSectionInfo.Builder(); meshInfo.setOcclusionData(occlusionData); + return meshInfo.build(); } @@ -114,4 +115,4 @@ private static T[] toArray(Collection collection, IntFunction alloca return collection.toArray(allocator); } -} +} \ No newline at end of file diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AccGroupResult.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AccGroupResult.java deleted file mode 100644 index 896ce606df..0000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AccGroupResult.java +++ /dev/null @@ -1,38 +0,0 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; - -import java.util.Collection; - -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; - -public abstract class AccGroupResult { - AccumulationGroup[] alignedDistances; - - public AccumulationGroup[] getAlignedDistances() { - return this.alignedDistances; - } - - public AccumulationGroup[] getAlignedDistancesOrCreate() { - if (this.alignedDistances == null) { - this.alignedDistances = new AccumulationGroup[ModelQuadFacing.DIRECTIONS]; - } - return this.alignedDistances; - } - - public abstract Collection getUnalignedDistances(); - - public abstract int getUnalignedDistanceCount(); - - public abstract AccumulationGroup getGroupForUnalignedNormal(NormalList normalList); - - AccumulationGroup getGroupForNormal(NormalList normalList) { - int collectorKey = normalList.getCollectorKey(); - if (collectorKey < 0xFF) { - if (this.alignedDistances == null) { - return null; - } - return this.alignedDistances[collectorKey]; - } else { - return getGroupForUnalignedNormal(normalList); - } - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AlignableNormal.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AlignableNormal.java new file mode 100644 index 0000000000..217079e16f --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AlignableNormal.java @@ -0,0 +1,88 @@ +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; + +import org.joml.Vector3f; +import org.joml.Vector3fc; + +import it.unimi.dsi.fastutil.floats.FloatArrays; +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; + +public class AlignableNormal extends Vector3f { + private static final AlignableNormal[] NORMALS = new AlignableNormal[ModelQuadFacing.DIRECTIONS]; + + static { + for (int i = 0; i < ModelQuadFacing.DIRECTIONS; i++) { + NORMALS[i] = new AlignableNormal(ModelQuadFacing.ALIGNED_NORMALS[i], i); + } + } + + private static final int UNASSIGNED = ModelQuadFacing.UNASSIGNED.ordinal(); + private final int alignedDirection; + + private AlignableNormal(Vector3fc v, int alignedDirection) { + super(v); + this.alignedDirection = alignedDirection; + } + + public static AlignableNormal fromAligned(int alignedDirection) { + return NORMALS[alignedDirection]; + } + + public static AlignableNormal fromUnaligned(Vector3fc v) { + return new AlignableNormal(v, UNASSIGNED); + } + + public int getAlignedDirection() { + return this.alignedDirection; + } + + public boolean isAligned() { + return this.alignedDirection != UNASSIGNED; + } + + @Override + public int hashCode() { + if (this.isAligned()) { + return this.alignedDirection; + } else { + return super.hashCode() + ModelQuadFacing.DIRECTIONS; + } + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + AlignableNormal other = (AlignableNormal) obj; + if (alignedDirection != other.alignedDirection) + return false; + return true; + } + + public static boolean queryRange(float[] sortedDistances, float start, float end) { + // test that there is actually an entry in the query range + int result = FloatArrays.binarySearch(sortedDistances, start); + if (result < 0) { + // recover the insertion point + int insertionPoint = -result - 1; + if (insertionPoint >= sortedDistances.length) { + // no entry in the query range + return false; + } + + // check if the entry at the insertion point, which is the next one greater than + // the start value, is less than or equal to the end value + if (sortedDistances[insertionPoint] <= end) { + // there is an entry in the query range + return true; + } + } else { + // exact match, trigger + return true; + } + return false; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java index b1048484d2..b7e9c8698b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java @@ -6,27 +6,134 @@ import org.joml.Vector3fc; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import net.caffeinemc.mods.sodium.api.util.NormI8; /** * Represents a quad for the purposes of translucency sorting. Called TQuad to * avoid confusion with other quad classes. */ -public record TQuad(ModelQuadFacing facing, Vector3fc normal, Vector3f center, float[] extents) { +public class TQuad { + /** + * The quantization factor with which the normals are quantized such that there + * are fewer possible unique normals. The factor describes the number of steps + * in each direction per dimension that the components of the normals can have. + * It determines the density of the grid on the surface of a unit cube centered + * at the origin onto which the normals are projected. The normals are snapped + * to the nearest grid point. + */ + private static final int QUANTIZATION_FACTOR = 4; + + private ModelQuadFacing facing; + private float[] extents; + private Vector3fc center; // null on aligned quads + private int packedNormal; + private Vector3fc quantizedNormal; + private float dotProduct; + + private TQuad(ModelQuadFacing facing, float[] extents, Vector3fc center, int packedNormal) { + this.facing = facing; + this.extents = extents; + this.center = center; + this.packedNormal = packedNormal; + + if (this.facing.isAligned()) { + this.dotProduct = this.extents[this.facing.ordinal()] * this.facing.getSign(); + } else { + float normX = NormI8.unpackX(this.packedNormal); + float normY = NormI8.unpackY(this.packedNormal); + float normZ = NormI8.unpackZ(this.packedNormal); + this.dotProduct = this.getCenter().dot(normX, normY, normZ); + } + } + + static TQuad fromAligned(ModelQuadFacing facing, float[] extents) { + return new TQuad(facing, extents, null, ModelQuadFacing.PACKED_ALIGNED_NORMALS[facing.ordinal()]); + } + + static TQuad fromUnaligned(ModelQuadFacing facing, float[] extents, Vector3fc center, int packedNormal) { + return new TQuad(facing, extents, center, packedNormal); + } + + public ModelQuadFacing getFacing() { + return this.facing; + } + + public float[] getExtents() { + return this.extents; + } + + public Vector3fc getCenter() { + // calculate aligned quad center on demand + if (this.center == null) { + this.center = new Vector3f( + (this.extents[0] + this.extents[3]) / 2, + (this.extents[1] + this.extents[4]) / 2, + (this.extents[2] + this.extents[5]) / 2); + } + return this.center; + } + + public float getDotProduct() { + return this.dotProduct; + } + + public int getPackedNormal() { + return this.packedNormal; + } + + public static boolean isOpposite(int normA, int normB) { + return NormI8.isOpposite(normA, normB); + } + + public Vector3fc getQuantizedNormal() { + if (this.quantizedNormal == null) { + if (this.facing.isAligned()) { + this.quantizedNormal = this.facing.getAlignedNormal(); + } else { + this.computeQuantizedNormal(); + } + } + return this.quantizedNormal; + } + + private void computeQuantizedNormal() { + float normX = NormI8.unpackX(this.packedNormal); + float normY = NormI8.unpackY(this.packedNormal); + float normZ = NormI8.unpackZ(this.packedNormal); + + // normalize onto the surface of a cube by dividing by the length of the longest + // component + float infNormLength = Math.max(Math.abs(normX), Math.max(Math.abs(normY), Math.abs(normZ))); + if (infNormLength != 0 && infNormLength != 1) { + normX /= infNormLength; + normY /= infNormLength; + normZ /= infNormLength; + } + + // quantize the coordinates on the surface of the cube. + // in each axis the number of values is 2 * QUANTIZATION_FACTOR + 1. + // the total number of normals is the number of points on that cube's surface. + this.quantizedNormal = new Vector3f( + (int) (normX * QUANTIZATION_FACTOR), + (int) (normY * QUANTIZATION_FACTOR), + (int) (normZ * QUANTIZATION_FACTOR)); + } + int getQuadHash() { // the hash code needs to be particularly collision resistant int result = 1; result = 31 * result + Arrays.hashCode(this.extents); - if (facing == ModelQuadFacing.UNASSIGNED) { - result = 31 * result + this.normal.hashCode(); - } else { + if (facing.isAligned()) { result = 31 * result + this.facing.hashCode(); + } else { + result = 31 * result + this.packedNormal; } - result = 31 * result + this.center.hashCode(); + result = 31 * result + Float.hashCode(this.dotProduct); return result; } public float getAlignedSurfaceArea() { - if (this.facing == ModelQuadFacing.UNASSIGNED) { + if (!this.facing.isAligned()) { return 100; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java index ff10b90e8a..7e0755df78 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java @@ -1,13 +1,13 @@ package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; +import java.util.Arrays; + import org.joml.Vector3f; import org.joml.Vector3fc; -import it.unimi.dsi.fastutil.ints.Int2ReferenceLinkedOpenHashMap; import it.unimi.dsi.fastutil.objects.ReferenceArrayList; import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions.SortBehavior; -import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.FluidRenderer; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; @@ -20,11 +20,11 @@ import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.StaticTopoAcyclicData; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TopoSortDynamicData; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger.GeometryPlanes; import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexEncoder; import me.jellysquid.mods.sodium.client.util.NativeBuffer; +import net.caffeinemc.mods.sodium.api.util.NormI8; import net.minecraft.util.math.ChunkSectionPos; -import java.util.Arrays; -import java.util.Collection; /** * The translucent geometry collector collects the data from the renderers and @@ -41,14 +41,36 @@ * doing it once without invisible quad exclusion and once with if the first * attempt fails. */ -public class TranslucentGeometryCollector extends AccGroupResult { - private Int2ReferenceLinkedOpenHashMap unalignedDistances; - +public class TranslucentGeometryCollector { private final ChunkSectionPos sectionPos; - private int facePlaneCount = 0; - private int alignedNormalBitmap = 0; - private Vector3f minBounds = new Vector3f(16, 16, 16); - private Vector3f maxBounds = new Vector3f(0, 0, 0); + + // true if there are any unaligned quads + private boolean hasUnaligned = false; + + // a bitmap of the aligned facings present in the section + private int alignedFacingBitmap = 0; + + // AABB of the geometry + private float[] extents = new float[ModelQuadFacing.DIRECTIONS]; + + // true if one of the extents has more than one plane + private boolean alignedExtentsMultiple = false; + + // the maximum (or minimum for negative directions) of quads with a particular + // facing. (Dot product of the normal with a vertex for all aligned facings) + private float[] alignedExtremes = new float[] { + Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY, + Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY + }; + + // keep track of two normals with each up to two distances for important special + // case heuristics + private int unalignedANormal = -1; + private float unalignedADistance1 = Float.NaN; + private float unalignedADistance2 = Float.NaN; + private int unalignedBNormal = -1; + private float unalignedBDistance1 = Float.NaN; + private float unalignedBDistance2 = Float.NaN; @SuppressWarnings("unchecked") private ReferenceArrayList[] quadLists = new ReferenceArrayList[ModelQuadFacing.COUNT]; @@ -75,8 +97,7 @@ public TranslucentGeometryCollector(ChunkSectionPos sectionPos) { } } - public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] vertices, ModelQuadFacing facing, - boolean flipNormal) { + public void appendQuad(int packedNormal, ChunkVertexEncoder.Vertex[] vertices, ModelQuadFacing facing) { float xSum = 0; float ySum = 0; float zSum = 0; @@ -120,11 +141,6 @@ public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] verti } } - var centerX = xSum / uniqueQuads; - var centerY = ySum / uniqueQuads; - var centerZ = zSum / uniqueQuads; - var center = new Vector3f(centerX, centerY, centerZ); - // shrink quad in non-normal directions to prevent intersections caused by // epsilon offsets applied by FluidRenderer if (facing != ModelQuadFacing.POS_X && facing != ModelQuadFacing.NEG_X) { @@ -149,74 +165,72 @@ public void appendQuad(ModelQuadView quadView, ChunkVertexEncoder.Vertex[] verti } } - if (facing != ModelQuadFacing.UNASSIGNED && this.unalignedDistances == null) { - maxBounds.x = Math.max(maxBounds.x, posXExtent); - maxBounds.y = Math.max(maxBounds.y, posYExtent); - maxBounds.z = Math.max(maxBounds.z, posZExtent); - minBounds.x = Math.min(minBounds.x, negXExtent); - minBounds.y = Math.min(minBounds.y, negYExtent); - minBounds.z = Math.min(minBounds.z, negZExtent); - } - // POS_X, POS_Y, POS_Z, NEG_X, NEG_Y, NEG_Z float[] extents = new float[] { posXExtent, posYExtent, posZExtent, negXExtent, negYExtent, negZExtent }; - // TODO: some of these things should probably only be computed on demand, and an - // allocation of a Quad object should be avoided - AccumulationGroup accGroup; - var quadList = this.quadLists[facing.ordinal()]; + int direction = facing.ordinal(); + var quadList = this.quadLists[direction]; if (quadList == null) { quadList = new ReferenceArrayList<>(); - this.quadLists[facing.ordinal()] = quadList; + this.quadLists[direction] = quadList; + } else if (facing.isAligned()) { + this.alignedExtentsMultiple = true; } - if (facing == ModelQuadFacing.UNASSIGNED) { - int flipFactor = flipNormal ? -1 : 1; - int normalX = flipFactor * quadView.getGFNINormX(); - int normalY = flipFactor * quadView.getGFNINormY(); - int normalZ = flipFactor * quadView.getGFNINormZ(); - - if (this.unalignedDistances == null) { - this.unalignedDistances = new Int2ReferenceLinkedOpenHashMap<>(4); + if (facing.isAligned()) { + // only update global extents if there are no unaligned quads since this is only + // used for the convex box test which doesn't work with unaligned quads anyways + if (!this.hasUnaligned) { + this.extents[0] = Math.max(this.extents[0], posXExtent); + this.extents[1] = Math.max(this.extents[1], posYExtent); + this.extents[2] = Math.max(this.extents[2], posZExtent); + this.extents[3] = Math.min(this.extents[3], negXExtent); + this.extents[4] = Math.min(this.extents[4], negYExtent); + this.extents[5] = Math.min(this.extents[5], negZExtent); } - // the key for the hash map is the normal packed into an int - // the lowest byte is 0xFF to prevent collisions with axis-aligned normals - // (assuming quantization with 32, which is 5 bits per component) - int normalKey = AccumulationGroup.collectorKeyFromNormal(normalX, normalY, normalZ); - accGroup = this.unalignedDistances.get(normalKey); - - if (accGroup == null) { - // actually normalize the vector to ensure it's a unit vector - // for the rest of the process which requires that - Vector3f normal = new Vector3f(normalX, normalY, normalZ); - normal.normalize(); - accGroup = new AccumulationGroup(sectionPos, normal, normalKey); - this.unalignedDistances.put(normalKey, accGroup); - } + var quad = TQuad.fromAligned(facing, extents); + quadList.add(quad); - quadList.add(new TQuad(facing, accGroup.normal, center, extents)); - } else { - if (this.alignedDistances == null) { - this.alignedDistances = new AccumulationGroup[ModelQuadFacing.DIRECTIONS]; + var extreme = this.alignedExtremes[direction]; + var distance = quad.getDotProduct(); + if (facing.getSign() > 1) { + this.alignedExtremes[direction] = Math.max(extreme, distance); + } else { + this.alignedExtremes[direction] = Math.min(extreme, distance); } + } else { + this.hasUnaligned = true; - int quadDirection = facing.ordinal(); - accGroup = this.alignedDistances[quadDirection]; + var centerX = xSum / uniqueQuads; + var centerY = ySum / uniqueQuads; + var centerZ = zSum / uniqueQuads; + var center = new Vector3f(centerX, centerY, centerZ); - if (accGroup == null) { - accGroup = new AccumulationGroup(sectionPos, ModelQuadFacing.NORMALS[quadDirection], quadDirection); - this.alignedDistances[quadDirection] = accGroup; - this.alignedNormalBitmap |= 1 << quadDirection; - } + var quad = TQuad.fromUnaligned(facing, extents, center, packedNormal); + quadList.add(quad); - quadList.add(new TQuad(facing, accGroup.normal, center, extents)); - } - - // use the center here because it's quantized while the vertices themselves - // aren't. If they were to be mixed this would cause issues in the sorting. - if (accGroup.addPlaneMember(centerX, centerY, centerZ)) { - this.facePlaneCount++; + // update the two unaligned normals that are tracked + var distance = quad.getDotProduct(); + if (packedNormal == this.unalignedANormal) { + if (Float.isNaN(this.unalignedADistance1)) { + this.unalignedADistance1 = distance; + } else { + this.unalignedADistance2 = distance; + } + } else if (packedNormal == this.unalignedBNormal) { + if (Float.isNaN(this.unalignedBDistance1)) { + this.unalignedBDistance1 = distance; + } else { + this.unalignedBDistance2 = distance; + } + } else if (this.unalignedANormal == -1) { + this.unalignedANormal = packedNormal; + this.unalignedADistance1 = distance; + } else if (this.unalignedBNormal == -1) { + this.unalignedBNormal = packedNormal; + this.unalignedBDistance1 = distance; + } } } @@ -289,46 +303,69 @@ private static SortType filterSortType(SortType sortType) { */ private SortType sortTypeHeuristic() { SortBehavior sortBehavior = SodiumClientMod.options().performance.sortBehavior; + int alignedNormalCount = Integer.bitCount(this.alignedFacingBitmap); + int alignedPlaneCount = alignedNormalCount; + if (this.alignedExtentsMultiple) { + alignedPlaneCount = 100; + } + + int unalignedPlaneCount = 0; + if (!Float.isNaN(this.unalignedADistance1)) { + unalignedPlaneCount++; + } + if (!Float.isNaN(this.unalignedADistance2)) { + unalignedPlaneCount++; + } + if (!Float.isNaN(this.unalignedBDistance1)) { + unalignedPlaneCount++; + } + if (!Float.isNaN(this.unalignedBDistance2)) { + unalignedPlaneCount++; + } + + int planeCount = alignedPlaneCount + unalignedPlaneCount; + + int unalignedNormalCount = 0; + if (unalignedANormal != -1) { + unalignedNormalCount++; + } + if (unalignedBNormal != -1) { + unalignedNormalCount++; + } + + int normalCount = alignedNormalCount + unalignedNormalCount; // special case A - if (sortBehavior == SortBehavior.OFF || this.facePlaneCount <= 1) { + if (sortBehavior == SortBehavior.OFF || planeCount <= 1) { return SortType.NONE; } - if (this.unalignedDistances == null) { - boolean twoOpposingNormals = this.alignedNormalBitmap == ModelQuadFacing.OPPOSING_X - || this.alignedNormalBitmap == ModelQuadFacing.OPPOSING_Y - || this.alignedNormalBitmap == ModelQuadFacing.OPPOSING_Z; + if (!this.hasUnaligned) { + boolean twoOpposingNormals = this.alignedFacingBitmap == ModelQuadFacing.OPPOSING_X + || this.alignedFacingBitmap == ModelQuadFacing.OPPOSING_Y + || this.alignedFacingBitmap == ModelQuadFacing.OPPOSING_Z; // special case B // if there are just two normals, they are exact opposites of eachother and they // each only have one distance, there is no way to see through one face to the // other. - if (this.facePlaneCount == 2 && twoOpposingNormals) { + if (planeCount == 2 && twoOpposingNormals) { return SortType.NONE; } // special case C // the more complex test that checks for distances aligned with the bounding box - if (this.facePlaneCount <= ModelQuadFacing.DIRECTIONS) { + if (!this.alignedExtentsMultiple) { boolean passesBoundingBoxTest = true; - for (AccumulationGroup accGroup : this.alignedDistances) { - if (accGroup == null) { + for (int direction = 0; direction < ModelQuadFacing.DIRECTIONS; direction++) { + var extreme = this.alignedExtremes[direction]; + if (Float.isInfinite(extreme)) { continue; } - if (accGroup.relativeDistancesSet.size() > 1) { - passesBoundingBoxTest = false; - break; - } - // check the distance against the bounding box - float outwardBoundDistance = (accGroup.normal.x() < 0 - || accGroup.normal.y() < 0 - || accGroup.normal.z() < 0) - ? accGroup.normal.dot(minBounds) - : accGroup.normal.dot(maxBounds); - if (accGroup.relativeDistancesSet.iterator().nextFloat() != outwardBoundDistance) { + var sign = direction < 3 ? 1 : -1; + if (sign * extreme != this.extents[direction]) { passesBoundingBoxTest = false; break; } @@ -342,32 +379,28 @@ private SortType sortTypeHeuristic() { // there are up to two normals that are opposing, this means no dynamic sorting // is necessary. Without static sorting, the geometry to trigger on could be // reduced but this isn't done here as we assume static sorting is possible. - if (twoOpposingNormals || Integer.bitCount(this.alignedNormalBitmap) == 1) { + if (twoOpposingNormals || alignedNormalCount == 1) { return SortType.STATIC_NORMAL_RELATIVE; } - } else if (this.alignedNormalBitmap == 0) { - if (this.unalignedDistances.size() == 1) { - // special case D but for one unaligned normal + } else if (alignedNormalCount == 0) { + // special case D but for one normal or two opposing unaligned normals + if (unalignedNormalCount == 1 + || unalignedNormalCount == 2 && NormI8.isOpposite(this.unalignedANormal, this.unalignedBNormal)) { + return SortType.STATIC_NORMAL_RELATIVE; + } + } else if (planeCount == 2) { // implies normalCount == 2 + // special case D with mixed aligned and unaligned normals + int alignedDirection = Integer.numberOfTrailingZeros(this.alignedFacingBitmap); + if (NormI8.isOpposite(this.unalignedANormal, ModelQuadFacing.PACKED_ALIGNED_NORMALS[alignedDirection])) { return SortType.STATIC_NORMAL_RELATIVE; - } else if (this.unalignedDistances.size() == 2) { - // special case D but for two opposing unaligned normals - var iterator = this.unalignedDistances.values().iterator(); - var normalA = iterator.next().normal; - var normalB = iterator.next().normal; - if (normalA.x() == -normalB.x() - && normalA.y() == -normalB.y() - && normalA.z() == -normalB.z()) { - return SortType.STATIC_NORMAL_RELATIVE; - } } } // use the given set of quad count limits to determine if a static topo sort // should be attempted - var uniqueNormals = Integer.bitCount(this.alignedNormalBitmap) - + (this.unalignedDistances == null ? 0 : this.unalignedDistances.size()); - uniqueNormals = Math.max(Math.min(uniqueNormals, STATIC_TOPO_SORT_ATTEMPT_LIMITS.length - 1), 2); - if (this.quads.length <= STATIC_TOPO_SORT_ATTEMPT_LIMITS[uniqueNormals]) { + + var attemptLimitIndex = Math.max(Math.min(normalCount, STATIC_TOPO_SORT_ATTEMPT_LIMITS.length - 1), 2); + if (this.quads.length <= STATIC_TOPO_SORT_ATTEMPT_LIMITS[attemptLimitIndex]) { return SortType.STATIC_TOPO_ACYCLIC; } @@ -391,7 +424,7 @@ public SortType finishRendering() { } } } - this.quadLists = null; + this.quadLists = null; // not needed anymore this.sortType = filterSortType(sortTypeHeuristic()); return this.sortType; @@ -400,18 +433,19 @@ public SortType finishRendering() { private TranslucentData makeNewTranslucentData(BuiltSectionMeshParts translucentMesh, Vector3fc cameraPos, TranslucentData oldData) { if (this.sortType == SortType.NONE) { - return AnyOrderData.fromMesh(translucentMesh, quads, sectionPos, null); + return AnyOrderData.fromMesh(translucentMesh, this.quads, this.sectionPos, null); } if (this.sortType == SortType.STATIC_NORMAL_RELATIVE) { - return StaticNormalRelativeData.fromMesh(translucentMesh, this.quads, sectionPos, this); + var isDoubleUnaligned = this.alignedFacingBitmap == 0; + return StaticNormalRelativeData.fromMesh(translucentMesh, this.quads, this.sectionPos, isDoubleUnaligned); } // from this point on we know the estimated sort type requires direction mixing // (no backface culling) and all vertices are in the UNASSIGNED direction. NativeBuffer buffer = PresentTranslucentData.nativeBufferForQuads(this.quads); if (this.sortType == SortType.STATIC_TOPO_ACYCLIC) { - var result = StaticTopoAcyclicData.fromMesh(translucentMesh, this.quads, sectionPos, buffer); + var result = StaticTopoAcyclicData.fromMesh(translucentMesh, this.quads, this.sectionPos, buffer); if (result != null) { return result; } @@ -422,16 +456,21 @@ private TranslucentData makeNewTranslucentData(BuiltSectionMeshParts translucent this.sortType = filterSortType(this.sortType); if (this.sortType == SortType.NONE) { - return AnyOrderData.fromMesh(translucentMesh, quads, sectionPos, buffer); + return AnyOrderData.fromMesh(translucentMesh, this.quads, this.sectionPos, buffer); } if (this.sortType == SortType.DYNAMIC_ALL) { try { - return BSPDynamicData.fromMesh(translucentMesh, cameraPos, quads, sectionPos, buffer, oldData); + return BSPDynamicData.fromMesh( + translucentMesh, cameraPos, this.quads, this.sectionPos, + buffer, oldData); } catch (BSPBuildFailureException e) { // TODO: investigate existing BSP build failures, then remove this logging System.out.println("BSP build failure: " + sectionPos); - return TopoSortDynamicData.fromMesh(translucentMesh, cameraPos, quads, sectionPos, this, buffer); + var geometryPlanes = GeometryPlanes.fromQuadLists(sectionPos, this.quads); + return TopoSortDynamicData.fromMesh( + translucentMesh, cameraPos, this.quads, this.sectionPos, + geometryPlanes, buffer); } } @@ -489,32 +528,4 @@ public TranslucentData getTranslucentData( } return newData; } - - @Override - public AccumulationGroup getGroupForUnalignedNormal(NormalList normalList) { - if (this.unalignedDistances == null) { - return null; - } - return this.unalignedDistances.get(normalList.getCollectorKey()); - } - - @Override - public Collection getUnalignedDistances() { - if (this.unalignedDistances == null) { - return null; - } - return this.unalignedDistances.values(); - } - - @Override - public int getUnalignedDistanceCount() { - if (this.unalignedDistances == null) { - return 0; - } - return this.unalignedDistances.size(); - } - - public int getAlignedNormalBitmap() { - return this.alignedNormalBitmap; - } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java index 36c1ec25ca..b6c069280d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java @@ -3,10 +3,10 @@ import org.joml.Vector3fc; import it.unimi.dsi.fastutil.ints.IntArrayList; -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TopoGraphSorting; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TopoGraphSorting; import me.jellysquid.mods.sodium.client.util.NativeBuffer; +import net.caffeinemc.mods.sodium.api.util.NormI8; import net.minecraft.util.math.ChunkSectionPos; /** @@ -49,10 +49,46 @@ public static BSPResult buildBSP(TQuad[] quads, ChunkSectionPos sectionPos, BSPN var rootNode = BSPNode.build(workspace, allIndexes, -1, oldRoot); var result = workspace.result; - result.rootNode = rootNode; + result.setRootNode(rootNode); return result; } + private static boolean doubleLeafPossible(TQuad quadA, TQuad quadB) { + // check for coplanar or mutually invisible quads + var facingA = quadA.getFacing(); + var facingB = quadB.getFacing(); + + // coplanar not aligned + if (!facingA.isAligned() || !facingB.isAligned()) { + var packedNormalA = quadA.getPackedNormal(); + var packedNormalB = quadB.getPackedNormal(); + // opposite normal (distance irrelevant) + if (NormI8.isOpposite(packedNormalA, packedNormalB) + // same normal and same distance + || packedNormalA == packedNormalB && quadA.getDotProduct() == quadB.getDotProduct()) { + return true; + } + } + + // coplanar aligned + else if (quadA.getExtents()[facingA.ordinal()] == quadB.getExtents()[facingB.ordinal()]) { + return true; + } + + // aligned facing away from eachother + else if (facingA == facingB.getOpposite()) { + return true; + } + + // aligned otherwise mutually invisible + else if (!TopoGraphSorting.orthogonalQuadVisibleThrough(quadA, quadB) + && !TopoGraphSorting.orthogonalQuadVisibleThrough(quadB, quadA)) { + return true; + } + + return false; + } + static BSPNode build(BSPWorkspace workspace, IntArrayList indexes, int depth, BSPNode oldNode) { depth++; @@ -67,30 +103,7 @@ static BSPNode build(BSPWorkspace workspace, IntArrayList indexes, int depth, BS var quadA = workspace.quads[quadIndexA]; var quadB = workspace.quads[quadIndexB]; - // check for coplanar or mutually invisible quads - var facingA = quadA.facing(); - var facingB = quadB.facing(); - var normalA = quadA.normal(); - var normalB = quadB.normal(); - if ( - // coplanar quads - ((facingA == ModelQuadFacing.UNASSIGNED || facingB == ModelQuadFacing.UNASSIGNED) - ? // opposite normal (distance irrelevant) - normalA.x() == -normalB.x() - && normalA.y() == -normalB.y() - && normalA.z() == -normalB.z() - // same normal and same distance - || normalA.equals(quadB.normal()) - && normalA.dot(quadA.center()) == quadB.normal().dot(quadB.center()) - // aligned same distance - : quadA.extents()[facingA.ordinal()] == quadB.extents()[facingB.ordinal()]) - // facing away from eachother - || facingA == facingB.getOpposite() - // otherwise mutually invisible - || facingA != ModelQuadFacing.UNASSIGNED - && facingB != ModelQuadFacing.UNASSIGNED - && !TopoGraphSorting.orthogonalQuadVisibleThrough(quadA, quadB) - && !TopoGraphSorting.orthogonalQuadVisibleThrough(quadB, quadA)) { + if (doubleLeafPossible(quadA, quadB)) { return new LeafDoubleBSPNode(quadIndexA, quadIndexB); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPResult.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPResult.java index 476c075385..41affcd52a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPResult.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPResult.java @@ -1,45 +1,15 @@ package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; -import java.util.Collection; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger.GeometryPlanes; -import org.joml.Vector3fc; - -import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.AccGroupResult; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.AccumulationGroup; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.NormalList; - -public class BSPResult extends AccGroupResult { - Object2ReferenceOpenHashMap unalignedDistances; - - BSPNode rootNode; - - @Override - public Collection getUnalignedDistances() { - if (this.unalignedDistances == null) { - return null; - } - return this.unalignedDistances.values(); - } - - @Override - public AccumulationGroup getGroupForUnalignedNormal(NormalList normalList) { - if (this.unalignedDistances == null) { - return null; - } - return this.unalignedDistances.get(normalList.getNormal()); - } - - @Override - public int getUnalignedDistanceCount() { - if (this.unalignedDistances == null) { - return 0; - } - return this.unalignedDistances.size(); - } +public class BSPResult extends GeometryPlanes { + private BSPNode rootNode; public BSPNode getRootNode() { return this.rootNode; } + public void setRootNode(BSPNode rootNode) { + this.rootNode = rootNode; + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java index ae5f580b0b..55ad9d0978 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java @@ -1,8 +1,7 @@ package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.AccumulationGroup; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger.GeometryPlanes; import net.minecraft.util.math.ChunkSectionPos; /** @@ -32,18 +31,10 @@ class BSPWorkspace { // top-level topo sorting isn't used anymore (and only use half as much memory // by not storing it double) void addAlignedPartitionPlane(int axis, float distance) { - var accGroups = result.getAlignedDistancesOrCreate(); - this.addOneSidedPlane(accGroups, axis, distance); - this.addOneSidedPlane(accGroups, axis + 3, -distance); + result.addDoubleSidedPlane(this.sectionPos, axis, distance); } - void addOneSidedPlane(AccumulationGroup[] accGroups, int direction, float distance) { - var accGroup = accGroups[direction]; - if (accGroup == null) { - accGroup = new AccumulationGroup( - this.sectionPos, ModelQuadFacing.NORMALS[direction], direction); - accGroups[direction] = accGroup; - } - accGroup.addPlaneMember(distance); + GeometryPlanes getGeometryPlanes() { + return result; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java index 51ca2a59a2..1fe068595e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java @@ -66,7 +66,7 @@ void collectSortedQuads(BSPSortState sortState, Vector3fc cameraPos) { } } - static BSPNode build(BSPWorkspace workspace, IntArrayList indexes, int depth, BSPNode oldNode, + static BSPNode buildFromPartitions(BSPWorkspace workspace, IntArrayList indexes, int depth, BSPNode oldNode, Partition inside, Partition outside, int axis) { var partitionDistance = inside.distance(); workspace.addAlignedPartitionPlane(axis, partitionDistance); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java index 8c3d10d52e..e72de5111f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java @@ -55,7 +55,7 @@ record NodeReuseData(float[][] quadExtents, int[] indexes, int indexCount, int m } InnerPartitionBSPNode(NodeReuseData reuseData, int axis) { - this.planeNormal = ModelQuadFacing.NORMALS[axis]; + this.planeNormal = ModelQuadFacing.ALIGNED_NORMALS[axis]; this.axis = axis; this.reuseData = reuseData; } @@ -72,7 +72,7 @@ static NodeReuseData prepareNodeReuse(BSPWorkspace workspace, IntArrayList index for (int i = 0; i < indexes.size(); i++) { var index = indexes.getInt(i); var quad = workspace.quads[index]; - var extents = quad.extents(); + var extents = quad.getExtents(); quadExtents[i] = extents; maxIndex = Math.max(maxIndex, index); } @@ -221,7 +221,7 @@ static BSPNode build(BSPWorkspace workspace, IntArrayList indexes, int depth, BS points.clear(); for (int quadIndex : indexes) { var quad = workspace.quads[quadIndex]; - var extents = quad.extents(); + var extents = quad.getExtents(); var posExtent = extents[axis]; var negExtent = extents[oppositeDirection]; if (posExtent == negExtent) { @@ -329,7 +329,7 @@ static BSPNode build(BSPWorkspace workspace, IntArrayList indexes, int depth, BS var inside = partitions.get(0); var outside = partitions.size() == 2 ? partitions.get(1) : null; if (outside == null || !endsWithPlane) { - return InnerBinaryPartitionBSPNode.build(workspace, indexes, depth, oldNode, + return InnerBinaryPartitionBSPNode.buildFromPartitions(workspace, indexes, depth, oldNode, inside, outside, axis); } } @@ -355,8 +355,8 @@ static BSPNode build(BSPWorkspace workspace, IntArrayList indexes, int depth, BS boolean intersects = true; for (int axis = 0; axis < 3; axis++) { var opposite = axis + 3; - var extentsA = quadA.extents(); - var extentsB = quadB.extents(); + var extentsA = quadA.getExtents(); + var extentsB = quadB.getExtents(); if (extentsA[axis] <= extentsB[opposite] || extentsB[axis] <= extentsA[opposite]) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/AnyOrderData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/AnyOrderData.java index 7d22419a77..a32f01ea9b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/AnyOrderData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/AnyOrderData.java @@ -32,9 +32,9 @@ public static AnyOrderData fromMesh(BuiltSectionMeshParts translucentMesh, buffer = PresentTranslucentData.nativeBufferForQuads(buffer, quads); var indexBuffer = buffer.getDirectBuffer().asIntBuffer(); var counter = 0; - var lastFacing = quads[0].facing(); + var lastFacing = quads[0].getFacing(); for (int i = 0; i < quads.length; i++) { - var currentFacing = quads[i].facing(); + var currentFacing = quads[i].getFacing(); if (i > 0 && currentFacing != lastFacing) { counter = 0; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java index 2e62d4ec66..f558856dd1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java @@ -56,23 +56,8 @@ public static BSPDynamicData fromMesh(BuiltSectionMeshParts translucentMesh, var dynamicData = new BSPDynamicData(sectionPos, buffer, range, result, generation); dynamicData.sort(cameraPos); - // prepare accumulation groups for integration into GFNI triggering - var aligned = result.getAlignedDistances(); - if (aligned != null) { - for (var accGroup : aligned) { - if (accGroup != null) { - accGroup.prepareIntegration(); - } - } - } - var unaligned = result.getUnalignedDistances(); - if (unaligned != null) { - for (var accGroup : unaligned) { - if (accGroup != null) { - accGroup.prepareIntegration(); - } - } - } + // prepare geometry planes for integration into GFNI triggering + result.prepareIntegration(); return dynamicData; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicData.java index 41858d714b..a863f90264 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicData.java @@ -1,17 +1,17 @@ package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data; import me.jellysquid.mods.sodium.client.gl.util.VertexRange; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.AccGroupResult; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortType; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger.GeometryPlanes; import me.jellysquid.mods.sodium.client.util.NativeBuffer; import net.minecraft.util.math.ChunkSectionPos; public abstract class DynamicData extends MixedDirectionData { - private AccGroupResult accGroupResult; + private GeometryPlanes geometryPlanes; - DynamicData(ChunkSectionPos sectionPos, NativeBuffer buffer, VertexRange range, AccGroupResult accGroupResult) { + DynamicData(ChunkSectionPos sectionPos, NativeBuffer buffer, VertexRange range, GeometryPlanes geometryPlanes) { super(sectionPos, buffer, range); - this.accGroupResult = accGroupResult; + this.geometryPlanes = geometryPlanes; } @Override @@ -19,11 +19,11 @@ public SortType getSortType() { return SortType.DYNAMIC_ALL; } - public AccGroupResult getAccGroupResult() { - return this.accGroupResult; + public GeometryPlanes getGeometryPlanes() { + return this.geometryPlanes; } - public void clearAccGroupData() { - this.accGroupResult = null; + public void clearGeometryPlanes() { + this.geometryPlanes = null; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java index 1142860d0c..d3ae556171 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java @@ -1,8 +1,7 @@ package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data; import java.nio.IntBuffer; - -import org.joml.Vector3f; +import java.util.Arrays; import com.mojang.blaze3d.systems.VertexSorter; @@ -11,9 +10,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortType; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TranslucentGeometryCollector; import me.jellysquid.mods.sodium.client.util.NativeBuffer; -import me.jellysquid.mods.sodium.client.util.sorting.MergeSort; import me.jellysquid.mods.sodium.client.util.sorting.VertexSorters; import net.minecraft.util.math.ChunkSectionPos; @@ -36,77 +33,61 @@ public SortType getSortType() { } private static StaticNormalRelativeData fromDoubleUnaligned(BuiltSectionMeshParts translucentMesh, - TQuad[] quads, ChunkSectionPos sectionPos, TranslucentGeometryCollector collector) { - VertexRange[] ranges = translucentMesh.getVertexRanges(); - float[] keys = new float[quads.length]; + TQuad[] quads, ChunkSectionPos sectionPos) { + long[] sortData = new long[quads.length]; for (int i = 0; i < quads.length; i++) { - TQuad quad = quads[i]; - keys[i] = quad.center().dot(quad.normal()); + sortData[i] = (long) quads[i].getDotProduct() << 32 | i; } var buffer = PresentTranslucentData.nativeBufferForQuads(quads); IntBuffer bufferBuilder = buffer.getDirectBuffer().asIntBuffer(); - TranslucentData.writeQuadVertexIndexes(bufferBuilder, MergeSort.mergeSort(keys)); + Arrays.sort(sortData); - return new StaticNormalRelativeData(sectionPos, buffer, ranges); + for (int i = 0; i < quads.length; i++) { + TranslucentData.writeQuadVertexIndexes(bufferBuilder, (int) sortData[i]); + } + + return new StaticNormalRelativeData(sectionPos, buffer, translucentMesh.getVertexRanges()); } - private static StaticNormalRelativeData fromAligned(BuiltSectionMeshParts translucentMesh, + private static StaticNormalRelativeData fromMixed(BuiltSectionMeshParts translucentMesh, TQuad[] quads, ChunkSectionPos sectionPos) { - VertexRange[] ranges = translucentMesh.getVertexRanges(); - Vector3f[][] centers = new Vector3f[ModelQuadFacing.COUNT][]; + var ranges = translucentMesh.getVertexRanges(); + long[] sortData = new long[quads.length]; - for (int i = 0; i < ModelQuadFacing.COUNT; i++) { - VertexRange range = ranges[i]; - if (range != null) { - centers[i] = new Vector3f[range.vertexCount() / TranslucentData.VERTICES_PER_QUAD]; - } - } - - int centerCounter = 0; - for (TQuad quad : quads) { - var directionCenters = centers[quad.facing().ordinal()]; - directionCenters[centerCounter++] = quad.center(); - - if (centerCounter == directionCenters.length) { - centerCounter = 0; - } + for (int quadIndex = 0; quadIndex < quads.length; quadIndex++) { + var quad = quads[quadIndex]; + sortData[quadIndex] = (long) quad.getDotProduct() << 32 | quadIndex; } var buffer = PresentTranslucentData.nativeBufferForQuads(quads); IntBuffer bufferBuilder = buffer.getDirectBuffer().asIntBuffer(); - // in this case there can only be up to one unaligned normal. - // since the quads are sorted by facing, it will be at the end if it exists - Vector3f unalignedNormal = new Vector3f(quads[quads.length - 1].normal()); - - for (int i = 0; i < ModelQuadFacing.COUNT; i++) { - var range = ranges[i]; + for (var range : ranges) { if (range != null) { - VertexSorter sorter; - if (i == ModelQuadFacing.UNASSIGNED.ordinal()) { - sorter = VertexSorters.sortByNormalRelative(unalignedNormal); - } else { - sorter = SORTERS[i]; + int start = TranslucentData.vertexCountToQuadCount(range.vertexStart()); + int count = TranslucentData.vertexCountToQuadCount(range.vertexCount()); + if (count > 1) { + Arrays.sort(sortData, start, start + count); } - - // add the vertex start converted to quads to the offset to get the real quad - // index and not just the index local to the direction's set of quads - TranslucentData.writeQuadVertexIndexes(bufferBuilder, sorter.sort(centers[i])); } } + for (int i = 0; i < quads.length; i++) { + TranslucentData.writeQuadVertexIndexes(bufferBuilder, (int) sortData[i]); + } + return new StaticNormalRelativeData(sectionPos, buffer, ranges); } public static StaticNormalRelativeData fromMesh(BuiltSectionMeshParts translucentMesh, - TQuad[] quads, ChunkSectionPos sectionPos, TranslucentGeometryCollector collector) { - if (collector.getAlignedNormalBitmap() == 0) { - return fromDoubleUnaligned(translucentMesh, quads, sectionPos, collector); + TQuad[] quads, ChunkSectionPos sectionPos, boolean isDoubleUnaligned) { + if (isDoubleUnaligned) { + return fromDoubleUnaligned(translucentMesh, quads, sectionPos); } else { - return fromAligned(translucentMesh, quads, sectionPos); + return fromMixed(translucentMesh, quads, sectionPos); } } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticTopoAcyclicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticTopoAcyclicData.java index 8b74aeec5b..29837f67bd 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticTopoAcyclicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticTopoAcyclicData.java @@ -4,7 +4,6 @@ import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortType; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TopoGraphSorting; import me.jellysquid.mods.sodium.client.util.NativeBuffer; import net.minecraft.util.math.ChunkSectionPos; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TopoGraphSorting.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoGraphSorting.java similarity index 86% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TopoGraphSorting.java rename to src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoGraphSorting.java index c9ed2c2b13..dd21243d7f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TopoGraphSorting.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoGraphSorting.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data; import java.nio.IntBuffer; @@ -6,7 +6,8 @@ import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.AlignableNormal; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; import me.jellysquid.mods.sodium.client.util.collections.BitArray; /** @@ -22,12 +23,6 @@ public class TopoGraphSorting { private TopoGraphSorting() { } - private static float halfspace(Vector3fc planeAnchor, Vector3fc planeNormal, Vector3fc point) { - return (point.x() - planeAnchor.x()) * planeNormal.x() + - (point.y() - planeAnchor.y()) * planeNormal.y() + - (point.z() - planeAnchor.z()) * planeNormal.z(); - } - /** * Test if the given point is within the half space defined by the plane anchor * and the plane normal. The normal points away from the space considered to be @@ -37,25 +32,25 @@ private static float halfspace(Vector3fc planeAnchor, Vector3fc planeNormal, Vec * @param planeNormal the normal of the plane * @param point the point to test */ - private static boolean pointOutsideHalfspace(Vector3fc planeAnchor, Vector3fc planeNormal, Vector3fc point) { - return halfspace(planeAnchor, planeNormal, point) > 0; + private static boolean pointOutsideHalfspace(float planeDistance, Vector3fc planeNormal, Vector3fc point) { + return planeNormal.dot(point) > planeDistance; } - private static boolean pointInsideHalfSpace(Vector3fc planeAnchor, Vector3fc planeNormal, Vector3fc point) { - return halfspace(planeAnchor, planeNormal, point) < 0; + private static boolean pointInsideHalfSpace(float planeDistance, Vector3fc planeNormal, Vector3fc point) { + return planeNormal.dot(point) < planeDistance; } public static boolean orthogonalQuadVisibleThrough(TQuad halfspace, TQuad otherQuad) { - var hd = halfspace.facing().ordinal(); - var hdOpposite = halfspace.facing().getOpposite().ordinal(); - var od = otherQuad.facing().ordinal(); - var hSign = halfspace.facing().getSign(); - var otherSign = otherQuad.facing().getSign(); + var hd = halfspace.getFacing().ordinal(); + var hdOpposite = halfspace.getFacing().getOpposite().ordinal(); + var od = otherQuad.getFacing().ordinal(); + var hSign = halfspace.getFacing().getSign(); + var otherSign = otherQuad.getFacing().getSign(); // A: test that the other quad has an extent within this quad's halfspace - return hSign * halfspace.extents()[hd] > hSign * otherQuad.extents()[hdOpposite] + return hSign * halfspace.getExtents()[hd] > hSign * otherQuad.getExtents()[hdOpposite] // B: test that this quad is not fully within the other quad's halfspace - && !(otherSign * otherQuad.extents()[od] >= otherSign * halfspace.extents()[od]); + && !(otherSign * otherQuad.getExtents()[od] >= otherSign * halfspace.getExtents()[od]); } private static boolean testSeparatorRange(Object2ReferenceOpenHashMap distancesByNormal, @@ -64,7 +59,7 @@ private static boolean testSeparatorRange(Object2ReferenceOpenHashMap separatorRangeEnd) { continue; } // test that the camera doesn't exclude all separators - var facingNormal = ModelQuadFacing.NORMALS[direction]; + var facingNormal = ModelQuadFacing.ALIGNED_NORMALS[direction]; var cameraDistance = facingNormal.dot(cameraPos); if (cameraDistance > separatorRangeEnd) { continue; @@ -137,8 +132,8 @@ private static boolean quadVisibleThrough(TQuad quad, TQuad other, } // aligned quads - var quadFacing = quad.facing(); - var otherFacing = other.facing(); + var quadFacing = quad.getFacing(); + var otherFacing = other.getFacing(); boolean result; if (quadFacing != ModelQuadFacing.UNASSIGNED && otherFacing != ModelQuadFacing.UNASSIGNED) { // opposites never see eachother @@ -150,7 +145,7 @@ private static boolean quadVisibleThrough(TQuad quad, TQuad other, if (quadFacing == otherFacing) { var sign = quadFacing.getSign(); var direction = quadFacing.ordinal(); - result = sign * quad.extents()[direction] > sign * other.extents()[direction]; + result = sign * quad.getExtents()[direction] > sign * other.getExtents()[direction]; } else { // orthogonal quads result = orthogonalQuadVisibleThrough(quad, other); @@ -160,8 +155,8 @@ private static boolean quadVisibleThrough(TQuad quad, TQuad other, // this is an approximation since our quads don't store all their vertices. // check that other center is within the halfspace of quad and that quad isn't // in the halfspace of other - result = pointInsideHalfSpace(quad.center(), quad.normal(), other.center()) - && !pointInsideHalfSpace(other.center(), other.normal(), quad.center()); + result = pointInsideHalfSpace(quad.getDotProduct(), quad.getQuantizedNormal(), other.getCenter()) + && !pointInsideHalfSpace(other.getDotProduct(), other.getQuantizedNormal(), quad.getCenter()); } // if enabled and necessary, try to disprove this see-through relationship with @@ -205,7 +200,7 @@ public static boolean topoSortDepthFirstCyclic( // TODO: this could introduce wrong sorting if the real normal and the quantized // normal don't line up, ignoring the quad if it's not visible through the // quantized one but visible in-camera - if (pointOutsideHalfspace(quad.center(), quad.normal(), cameraPos)) { + if (pointOutsideHalfspace(quad.getDotProduct(), quad.getQuantizedNormal(), cameraPos)) { activeToRealIndex[activeQuads] = i; quads[activeQuads] = quad; activeQuads++; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java index 94a565d533..a76e513924 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java @@ -9,8 +9,7 @@ import me.jellysquid.mods.sodium.client.gl.util.VertexRange; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TopoGraphSorting; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TranslucentGeometryCollector; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger.GeometryPlanes; import me.jellysquid.mods.sodium.client.util.NativeBuffer; import net.minecraft.util.math.ChunkSectionPos; @@ -42,9 +41,9 @@ public class TopoSortDynamicData extends DynamicData { private TopoSortDynamicData(ChunkSectionPos sectionPos, NativeBuffer buffer, VertexRange range, TQuad[] quads, - TranslucentGeometryCollector collector, + GeometryPlanes geometryPlanes, Object2ReferenceOpenHashMap distancesByNormal) { - super(sectionPos, buffer, range, collector); + super(sectionPos, buffer, range, geometryPlanes); this.quads = quads; this.distancesByNormal = distancesByNormal; } @@ -183,7 +182,7 @@ private void sort(Vector3fc cameraPos, boolean isAngleTrigger, boolean initial) private static void distanceSortDirect(IntBuffer indexBuffer, TQuad[] quads, Vector3fc cameraPos) { var data = new long[quads.length]; for (int i = 0; i < quads.length; i++) { - float distance = cameraPos.distanceSquared(quads[i].center()); + float distance = cameraPos.distanceSquared(quads[i].getCenter()); data[i] = (long) Float.floatToRawIntBits(distance) << 32 | i; } @@ -195,31 +194,16 @@ private static void distanceSortDirect(IntBuffer indexBuffer, TQuad[] quads, Vec } public static TopoSortDynamicData fromMesh(BuiltSectionMeshParts translucentMesh, - Vector3fc cameraPos, TQuad[] quads, ChunkSectionPos sectionPos, TranslucentGeometryCollector collector, + Vector3fc cameraPos, TQuad[] quads, ChunkSectionPos sectionPos, GeometryPlanes geometryPlanes, NativeBuffer buffer) { - // prepare accumulation groups for GFNI integration and copy - var size = Integer.bitCount(collector.getAlignedNormalBitmap()) + collector.getUnalignedDistanceCount(); - - var distancesByNormal = new Object2ReferenceOpenHashMap(size); - if (collector.getAlignedDistances() != null) { - for (var accGroup : collector.getAlignedDistances()) { - if (accGroup != null) { - accGroup.prepareAndInsert(distancesByNormal); - } - } - } - if (collector.getUnalignedDistanceCount() > 0) { - for (var accGroup : collector.getUnalignedDistances()) { - accGroup.prepareAndInsert(distancesByNormal); - } - } + var distancesByNormal = geometryPlanes.prepareAndGetDistances(); VertexRange range = TranslucentData.getUnassignedVertexRange(translucentMesh); if (buffer == null) { buffer = PresentTranslucentData.nativeBufferForQuads(quads); } - var dynamicData = new TopoSortDynamicData(sectionPos, buffer, range, quads, collector, distancesByNormal); + var dynamicData = new TopoSortDynamicData(sectionPos, buffer, range, quads, geometryPlanes, distancesByNormal); dynamicData.sort(cameraPos, false, true); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TranslucentData.java index 41324d7fff..b3c36bc87d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TranslucentData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TranslucentData.java @@ -50,6 +50,10 @@ public static int vertexCountToIndexBytes(int vertexCount) { return vertexCount / VERTICES_PER_QUAD * BYTES_PER_QUAD; } + public static int vertexCountToQuadCount(int vertexCount) { + return vertexCount / VERTICES_PER_QUAD; + } + public static int quadCountToIndexBytes(int quadCount) { return quadCount * BYTES_PER_QUAD; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/CameraMovement.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/CameraMovement.java similarity index 90% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/CameraMovement.java rename to src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/CameraMovement.java index 9c678c40ed..8a07580b31 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/CameraMovement.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/CameraMovement.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger; import org.joml.Vector3dc; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/DirectTriggers.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/DirectTriggers.java similarity index 99% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/DirectTriggers.java rename to src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/DirectTriggers.java index 727719b46b..b622ba87a4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/DirectTriggers.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/DirectTriggers.java @@ -1,12 +1,12 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger; import org.joml.Vector3d; import org.joml.Vector3dc; import it.unimi.dsi.fastutil.doubles.Double2ObjectRBTreeMap; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TranslucentSorting.SectionTriggers; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TopoSortDynamicData; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger.TranslucentSorting.SectionTriggers; import net.minecraft.util.math.ChunkSectionPos; /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/GFNITriggers.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GFNITriggers.java similarity index 77% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/GFNITriggers.java rename to src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GFNITriggers.java index b15517388d..079107d75d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/GFNITriggers.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GFNITriggers.java @@ -1,12 +1,12 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger; import org.joml.Vector3dc; import org.joml.Vector3fc; import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TranslucentSorting.SectionTriggers; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.DynamicData; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger.TranslucentSorting.SectionTriggers; import net.minecraft.util.math.ChunkSectionPos; /** @@ -34,13 +34,13 @@ public void processTriggers(TranslucentSorting ts, CameraMovement movement) { } } - private void addSectionInNewNormalLists(DynamicData dynamicData, AccumulationGroup accGroup) { - var normal = accGroup.normal; + private void addSectionInNewNormalLists(DynamicData dynamicData, NormalPlanes normalPlanes) { + var normal = normalPlanes.normal; var normalList = this.normalLists.get(normal); if (normalList == null) { - normalList = new NormalList(normal, accGroup.collectorKey); + normalList = new NormalList(normal); this.normalLists.put(normal, normalList); - normalList.addSection(accGroup, accGroup.sectionPos.asLong()); + normalList.addSection(normalPlanes, normalPlanes.sectionPos.asLong()); } } @@ -69,7 +69,7 @@ public void removeSection(long sectionPos, TranslucentData data) { @Override public void addSection(ChunkSectionPos pos, DynamicData data, Vector3dc cameraPos) { long sectionPos = pos.asLong(); - var accGroupResult = data.getAccGroupResult(); + var geometryPlanes = data.getGeometryPlanes(); // go through all normal lists and check against the normals that the group // builder has. if the normal list has data for the section, but the group @@ -79,17 +79,17 @@ public void addSection(ChunkSectionPos pos, DynamicData data, Vector3dc cameraPo var normalList = iterator.next(); // check if the geometry collector includes data for this normal. - var accGroup = accGroupResult.getGroupForNormal(normalList); + var normalPlanes = geometryPlanes.getPlanesForNormal(normalList); if (normalList.hasSection(sectionPos)) { - if (accGroup == null) { + if (normalPlanes == null) { if (this.removeSectionFromList(normalList, sectionPos)) { iterator.remove(); } } else { - normalList.updateSection(accGroup, sectionPos); + normalList.updateSection(normalPlanes, sectionPos); } - } else if (accGroup != null) { - normalList.addSection(accGroup, sectionPos); + } else if (normalPlanes != null) { + normalList.addSection(normalPlanes, sectionPos); } } @@ -97,21 +97,21 @@ public void addSection(ChunkSectionPos pos, DynamicData data, Vector3dc cameraPo // normals // for which there are no normal lists yet. This only checks for new normal // lists since new data for existing normal lists is handled above. - var aligned = accGroupResult.getAlignedDistances(); + var aligned = geometryPlanes.getAligned(); if (aligned != null) { - for (var accGroup : aligned) { - if (accGroup != null) { - this.addSectionInNewNormalLists(data, accGroup); + for (var normalPlane : aligned) { + if (normalPlane != null) { + this.addSectionInNewNormalLists(data, normalPlane); } } } - var unaligned = accGroupResult.getUnalignedDistances(); + var unaligned = geometryPlanes.getUnaligned(); if (unaligned != null) { - for (var accGroup : unaligned) { - this.addSectionInNewNormalLists(data, accGroup); + for (var normalPlane : unaligned) { + this.addSectionInNewNormalLists(data, normalPlane); } } - data.clearAccGroupData(); + data.clearGeometryPlanes(); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GeometryPlanes.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GeometryPlanes.java new file mode 100644 index 0000000000..5d51a23ddc --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GeometryPlanes.java @@ -0,0 +1,129 @@ +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger; + +import java.util.Collection; + +import org.joml.Vector3fc; + +import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; +import net.minecraft.util.math.ChunkSectionPos; + +public class GeometryPlanes { + private NormalPlanes[] alignedDistances; + private Object2ReferenceOpenHashMap unalignedDistances; + + public NormalPlanes[] getAligned() { + return this.alignedDistances; + } + + public NormalPlanes[] getAlignedOrCreate() { + if (this.alignedDistances == null) { + this.alignedDistances = new NormalPlanes[ModelQuadFacing.DIRECTIONS]; + } + return this.alignedDistances; + } + + public Collection getUnaligned() { + if (this.unalignedDistances == null) { + return null; + } + return this.unalignedDistances.values(); + } + + public Object2ReferenceOpenHashMap getUnalignedOrCreate() { + if (this.unalignedDistances == null) { + this.unalignedDistances = new Object2ReferenceOpenHashMap<>(); + } + return this.unalignedDistances; + } + + public Collection getUnalignedNormals() { + if (this.unalignedDistances == null) { + return null; + } + return this.unalignedDistances.keySet(); + } + + NormalPlanes getPlanesForNormal(NormalList normalList) { + var normal = normalList.getNormal(); + if (normal.isAligned()) { + if (this.alignedDistances == null) { + return null; + } + return this.alignedDistances[normal.getAlignedDirection()]; + } else { + if (this.unalignedDistances == null) { + return null; + } + return this.unalignedDistances.get(normal); + } + } + + public void addAlignedPlane(ChunkSectionPos sectionPos, int direction, float distance) { + var alignedDistances = this.getAlignedOrCreate(); + var normalPlanes = alignedDistances[direction]; + if (normalPlanes == null) { + normalPlanes = new NormalPlanes(sectionPos, direction); + alignedDistances[direction] = normalPlanes; + } + normalPlanes.addPlaneMember(distance); + } + + public void addDoubleSidedPlane(ChunkSectionPos sectionPos, int axis, float distance) { + this.addAlignedPlane(sectionPos, axis, distance); + this.addAlignedPlane(sectionPos, axis + 3, -distance); + } + + public void addUnalignedPlane(ChunkSectionPos sectionPos, Vector3fc normal, float distance) { + var unalignedDistances = this.getUnalignedOrCreate(); + var normalPlanes = unalignedDistances.get(normal); + if (normalPlanes == null) { + normalPlanes = new NormalPlanes(sectionPos, normal); + unalignedDistances.put(normal, normalPlanes); + } + normalPlanes.addPlaneMember(distance); + } + + public void addQuadPlane(ChunkSectionPos sectionPos, TQuad quad) { + var facing = quad.getFacing(); + if (facing.isAligned()) { + this.addAlignedPlane(sectionPos, facing.ordinal(), quad.getDotProduct()); + } else { + this.addUnalignedPlane(sectionPos, quad.getQuantizedNormal(), quad.getDotProduct()); + } + } + + private void prepareAndInsert(Object2ReferenceOpenHashMap distancesByNormal) { + if (this.alignedDistances != null) { + for (var normalPlanes : this.alignedDistances) { + if (normalPlanes != null) { + normalPlanes.prepareAndInsert(distancesByNormal); + } + } + } + if (this.unalignedDistances != null) { + for (var normalPlanes : this.unalignedDistances.values()) { + normalPlanes.prepareAndInsert(distancesByNormal); + } + } + } + + public void prepareIntegration() { + this.prepareAndInsert(null); + } + + public Object2ReferenceOpenHashMap prepareAndGetDistances() { + var distancesByNormal = new Object2ReferenceOpenHashMap(10); + this.prepareAndInsert(distancesByNormal); + return distancesByNormal; + } + + public static GeometryPlanes fromQuadLists(ChunkSectionPos sectionPos, TQuad[] quads) { + var geometryPlanes = new GeometryPlanes(); + for (var quad : quads) { + geometryPlanes.addQuadPlane(sectionPos, quad); + } + return geometryPlanes; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/Group.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/Group.java similarity index 50% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/Group.java rename to src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/Group.java index 0292452e63..a39cde8520 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/Group.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/Group.java @@ -1,8 +1,8 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger; import com.lodborg.intervaltree.DoubleInterval; -import it.unimi.dsi.fastutil.floats.FloatArrays; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.AlignableNormal; /** * A group represents a set of face planes of the same normal within a section. @@ -36,50 +36,29 @@ class Group { double baseDistance; - Group(AccumulationGroup accGroup) { - this.replaceWith(accGroup); - } + AlignableNormal normal; - void replaceWith(AccumulationGroup accGroup) { - this.sectionPos = accGroup.sectionPos.asLong(); - this.distances = accGroup.distanceRange; - this.relDistanceHash = accGroup.relDistanceHash; - this.facePlaneDistances = accGroup.relativeDistances; - this.baseDistance = accGroup.baseDistance; + Group(NormalPlanes normalPlanes) { + this.replaceWith(normalPlanes); } - public static boolean queryRange(float[] sortedDistances, float start, float end) { - // test that there is actually an entry in the query range - int result = FloatArrays.binarySearch(sortedDistances, start); - if (result < 0) { - // recover the insertion point - int insertionPoint = -result - 1; - if (insertionPoint >= sortedDistances.length) { - // no entry in the query range - return false; - } - - // check if the entry at the insertion point, which is the next one greater than - // the start value, is less than or equal to the end value - if (sortedDistances[insertionPoint] <= end) { - // there is an entry in the query range - return true; - } - } else { - // exact match, trigger - return true; - } - return false; + void replaceWith(NormalPlanes normalPlanes) { + this.sectionPos = normalPlanes.sectionPos.asLong(); + this.distances = normalPlanes.distanceRange; + this.relDistanceHash = normalPlanes.relDistanceHash; + this.facePlaneDistances = normalPlanes.relativeDistances; + this.baseDistance = normalPlanes.baseDistance; + this.normal = normalPlanes.normal; } - void triggerRange(TranslucentSorting ts, double start, double end, int collectorKey) { + void triggerRange(TranslucentSorting ts, double start, double end) { // trigger self on the section if the query range overlaps with the group // testing for strict inequality because if the two intervals just touch at the // start/end, there can be no overlap if (start < this.distances.getEnd() && end > this.distances.getStart() - && queryRange(this.facePlaneDistances, + && AlignableNormal.queryRange(this.facePlaneDistances, (float) (start - this.baseDistance), (float) (end - this.baseDistance))) { - ts.triggerSectionGFNI(this.sectionPos, collectorKey); + ts.triggerSectionGFNI(this.sectionPos, this.normal); } } @@ -93,9 +72,9 @@ && queryRange(this.facePlaneDistances, * TODO: how common are collisions and are they bad? * If they are common, use second hash */ - boolean equalsAccGroup(AccumulationGroup accGroup) { - return this.facePlaneDistances.length == accGroup.relativeDistancesSet.size() - && this.distances.equals(accGroup.distanceRange) - && this.relDistanceHash == accGroup.relDistanceHash; + boolean equalsNOrmalPlanes(NormalPlanes normalPlanes) { + return this.facePlaneDistances.length == normalPlanes.relativeDistancesSet.size() + && this.distances.equals(normalPlanes.distanceRange) + && this.relDistanceHash == normalPlanes.relDistanceHash; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/NormalList.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalList.java similarity index 79% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/NormalList.java rename to src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalList.java index 6cc6ce1f12..97d75f6eaa 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/NormalList.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalList.java @@ -1,10 +1,8 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger; import java.util.Collection; -import org.joml.Vector3d; import org.joml.Vector3dc; -import org.joml.Vector3fc; import com.lodborg.intervaltree.DoubleInterval; import com.lodborg.intervaltree.Interval; @@ -15,6 +13,7 @@ import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; import it.unimi.dsi.fastutil.objects.ReferenceArraySet; import it.unimi.dsi.fastutil.objects.ReferenceLinkedOpenHashSet; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.AlignableNormal; /** * A normal list contains all the face planes that have the same normal. @@ -35,18 +34,7 @@ public class NormalList { /** * The normal of this normal list. */ - private final Vector3dc normal; - private final Vector3fc normalf; - - /** - * If this normal list is for an axis-aligned normal, this is the index of it - * for querying in - * {@link TranslucentGeometryCollector#getGroupForNormal(Vector3fc)}. - * - * If this normal list is for an unaligned normal, this is the key for the - * hash map of quantized normals. - */ - private final int collectorKey; + private final AlignableNormal normal; /** * An interval tree of group intervals. Since this only stores intervals, the @@ -73,24 +61,24 @@ public class NormalList { * @param normal The unit normal vector * @param collectorKey The geometry collector index */ - NormalList(Vector3fc normal, int collectorKey) { - this.normalf = normal; - this.normal = new Vector3d(normal); - this.collectorKey = collectorKey; + NormalList(AlignableNormal normal) { + this.normal = normal; } - public Vector3fc getNormal() { - return normalf; + public AlignableNormal getNormal() { + return this.normal; } - int getCollectorKey() { - return collectorKey; + private double normalDotDouble(Vector3dc v) { + return Math.fma((double) this.normal.x, v.x(), + Math.fma((double) this.normal.y, v.y(), + (double) this.normal.z * v.z())); } void processMovement(TranslucentSorting ts, CameraMovement movement) { // calculate the distance range of the movement with respect to the normal - double start = this.normal.dot(movement.lastCamera()); - double end = this.normal.dot(movement.currentCamera()); + double start = this.normalDotDouble(movement.lastCamera()); + double end = this.normalDotDouble(movement.currentCamera()); // stop if the movement is reverse with regards to the normal // since this means it's moving against the normal @@ -103,7 +91,7 @@ void processMovement(TranslucentSorting ts, CameraMovement movement) { var interval = new DoubleInterval(start, end, Bounded.CLOSED); for (Interval groupInterval : intervalTree.query(interval)) { for (Group group : groupsByInterval.get(groupInterval)) { - group.triggerRange(ts, start, end, this.collectorKey); + group.triggerRange(ts, start, end); } } } @@ -147,8 +135,8 @@ boolean isEmpty() { return this.groupsBySection.isEmpty(); } - void addSection(AccumulationGroup accGroup, long sectionPos) { - var group = new Group(accGroup); + void addSection(NormalPlanes normalPlanes, long sectionPos) { + var group = new Group(normalPlanes); this.groupsBySection.put(sectionPos, group); this.addGroupInterval(group); @@ -161,17 +149,17 @@ void removeSection(long sectionPos) { } } - void updateSection(AccumulationGroup accGroup, long sectionPos) { + void updateSection(NormalPlanes normalPlanes, long sectionPos) { Group group = this.groupsBySection.get(sectionPos); // only update on changes to translucent geometry - if (group.equalsAccGroup(accGroup)) { + if (group.equalsNOrmalPlanes(normalPlanes)) { // don't update if they are the same return; } this.removeGroupInterval(group); - group.replaceWith(accGroup); + group.replaceWith(normalPlanes); this.addGroupInterval(group); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AccumulationGroup.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalPlanes.java similarity index 75% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AccumulationGroup.java rename to src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalPlanes.java index 062186f411..555c85f50b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AccumulationGroup.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalPlanes.java @@ -1,19 +1,19 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger; import org.joml.Vector3fc; +import java.util.Arrays; import com.lodborg.intervaltree.DoubleInterval; import com.lodborg.intervaltree.Interval.Bounded; -import it.unimi.dsi.fastutil.floats.FloatArrays; import it.unimi.dsi.fastutil.floats.FloatOpenHashSet; import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.AlignableNormal; import net.minecraft.util.math.ChunkSectionPos; -public class AccumulationGroup { +public class NormalPlanes { final FloatOpenHashSet relativeDistancesSet = new FloatOpenHashSet(16); - final Vector3fc normal; - final int collectorKey; + final AlignableNormal normal; final ChunkSectionPos sectionPos; float[] relativeDistances; // relative to the base distance @@ -21,14 +21,17 @@ public class AccumulationGroup { long relDistanceHash; double baseDistance; - static int collectorKeyFromNormal(int normalX, int normalY, int normalZ) { - return 0xFF | (normalX & 0xFF << 8) | (normalY & 0xFF << 15) | (normalZ & 0xFF << 22); - } - - public AccumulationGroup(ChunkSectionPos sectionPos, Vector3fc normal, int collectorKey) { + private NormalPlanes(ChunkSectionPos sectionPos, AlignableNormal normal) { this.sectionPos = sectionPos; this.normal = normal; - this.collectorKey = collectorKey; + } + + public NormalPlanes(ChunkSectionPos sectionPos, Vector3fc normal) { + this(sectionPos, AlignableNormal.fromUnaligned(normal)); + } + + public NormalPlanes(ChunkSectionPos sectionPos, int alignedDirection) { + this(sectionPos, AlignableNormal.fromAligned(alignedDirection)); } boolean addPlaneMember(float vertexX, float vertexY, float vertexZ) { @@ -57,7 +60,7 @@ public void prepareIntegration() { } // sort the array ascending - FloatArrays.quickSort(relativeDistances); + Arrays.sort(relativeDistances); this.baseDistance = this.normal.dot( sectionPos.getMinX(), sectionPos.getMinY(), sectionPos.getMinZ()); @@ -65,11 +68,12 @@ public void prepareIntegration() { this.relativeDistances[0] + this.baseDistance, this.relativeDistances[size - 1] + this.baseDistance, Bounded.CLOSED); - } public void prepareAndInsert(Object2ReferenceOpenHashMap distancesByNormal) { this.prepareIntegration(); - distancesByNormal.put(this.normal, this.relativeDistances); + if (distancesByNormal != null) { + distancesByNormal.put(this.normal, this.relativeDistances); + } } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentSorting.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/TranslucentSorting.java similarity index 90% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentSorting.java rename to src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/TranslucentSorting.java index 8bcd7024eb..cf356fca59 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentSorting.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/TranslucentSorting.java @@ -1,11 +1,13 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger; import java.util.List; import java.util.function.BiConsumer; import org.joml.Vector3dc; -import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.AlignableNormal; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortType; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.DynamicData; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TopoSortDynamicData; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; @@ -24,16 +26,6 @@ * @author douira (the translucent_sorting package) */ public class TranslucentSorting { - /** - * The quantization factor with which the normals are quantized such that there - * are fewer possible unique normals. The factor describes the number of steps - * in each direction per dimension that the components of the normals can have. - * It determines the density of the grid on the surface of a unit cube centered - * at the origin onto which the normals are projected. The normals are snapped - * to the nearest grid point. - */ - public static final int QUANTIZATION_FACTOR = 4; - /** * To avoid generating a collection of the triggered sections, this callback is * used to process the triggered sections directly as they are queried from the @@ -48,7 +40,7 @@ public class TranslucentSorting { */ private int gfniTriggerCount = 0; private int directTriggerCount = 0; - private final IntOpenHashSet triggeredNormals = new IntOpenHashSet(); + private final ObjectOpenHashSet triggeredNormals = new ObjectOpenHashSet<>(); private int triggeredNormalCount = 0; /** @@ -99,8 +91,8 @@ public void triggerSections(BiConsumer triggerSectionCallback, Ca triggerSectionCallback = null; } - void triggerSectionGFNI(long sectionPos, int collectorKey) { - this.triggeredNormals.add(collectorKey); + void triggerSectionGFNI(long sectionPos, AlignableNormal normal) { + this.triggeredNormals.add(normal); this.triggerSectionCallback.accept(sectionPos, false); this.gfniTriggerCount++; } @@ -176,7 +168,7 @@ public void integrateTranslucentData(TranslucentData oldData, TranslucentData ne } else { // remove the trigger data since this section is never going to get gfni // triggering (there's no option to add sections to GFNI later currently) - topoSortData.clearAccGroupData(); + topoSortData.clearGeometryPlanes(); } if (topoSortData.directTriggerEnabled()) { this.direct.addSection(pos, topoSortData, cameraPos); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/ModelQuadUtil.java b/src/main/java/me/jellysquid/mods/sodium/client/util/ModelQuadUtil.java index 33d207d1a7..8fa692bea4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/ModelQuadUtil.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/ModelQuadUtil.java @@ -1,10 +1,5 @@ package me.jellysquid.mods.sodium.client.util; -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; -import net.caffeinemc.mods.sodium.api.util.NormI8; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.MathHelper; -import org.joml.Vector3f; /** * Provides some utilities and constants for interacting with vanilla's model quad vertex format. @@ -38,34 +33,4 @@ public class ModelQuadUtil { public static int vertexOffset(int vertexIndex) { return vertexIndex * VERTEX_SIZE; } - - public static ModelQuadFacing findNormalFace(float x, float y, float z) { - Vector3f normal = new Vector3f(x, y, z); - - if (!normal.isFinite()) { - return ModelQuadFacing.UNASSIGNED; - } - - float maxDot = 0; - Direction closestFace = null; - - for (Direction face : DirectionUtil.ALL_DIRECTIONS) { - float dot = normal.dot(face.getUnitVector()); - - if (dot > maxDot) { - maxDot = dot; - closestFace = face; - } - } - - if (closestFace != null && MathHelper.approximatelyEquals(maxDot, 1.0f)) { - return ModelQuadFacing.fromDirection(closestFace); - } - - return ModelQuadFacing.UNASSIGNED; - } - - public static ModelQuadFacing findNormalFace(int normal) { - return findNormalFace(NormI8.unpackX(normal), NormI8.unpackY(normal), NormI8.unpackZ(normal)); - } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/MergeSort.java b/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/MergeSort.java index abd9b4d07e..51980cdbee 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/MergeSort.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/MergeSort.java @@ -43,7 +43,7 @@ public static int[] mergeSort(float[] keys) { return indices; } - public static void mergeSort(final int[] indices, final float[] keys) { + private static void mergeSort(final int[] indices, final float[] keys) { mergeSort(indices, keys, 0, indices.length, null); } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/model/quad/BakedQuadMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/model/quad/BakedQuadMixin.java index 356e629fab..2d12815b5f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/model/quad/BakedQuadMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/core/model/quad/BakedQuadMixin.java @@ -43,20 +43,14 @@ public class BakedQuadMixin implements BakedQuadView { @Unique private int normal; + @Unique - private int GFNINormX; - @Unique - private int GFNINormY; - @Unique - private int GFNINormZ; private ModelQuadFacing normalFace; @Inject(method = "", at = @At("RETURN")) private void init(int[] vertexData, int colorIndex, Direction face, Sprite sprite, boolean shade, CallbackInfo ci) { - // calculates the GFNI normal (side effect) and returns the packed unit normal - this.normal = calculateNormals(true); - - this.normalFace = findNormalFace(this.normal); + this.normal = this.calculateNormal(); + this.normalFace = ModelQuadFacing.fromPackedNormal(this.normal); this.flags = ModelQuadFlags.getQuadFlags(this, face); } @@ -86,28 +80,6 @@ public Sprite getSprite() { return this.sprite; } - @Override - public int getGFNINormX() { - return this.GFNINormX; - } - - @Override - public int getGFNINormY() { - return this.GFNINormY; - } - - @Override - public int getGFNINormZ() { - return this.GFNINormZ; - } - - @Override - public void setGFNINormal(int x, int y, int z) { - this.GFNINormX = x; - this.GFNINormY = y; - this.GFNINormZ = z; - } - @Override public float getTexU(int idx) { return Float.intBitsToFloat(this.vertexData[vertexOffset(idx) + TEXTURE_INDEX]); @@ -133,6 +105,11 @@ public ModelQuadFacing getNormalFace() { return this.normalFace; } + @Override + public int getNormal() { + return this.normal; + } + @Override public Direction getLightFace() { return this.face; From 0f0ef22f5eb2bbcdbfa7c3a01a96d961a11a86ac Mon Sep 17 00:00:00 2001 From: douira Date: Wed, 20 Dec 2023 22:00:59 +0100 Subject: [PATCH 192/256] rename TranslucentSorting to SortTriggering and some field names --- .../render/chunk/RenderSectionManager.java | 6 +-- .../trigger/DirectTriggers.java | 4 +- .../trigger/GFNITriggers.java | 4 +- .../trigger/GeometryPlanes.java | 42 +++++++++---------- .../translucent_sorting/trigger/Group.java | 2 +- .../trigger/NormalList.java | 2 +- ...lucentSorting.java => SortTriggering.java} | 4 +- 7 files changed, 32 insertions(+), 32 deletions(-) rename src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/{TranslucentSorting.java => SortTriggering.java} (98%) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index 977f8097f4..e6a4090af9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -33,7 +33,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TopoSortDynamicData; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger.CameraMovement; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger.TranslucentSorting; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger.SortTriggering; import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkMeshFormats; import me.jellysquid.mods.sodium.client.render.texture.SpriteUtil; import me.jellysquid.mods.sodium.client.render.util.RenderAsserts; @@ -80,7 +80,7 @@ public class RenderSectionManager { private final int renderDistance; - private final TranslucentSorting ts; + private final SortTriggering ts; @NotNull private SortedRenderLists renderLists; @@ -99,7 +99,7 @@ public RenderSectionManager(ClientWorld world, int renderDistance, CommandList c this.chunkRenderer = new DefaultChunkRenderer(RenderDevice.INSTANCE, ChunkMeshFormats.COMPACT); this.world = world; - this.ts = new TranslucentSorting(); + this.ts = new SortTriggering(); this.builder = new ChunkBuilder(world, ChunkMeshFormats.COMPACT); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/DirectTriggers.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/DirectTriggers.java index b622ba87a4..acc0842b9c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/DirectTriggers.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/DirectTriggers.java @@ -6,7 +6,7 @@ import it.unimi.dsi.fastutil.doubles.Double2ObjectRBTreeMap; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TopoSortDynamicData; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger.TranslucentSorting.SectionTriggers; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger.SortTriggering.SectionTriggers; import net.minecraft.util.math.ChunkSectionPos; /** @@ -130,7 +130,7 @@ private void insertTrigger(double key, DirectTriggerData data) { } @Override - public void processTriggers(TranslucentSorting ts, CameraMovement movement) { + public void processTriggers(SortTriggering ts, CameraMovement movement) { Vector3dc lastCamera = movement.lastCamera(); Vector3dc camera = movement.currentCamera(); this.accumulatedDistance += lastCamera.distance(camera); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GFNITriggers.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GFNITriggers.java index 079107d75d..87e1ace17f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GFNITriggers.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GFNITriggers.java @@ -6,7 +6,7 @@ import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.DynamicData; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger.TranslucentSorting.SectionTriggers; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger.SortTriggering.SectionTriggers; import net.minecraft.util.math.ChunkSectionPos; /** @@ -28,7 +28,7 @@ int getUniqueNormalCount() { } @Override - public void processTriggers(TranslucentSorting ts, CameraMovement movement) { + public void processTriggers(SortTriggering ts, CameraMovement movement) { for (var normalList : this.normalLists.values()) { normalList.processMovement(ts, movement); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GeometryPlanes.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GeometryPlanes.java index 5d51a23ddc..3eec3454dd 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GeometryPlanes.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GeometryPlanes.java @@ -10,53 +10,53 @@ import net.minecraft.util.math.ChunkSectionPos; public class GeometryPlanes { - private NormalPlanes[] alignedDistances; - private Object2ReferenceOpenHashMap unalignedDistances; + private NormalPlanes[] alignedPlanes; + private Object2ReferenceOpenHashMap unalignedPlanes; public NormalPlanes[] getAligned() { - return this.alignedDistances; + return this.alignedPlanes; } public NormalPlanes[] getAlignedOrCreate() { - if (this.alignedDistances == null) { - this.alignedDistances = new NormalPlanes[ModelQuadFacing.DIRECTIONS]; + if (this.alignedPlanes == null) { + this.alignedPlanes = new NormalPlanes[ModelQuadFacing.DIRECTIONS]; } - return this.alignedDistances; + return this.alignedPlanes; } public Collection getUnaligned() { - if (this.unalignedDistances == null) { + if (this.unalignedPlanes == null) { return null; } - return this.unalignedDistances.values(); + return this.unalignedPlanes.values(); } public Object2ReferenceOpenHashMap getUnalignedOrCreate() { - if (this.unalignedDistances == null) { - this.unalignedDistances = new Object2ReferenceOpenHashMap<>(); + if (this.unalignedPlanes == null) { + this.unalignedPlanes = new Object2ReferenceOpenHashMap<>(); } - return this.unalignedDistances; + return this.unalignedPlanes; } public Collection getUnalignedNormals() { - if (this.unalignedDistances == null) { + if (this.unalignedPlanes == null) { return null; } - return this.unalignedDistances.keySet(); + return this.unalignedPlanes.keySet(); } NormalPlanes getPlanesForNormal(NormalList normalList) { var normal = normalList.getNormal(); if (normal.isAligned()) { - if (this.alignedDistances == null) { + if (this.alignedPlanes == null) { return null; } - return this.alignedDistances[normal.getAlignedDirection()]; + return this.alignedPlanes[normal.getAlignedDirection()]; } else { - if (this.unalignedDistances == null) { + if (this.unalignedPlanes == null) { return null; } - return this.unalignedDistances.get(normal); + return this.unalignedPlanes.get(normal); } } @@ -95,15 +95,15 @@ public void addQuadPlane(ChunkSectionPos sectionPos, TQuad quad) { } private void prepareAndInsert(Object2ReferenceOpenHashMap distancesByNormal) { - if (this.alignedDistances != null) { - for (var normalPlanes : this.alignedDistances) { + if (this.alignedPlanes != null) { + for (var normalPlanes : this.alignedPlanes) { if (normalPlanes != null) { normalPlanes.prepareAndInsert(distancesByNormal); } } } - if (this.unalignedDistances != null) { - for (var normalPlanes : this.unalignedDistances.values()) { + if (this.unalignedPlanes != null) { + for (var normalPlanes : this.unalignedPlanes.values()) { normalPlanes.prepareAndInsert(distancesByNormal); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/Group.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/Group.java index a39cde8520..f0a7ecda3d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/Group.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/Group.java @@ -51,7 +51,7 @@ void replaceWith(NormalPlanes normalPlanes) { this.normal = normalPlanes.normal; } - void triggerRange(TranslucentSorting ts, double start, double end) { + void triggerRange(SortTriggering ts, double start, double end) { // trigger self on the section if the query range overlaps with the group // testing for strict inequality because if the two intervals just touch at the // start/end, there can be no overlap diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalList.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalList.java index 97d75f6eaa..512bfe2c9d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalList.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalList.java @@ -75,7 +75,7 @@ private double normalDotDouble(Vector3dc v) { (double) this.normal.z * v.z())); } - void processMovement(TranslucentSorting ts, CameraMovement movement) { + void processMovement(SortTriggering ts, CameraMovement movement) { // calculate the distance range of the movement with respect to the normal double start = this.normalDotDouble(movement.lastCamera()); double end = this.normalDotDouble(movement.currentCamera()); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/TranslucentSorting.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java similarity index 98% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/TranslucentSorting.java rename to src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java index cf356fca59..1bd56ebefa 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/TranslucentSorting.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java @@ -25,7 +25,7 @@ * * @author douira (the translucent_sorting package) */ -public class TranslucentSorting { +public class SortTriggering { /** * To avoid generating a collection of the triggered sections, this callback is * used to process the triggered sections directly as they are queried from the @@ -52,7 +52,7 @@ public class TranslucentSorting { private final DirectTriggers direct = new DirectTriggers(); interface SectionTriggers { - void processTriggers(TranslucentSorting ts, CameraMovement movement); + void processTriggers(SortTriggering ts, CameraMovement movement); void removeSection(long sectionPos, TranslucentData data); From 450c9b1d1e0e6ff989180418b2b38f3442119bb6 Mon Sep 17 00:00:00 2001 From: douira Date: Wed, 20 Dec 2023 22:07:15 +0100 Subject: [PATCH 193/256] fix distance sort to sort distance descending --- .../chunk/translucent_sorting/data/TopoSortDynamicData.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java index a76e513924..817961f081 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java @@ -183,7 +183,7 @@ private static void distanceSortDirect(IntBuffer indexBuffer, TQuad[] quads, Vec var data = new long[quads.length]; for (int i = 0; i < quads.length; i++) { float distance = cameraPos.distanceSquared(quads[i].getCenter()); - data[i] = (long) Float.floatToRawIntBits(distance) << 32 | i; + data[i] = (long) ~Float.floatToRawIntBits(distance) << 32 | i; } Arrays.sort(data); From df31c707359482853611f0ee9a0fba64c3069b85 Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 22 Dec 2023 01:35:10 +0100 Subject: [PATCH 194/256] clean up todos and comments, add some javadoc --- .../translucent_sorting/AlignableNormal.java | 5 +++ .../chunk/translucent_sorting/SortType.java | 2 -- .../TranslucentGeometryCollector.java | 8 ----- .../bsp_tree/BSPResult.java | 4 +++ .../bsp_tree/BSPSortState.java | 5 +++ .../bsp_tree/BSPWorkspace.java | 4 +++ .../bsp_tree/InnerBinaryPartitionBSPNode.java | 4 +++ .../bsp_tree/InnerMultiPartitionBSPNode.java | 8 +++-- .../bsp_tree/InnerPartitionBSPNode.java | 31 ++++++++++++++++--- .../bsp_tree/LeafDoubleBSPNode.java | 3 ++ .../bsp_tree/LeafMultiBSPNode.java | 3 ++ .../bsp_tree/LeafSingleBSPNode.java | 3 ++ .../bsp_tree/Partition.java | 2 +- .../data/AnyOrderData.java | 10 ++++-- .../data/BSPDynamicData.java | 6 ++++ .../data/MixedDirectionData.java | 5 ++- .../translucent_sorting/data/NoData.java | 8 ++--- .../data/SplitDirectionData.java | 4 +-- .../data/StaticNormalRelativeData.java | 4 +++ .../data/StaticTopoAcyclicData.java | 5 +++ .../data/TopoGraphSorting.java | 12 ++++--- .../data/TopoSortDynamicData.java | 8 +++++ .../trigger/DirectTriggers.java | 13 ++++++-- .../trigger/GFNITriggers.java | 7 +++-- .../trigger/GeometryPlanes.java | 4 +++ .../translucent_sorting/trigger/Group.java | 2 +- .../trigger/NormalPlanes.java | 4 +++ .../trigger/SortTriggering.java | 3 +- 28 files changed, 134 insertions(+), 43 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AlignableNormal.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AlignableNormal.java index 217079e16f..e082a89043 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AlignableNormal.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AlignableNormal.java @@ -6,6 +6,11 @@ import it.unimi.dsi.fastutil.floats.FloatArrays; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; +/** + * A normal vector that has additional information about its alignment. This is + * useful for better hashing and telling other code that the normal is aligned, + * which in turn enables many optimizations and fast paths to be taken. + */ public class AlignableNormal extends Vector3f { private static final AlignableNormal[] NORMALS = new AlignableNormal[ModelQuadFacing.DIRECTIONS]; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SortType.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SortType.java index 70e562555b..791b7425b7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SortType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SortType.java @@ -3,8 +3,6 @@ /** * What type of sorting to use for a section. Calculated by a heuristic after * building a section. - * - * TODO: maybe remove needsDynamicSort if they remain unused */ public enum SortType { /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java index 7e0755df78..eaf9500e7f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java @@ -32,14 +32,6 @@ * determines the best sort type for the section and constructs various types of * translucent data objects that then perform sorting and get registered with * GFNI for triggering. - * - * TODO: - * - use continuous arrays for the quad centers and quad storage if necessary - * - use more accurate normals for unaligned topo sort? - * - optionally add a way to attempt full acyclic topo sort even if the - * heuristic doesn't expect it to be possible. The caveat is that this costs - * doing it once without invisible quad exclusion and once with if the first - * attempt fails. */ public class TranslucentGeometryCollector { private final ChunkSectionPos sectionPos; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPResult.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPResult.java index 41affcd52a..00111e9b10 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPResult.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPResult.java @@ -2,6 +2,10 @@ import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger.GeometryPlanes; +/** + * The result of a BSP building operation. Building a BSP returns the root node + * along with the partition planes that need to be added to the trigger system. + */ public class BSPResult extends GeometryPlanes { private BSPNode rootNode; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java index d21fd8da30..c15ded3a8a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java @@ -8,6 +8,11 @@ import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; import me.jellysquid.mods.sodium.client.util.NativeBuffer; +/** + * The sort state is passed around the tree (similar to visitor pattern) and + * contains the index buffer being written to alongside additional state for + * remapping indexes when traversing the subtree of a reused node. + */ class BSPSortState { static final int NO_FIXED_OFFSET = Integer.MIN_VALUE; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java index 55ad9d0978..5d8a8d72f1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java @@ -5,6 +5,10 @@ import net.minecraft.util.math.ChunkSectionPos; /** + * The BSP workspace holds the state during the BSP building process. (see also + * BSPSortState) It brings a number of fixed parameters and receives partition + * planes to return as part of the final result. + * * Implementation note: Storing the multi partition node's interval points in a * global array instead of making a new one at each tree level doesn't appear to * have any performance benefit. diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java index 1fe068595e..898f49a9a6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java @@ -4,6 +4,10 @@ import it.unimi.dsi.fastutil.ints.IntArrayList; +/** + * Partitions quads into two sides, each its own BSP node, of a partition plane + * and a set of quads that lie on the plane. + */ class InnerBinaryPartitionBSPNode extends InnerPartitionBSPNode { private final float planeDistance; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerMultiPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerMultiPartitionBSPNode.java index 92c5e0d378..4747399fea 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerMultiPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerMultiPartitionBSPNode.java @@ -6,6 +6,10 @@ import it.unimi.dsi.fastutil.objects.ReferenceArrayList; /** + * Partitions quads into multiple child BSP nodes with multiple parallel + * partition planes. This is uses less memory and time than constructing a + * binary BSP tree through more partitioning passes. + * * Implementation note: Detecting and avoiding the double array when possible * brings no performance benefit in sorting speed, only a building speed * detriment. @@ -89,7 +93,7 @@ void collectSortedQuads(BSPSortState sortState, Vector3fc cameraPos) { this.collectPartitionQuads(sortState, this.planeDistances.length, cameraPos); } - static BSPNode build(BSPWorkspace workspace, IntArrayList indexes, int depth, BSPNode oldNode, + static BSPNode buildFromPartitions(BSPWorkspace workspace, IntArrayList indexes, int depth, BSPNode oldNode, ReferenceArrayList partitions, int axis, boolean endsWithPlane) { int planeCount = endsWithPlane ? partitions.size() : partitions.size() - 1; float[] planeDistances = new float[planeCount]; @@ -117,7 +121,7 @@ static BSPNode build(BSPWorkspace workspace, IntArrayList indexes, int depth, BS partitionDistance = partition.distance(); workspace.addAlignedPartitionPlane(axis, partitionDistance); - // TODO: remove + // NOTE: sanity check if (partitionDistance == -1) { throw new IllegalStateException("partition distance not set"); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java index e72de5111f..99c837e1c2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java @@ -11,11 +11,14 @@ import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; /** - * Implementation note: + * Performs aligned BSP partitioning of many nodes and constructs appropriate + * BSP nodes based on the result. + * + * Implementation notes: * - Presorting the points in block-sized buckets doesn't help. It seems the * sort algorithm is just fast enough to handle this. * - Eliminating the use of partition objects doesn't help. Since there's - * usually just very few partitions, it's not worth it it seems. + * usually just very few partitions, it's not worth it, it seems. * - Using fastutil's LongArrays sorting options (radix and quicksort) is slower * than using Arrays.sort (which uses DualPivotQuicksort internally), even on * worlds with player-built structures. @@ -29,6 +32,14 @@ * 0x8000... and negative numbers with 0xffff... This should flip the sign bit * on both (so negative numbers go first), and then reverse the ordering on * negative numbers." from https://stackoverflow.com/q/43299299 + * + * When aligned partitioning fails the geometry is checked for intersection. If + * there is intersection it means the section is unsortable and an approximation + * is used instead. When it doesn't intersect but is not aligned partitionable, + * it either requires unaligned partitioning (a hard problem not solved here) + * or it's unpartitionable. It would be possible to insert a topo sorting node + * here, but it's not worth the implementation effort unless it's found to be a + * reasonable and common use case (I haven't been able to determine that it is). */ abstract class InnerPartitionBSPNode extends BSPNode { private static int NODE_REUSE_THRESHOLD = 30; @@ -335,13 +346,13 @@ static BSPNode build(BSPWorkspace workspace, IntArrayList indexes, int depth, BS } // create a multi-partition node - return InnerMultiPartitionBSPNode.build(workspace, indexes, depth, oldNode, + return InnerMultiPartitionBSPNode.buildFromPartitions(workspace, indexes, depth, oldNode, partitions, axis, endsWithPlane); } - // test if the geometry intersects with itself + // test if the geometry intersects with itself. // if there is self-intersection, return a multi leaf node to just give up - // sorting this geometry. intersecting geometry is rare but when it does happen, + // sorting this geometry. Intersecting geometry is rare but when it does happen, // it should simply be accepted and rendered as-is. Whatever artifacts this // causes are considered "ok". int testsRemaining = 10000; @@ -385,6 +396,16 @@ static BSPNode build(BSPWorkspace workspace, IntArrayList indexes, int depth, BS } } + // At this point we know the geometry is (probably) not intersecting, and it + // can't be partitioned along an aligned axis. This means that either the + // geometry is unpartitionable with free cuts (partitions that don't fragment + // geometry) or it required unaligned partitioning. Unaligned partitioning is a + // hard problem and solving it here isn't really necessary. Fully aligned + // unpartitonable constructions exist but not in normal Minecraft and also not + // likely in any other normal scenario. + + // Throwing this exception will cause the entire section to be either topo + // sorted or the distance sorting fallback to be used. throw new BSPBuildFailureException("no partition found"); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafDoubleBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafDoubleBSPNode.java index 5db07d4929..24d6c9b152 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafDoubleBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafDoubleBSPNode.java @@ -2,6 +2,9 @@ import org.joml.Vector3fc; +/** + * A leaf node of a BSP tree that contains two quads. + */ public class LeafDoubleBSPNode extends BSPNode { private final int quadA; private final int quadB; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafMultiBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafMultiBSPNode.java index 6a1262b727..5bfb17d3ca 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafMultiBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafMultiBSPNode.java @@ -2,6 +2,9 @@ import org.joml.Vector3fc; +/** + * A leaf node of a BSP tree that contains a set of quads. + */ class LeafMultiBSPNode extends BSPNode { private final int[] quads; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafSingleBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafSingleBSPNode.java index 6c328563a0..fc6ae461b3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafSingleBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafSingleBSPNode.java @@ -2,6 +2,9 @@ import org.joml.Vector3fc; +/** + * A leaf node of a BSP tree that contains a single quad. + */ class LeafSingleBSPNode extends BSPNode { private final int quad; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/Partition.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/Partition.java index b4d38c899d..cf50ddcec4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/Partition.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/Partition.java @@ -3,7 +3,7 @@ import it.unimi.dsi.fastutil.ints.IntArrayList; /** - * models a partition of the space into a set of quads that lie inside or on the + * Models a partition of the space into a set of quads that lie inside or on the * plane with the specified distance. If the distance is -1 this is the "end" * partition after the last partition plane. */ diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/AnyOrderData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/AnyOrderData.java index a32f01ea9b..9206160464 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/AnyOrderData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/AnyOrderData.java @@ -13,9 +13,13 @@ * vertices are assembled into quads. Since the sort order doesn't matter, all * sections with this sort type can share the same data in the index buffer. * - * TODO: share the buffer on the CPU and on the GPU. This is essentially the - * same as SharedQuadIndexBuffer but it has to be compatible with sections in - * the same region using custom index buffers. + * NOTE: A possible optimization would be to share the buffer for unordered + * translucent sections on the CPU and on the GPU. It would essentially be the + * same as SharedQuadIndexBuffer, but it has to be compatible with sections in + * the same region using custom index buffers which makes the management + * complicated. The shared buffer would be a member amongst the other non-shared + * buffer segments and would need to be resized when a larger section wants to + * use it. */ public class AnyOrderData extends SplitDirectionData { AnyOrderData(ChunkSectionPos sectionPos, NativeBuffer buffer, VertexRange[] ranges) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java index f558856dd1..18db437bce 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java @@ -10,6 +10,12 @@ import me.jellysquid.mods.sodium.client.util.NativeBuffer; import net.minecraft.util.math.ChunkSectionPos; +/** + * Constructs a BSP tree of the quads and sorts them dynamically. + * + * Triggering is performed when the BSP tree's partition planes are crossed in + * any direction (bidirectional). + */ public class BSPDynamicData extends DynamicData { private static final int NODE_REUSE_MIN_GENERATION = 1; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/MixedDirectionData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/MixedDirectionData.java index 873dacd611..930fd77b5f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/MixedDirectionData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/MixedDirectionData.java @@ -7,17 +7,16 @@ public abstract class MixedDirectionData extends PresentTranslucentData { public final VertexRange range; + private final VertexRange[] ranges = new VertexRange[ModelQuadFacing.COUNT]; MixedDirectionData(ChunkSectionPos sectionPos, NativeBuffer buffer, VertexRange range) { super(sectionPos, buffer); this.range = range; + this.ranges[ModelQuadFacing.UNASSIGNED.ordinal()] = range; } @Override public VertexRange[] getVertexRanges() { - // TODO: cache this array? - var ranges = new VertexRange[ModelQuadFacing.COUNT]; - ranges[ModelQuadFacing.UNASSIGNED.ordinal()] = this.range; return ranges; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/NoData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/NoData.java index b72ef326ad..f1007a7683 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/NoData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/NoData.java @@ -4,11 +4,11 @@ import net.minecraft.util.math.ChunkSectionPos; /** - * This class means there is no translucent data and is used to signal to GFNI - * to remove the section from the triggering structure. + * This class means there is no translucent data and is used to signal that the + * section should be removed from triggering data structures. * - * If no translucent sorting is being performed, not even this class is used but - * null is passed instead. + * If translucent sorting is disabled, not even this class is used, but null is + * passed instead. */ public class NoData extends TranslucentData { public NoData(ChunkSectionPos sectionPos) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/SplitDirectionData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/SplitDirectionData.java index 6e4581fe6f..0982875245 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/SplitDirectionData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/SplitDirectionData.java @@ -6,8 +6,8 @@ /** * Super class for translucent data that is rendered separately for each facing. - * It's important that the indices are inserted starting at zero for each - * direction. + * (block face culling is possible) It's important that the indices are inserted + * starting at zero for each facing. */ public abstract class SplitDirectionData extends PresentTranslucentData { public final VertexRange[] ranges; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java index d3ae556171..a301f0eeca 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java @@ -14,6 +14,10 @@ import me.jellysquid.mods.sodium.client.util.sorting.VertexSorters; import net.minecraft.util.math.ChunkSectionPos; +/** + * Static normal relative sorting orders quads by the dot product of their + * normal and position. (referred to as "distance" throughout the code) + */ public class StaticNormalRelativeData extends SplitDirectionData { public StaticNormalRelativeData(ChunkSectionPos sectionPos, NativeBuffer buffer, VertexRange[] ranges) { super(sectionPos, buffer, ranges); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticTopoAcyclicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticTopoAcyclicData.java index 29837f67bd..48c342dd8d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticTopoAcyclicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticTopoAcyclicData.java @@ -7,6 +7,11 @@ import me.jellysquid.mods.sodium.client.util.NativeBuffer; import net.minecraft.util.math.ChunkSectionPos; +/** + * Static topo acyclic sorting uses the topo sorting algorithm but only if it's + * possible to sort without dynamic triggering, meaning the sort order never + * needs to change. + */ public class StaticTopoAcyclicData extends MixedDirectionData { private static final int MAX_STATIC_TOPO_SORT_QUADS = 1000; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoGraphSorting.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoGraphSorting.java index dd21243d7f..9def872a4f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoGraphSorting.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoGraphSorting.java @@ -106,7 +106,10 @@ private static boolean visibilityWithSeparator(TQuad quadA, TQuad quadB, } } - // TODO: check all other normals too + // NOTE: unaligned normals for separators are not checked because doing so is a + // hard + // problem and this is an approximation. The fully correct topo sort would need + // to be much more complicated. // visibility not disproven return true; @@ -184,7 +187,6 @@ public static boolean topoSortDepthFirstCyclic( IntBuffer indexBuffer, TQuad[] allQuads, Object2ReferenceOpenHashMap distancesByNormal, Vector3fc cameraPos) { - // TODO: quads visibility filter copy-pasted from topoSortAlignedAcyclic // if enabled, check for visibility and produce a mapping of indices TQuad[] quads = null; int[] activeToRealIndex = null; @@ -197,9 +199,9 @@ public static boolean topoSortDepthFirstCyclic( for (int i = 0; i < allQuads.length; i++) { TQuad quad = allQuads[i]; - // TODO: this could introduce wrong sorting if the real normal and the quantized - // normal don't line up, ignoring the quad if it's not visible through the - // quantized one but visible in-camera + // NOTE: This approximation may introduce wrong sorting if the real and the + // quantized normal aren't the same. A quad may be ignored with the quantized + // normal, but it's actually visible in camera. if (pointOutsideHalfspace(quad.getDotProduct(), quad.getQuantizedNormal(), cameraPos)) { activeToRealIndex[activeQuads] = i; quads[activeQuads] = quad; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java index 817961f081..98e604fa7a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java @@ -14,6 +14,14 @@ import net.minecraft.util.math.ChunkSectionPos; /** + * Performs dynamic topo sorting and falls back to distance sorting as + * necessary. This class implements a number of heuristics to attempt to upgrade + * distance-based sorting back to topo sorting when possible as topo sorting + * generally needs to happen far less often. + * + * Triggering is performed when the quads' planes crossed along their normal + * direction (unidirectional). + * * Implementation note: * - Reusing the output of previous distance sorting job doesn't make a * difference or makes things slower in some cases. It's unclear why exactly diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/DirectTriggers.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/DirectTriggers.java index acc0842b9c..51f45e0aa0 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/DirectTriggers.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/DirectTriggers.java @@ -10,8 +10,17 @@ import net.minecraft.util.math.ChunkSectionPos; /** - * Performs direct triggering for sections that can't (or shouldn't) be - * topologically sorted and thus aren't eligible for GFNI triggering. + * Performs direct triggering for sections that are sorted by distance. Direct + * triggering means the section is not triggered based on its geometry but + * rather the movement of the camera relative to the last position the camera + * was in when the section was sorted last. + * + * There are two types of direct triggering: Distance triggering is used when + * the camera is close to or inside the section. Angle triggering is used + * otherwise. Distance triggering sorts the section when the camera has moved at + * least a certain distance from the last sort position while angle triggering + * sorts it when a certain angle between the current and last sort position is + * exceeded (relative to the section center). */ class DirectTriggers implements SectionTriggers { /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GFNITriggers.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GFNITriggers.java index 87e1ace17f..b715c58443 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GFNITriggers.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GFNITriggers.java @@ -13,9 +13,10 @@ * Performs Global Face Normal Indexing-based triggering as described in * https://hackmd.io/@douira100/sodium-sl-gfni * - * Global distances are stored as doubles while section-relative distances are - * stored as floats. Normals are stored as float vectors unless they're needed - * to produce global double distances. + * Note on precision: Global distances are stored as doubles while + * section-relative distances are stored as floats. The distances of the camera + * are calculated as doubles, but using float normal vectors (furthermore normal + * vectors are heavily quantized, so angular precision is not a concern). */ class GFNITriggers implements SectionTriggers { /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GeometryPlanes.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GeometryPlanes.java index 3eec3454dd..46f02f4e1d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GeometryPlanes.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GeometryPlanes.java @@ -9,6 +9,10 @@ import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; import net.minecraft.util.math.ChunkSectionPos; +/** + * GeometryPlanes stores the NormalPlanes for different normals, both aligned + * and unaligned. + */ public class GeometryPlanes { private NormalPlanes[] alignedPlanes; private Object2ReferenceOpenHashMap unalignedPlanes; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/Group.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/Group.java index f0a7ecda3d..ef383b3127 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/Group.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/Group.java @@ -70,7 +70,7 @@ void triggerRange(SortTriggering ts, double start, double end) { * position since the group was retrieved from the map for the right position. * * TODO: how common are collisions and are they bad? - * If they are common, use second hash + * If they are common, use second or different hash */ boolean equalsNOrmalPlanes(NormalPlanes normalPlanes) { return this.facePlaneDistances.length == normalPlanes.relativeDistancesSet.size() diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalPlanes.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalPlanes.java index 555c85f50b..9f6b179e5b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalPlanes.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalPlanes.java @@ -11,6 +11,10 @@ import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.AlignableNormal; import net.minecraft.util.math.ChunkSectionPos; +/** + * NormalPlanes represents planes by a normal and a list of distances. Initially they're + * stored in a hash set and later sorted for range queries. + */ public class NormalPlanes { final FloatOpenHashSet relativeDistancesSet = new FloatOpenHashSet(16); final AlignableNormal normal; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java index 1bd56ebefa..9c1435769e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java @@ -18,8 +18,7 @@ * of translucent data objects for each sort type and delegates triggering of * sections for dynamic sorting to the trigger components. * - * TODO: - * - Incompatible with rendering anything through Indium because it doesn't run + * TODO: Incompatible with rendering anything through Indium because it doesn't run * the translucent geometry collector properly. It doesn't run Sodium's * BlockRenderer which is required for lines 166-167 of BlockRenderer to work. * From 7f1d340acbaef7674f6e6c56645783821ba3ae7f Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 22 Dec 2023 01:54:07 +0100 Subject: [PATCH 195/256] use proper logger for bsp build failures --- .../translucent_sorting/TranslucentGeometryCollector.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java index eaf9500e7f..b15836f13a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java @@ -2,6 +2,8 @@ import java.util.Arrays; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.joml.Vector3f; import org.joml.Vector3fc; @@ -34,6 +36,8 @@ * GFNI for triggering. */ public class TranslucentGeometryCollector { + private static final Logger LOGGER = LogManager.getLogger(TranslucentGeometryCollector.class); + private final ChunkSectionPos sectionPos; // true if there are any unaligned quads @@ -458,7 +462,7 @@ private TranslucentData makeNewTranslucentData(BuiltSectionMeshParts translucent buffer, oldData); } catch (BSPBuildFailureException e) { // TODO: investigate existing BSP build failures, then remove this logging - System.out.println("BSP build failure: " + sectionPos); + LOGGER.warn("BSP build failure at {}. Please report this to douira for evaluation alongside with some way of reproducing the geometry in this section. (coordinates and world file or seed)", sectionPos); var geometryPlanes = GeometryPlanes.fromQuadLists(sectionPos, this.quads); return TopoSortDynamicData.fromMesh( translucentMesh, cameraPos, this.quads, this.sectionPos, From a6f3fe00e0e5e7bc1dbddaf8a6b8645ee10c6830 Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 22 Dec 2023 01:54:13 +0100 Subject: [PATCH 196/256] fix naming and comments --- .../chunk/translucent_sorting/bsp_tree/BSPSortState.java | 7 ------- .../render/chunk/translucent_sorting/trigger/Group.java | 2 +- .../chunk/translucent_sorting/trigger/NormalList.java | 2 +- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java index c15ded3a8a..0fadcff7e4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java @@ -151,10 +151,6 @@ static int[] compressIndexes(IntArrayList indexes, boolean doSort) { compressed[0] = 1 << 31 | CONSTANT_DELTA_WIDTH_INDEX << 27 | deltaCount << 17 | firstIndex; compressed[1] = minDelta; - // System.out.println( - // "Densely compressed " + indexes.size() + " indexes to 2 ints, compression - // ratio " + - // (indexes.size() / 2)); return compressed; } @@ -200,9 +196,6 @@ static int[] compressIndexes(IntArrayList indexes, boolean doSort) { compressed[outputIndex++] = gatherInt; } - // System.out.println("Compressed " + indexes.size() + " indexes to " + size + " - // ints, compression ratio " - // + (indexes.size() / size)); return compressed; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/Group.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/Group.java index ef383b3127..5d89684eb5 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/Group.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/Group.java @@ -72,7 +72,7 @@ void triggerRange(SortTriggering ts, double start, double end) { * TODO: how common are collisions and are they bad? * If they are common, use second or different hash */ - boolean equalsNOrmalPlanes(NormalPlanes normalPlanes) { + boolean normalPlanesEquals(NormalPlanes normalPlanes) { return this.facePlaneDistances.length == normalPlanes.relativeDistancesSet.size() && this.distances.equals(normalPlanes.distanceRange) && this.relDistanceHash == normalPlanes.relDistanceHash; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalList.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalList.java index 512bfe2c9d..328e7c0925 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalList.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalList.java @@ -153,7 +153,7 @@ void updateSection(NormalPlanes normalPlanes, long sectionPos) { Group group = this.groupsBySection.get(sectionPos); // only update on changes to translucent geometry - if (group.equalsNOrmalPlanes(normalPlanes)) { + if (group.normalPlanesEquals(normalPlanes)) { // don't update if they are the same return; } From b96977bd3e5b7f9c0e432aa2a9f951c691214782 Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 22 Dec 2023 04:14:42 +0100 Subject: [PATCH 197/256] fix quantized normal normalization (to make unit normal) --- .../sodium/client/render/chunk/translucent_sorting/TQuad.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java index b7e9c8698b..581594f449 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java @@ -113,10 +113,12 @@ private void computeQuantizedNormal() { // quantize the coordinates on the surface of the cube. // in each axis the number of values is 2 * QUANTIZATION_FACTOR + 1. // the total number of normals is the number of points on that cube's surface. - this.quantizedNormal = new Vector3f( + var normal = new Vector3f( (int) (normX * QUANTIZATION_FACTOR), (int) (normY * QUANTIZATION_FACTOR), (int) (normZ * QUANTIZATION_FACTOR)); + normal.normalize(); + this.quantizedNormal = normal; } int getQuadHash() { From 16c24cfbd6866b46b501865437c9ae098ceb72e8 Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 22 Dec 2023 04:14:58 +0100 Subject: [PATCH 198/256] fix aligned facing bitmap --- .../TranslucentGeometryCollector.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java index b15836f13a..73c9aa7864 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java @@ -413,11 +413,15 @@ public SortType finishRendering() { } this.quads = new TQuad[totalQuadCount]; int quadIndex = 0; - for (var quadList : this.quadLists) { + for (int direction = 0; direction < ModelQuadFacing.COUNT; direction++) { + var quadList = this.quadLists[direction]; if (quadList != null) { for (var quad : quadList) { this.quads[quadIndex++] = quad; } + if (direction < ModelQuadFacing.DIRECTIONS) { + this.alignedFacingBitmap |= 1 << direction; + } } } this.quadLists = null; // not needed anymore @@ -462,7 +466,9 @@ private TranslucentData makeNewTranslucentData(BuiltSectionMeshParts translucent buffer, oldData); } catch (BSPBuildFailureException e) { // TODO: investigate existing BSP build failures, then remove this logging - LOGGER.warn("BSP build failure at {}. Please report this to douira for evaluation alongside with some way of reproducing the geometry in this section. (coordinates and world file or seed)", sectionPos); + LOGGER.warn( + "BSP build failure at {}. Please report this to douira for evaluation alongside with some way of reproducing the geometry in this section. (coordinates and world file or seed)", + sectionPos); var geometryPlanes = GeometryPlanes.fromQuadLists(sectionPos, this.quads); return TopoSortDynamicData.fromMesh( translucentMesh, cameraPos, this.quads, this.sectionPos, From 939159a6d0a16caadf248074a4660135da53ec8a Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 22 Dec 2023 15:32:53 +0100 Subject: [PATCH 199/256] fix mod json messed up by upstream force push --- src/main/resources/fabric.mod.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index cdda9bd672..32eafbab16 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -86,7 +86,7 @@ "farsight": "<1.20.1-4.0", "fluidvoidfading": "<1.1.2", "iceberg": "<1.1.14", - "iris": "*", + "iris": "<1.6.7", "immersive_portals": "<=3.2.5", "indium": "<1.0.24", "notenoughcrashes": "<4.4.6", From 5ff8740b568ed321f66bb5f52a936f4ade20a106 Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 22 Dec 2023 15:55:36 +0100 Subject: [PATCH 200/256] rename and clean up sort types, fix reduced sorting --- .../render/chunk/translucent_sorting/SortType.java | 12 ++---------- .../TranslucentGeometryCollector.java | 14 +++++++------- .../translucent_sorting/data/DynamicData.java | 2 +- .../data/StaticTopoAcyclicData.java | 2 +- .../trigger/SortTriggering.java | 4 ++-- 5 files changed, 13 insertions(+), 21 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SortType.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SortType.java index 791b7425b7..cc22f54a79 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SortType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SortType.java @@ -26,21 +26,13 @@ public enum SortType { * determining the static sort order involves doing a toplogical sort of the * quads. */ - STATIC_TOPO_ACYCLIC(true, true, false), - - /** - * There is more than one sort order but instead of sorting one each plane - * trigger, a small number of sort orders is precomputed by breaking any cycles - * in the graph. They are swapped out when the cycle-breaking planes are - * triggered in GFNI. - */ - // DYNAMIC_TOPO_CYCLIC(true, true, true, false), + STATIC_TOPO(true, true, false), /** * There are multiple sort orders. Sorting is required every time GFNI triggers * this section. */ - DYNAMIC_ALL(true, true, true); + DYNAMIC(true, true, true); public final boolean needsIndexBuffer; public final boolean needsDirectionMixing; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java index 73c9aa7864..759258e650 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java @@ -242,10 +242,10 @@ private static SortType filterSortType(SortType sortType) { case OFF: return SortType.NONE; case STATIC: - if (sortType == SortType.NONE) { + if (sortType == SortType.STATIC_NORMAL_RELATIVE || sortType == SortType.STATIC_TOPO) { return sortType; } else { - return SortType.STATIC_NORMAL_RELATIVE; + return SortType.NONE; } case DYNAMIC: return sortType; @@ -397,10 +397,10 @@ private SortType sortTypeHeuristic() { var attemptLimitIndex = Math.max(Math.min(normalCount, STATIC_TOPO_SORT_ATTEMPT_LIMITS.length - 1), 2); if (this.quads.length <= STATIC_TOPO_SORT_ATTEMPT_LIMITS[attemptLimitIndex]) { - return SortType.STATIC_TOPO_ACYCLIC; + return SortType.STATIC_TOPO; } - return SortType.DYNAMIC_ALL; + return SortType.DYNAMIC; } public SortType finishRendering() { @@ -444,12 +444,12 @@ private TranslucentData makeNewTranslucentData(BuiltSectionMeshParts translucent // from this point on we know the estimated sort type requires direction mixing // (no backface culling) and all vertices are in the UNASSIGNED direction. NativeBuffer buffer = PresentTranslucentData.nativeBufferForQuads(this.quads); - if (this.sortType == SortType.STATIC_TOPO_ACYCLIC) { + if (this.sortType == SortType.STATIC_TOPO) { var result = StaticTopoAcyclicData.fromMesh(translucentMesh, this.quads, this.sectionPos, buffer); if (result != null) { return result; } - this.sortType = SortType.DYNAMIC_ALL; + this.sortType = SortType.DYNAMIC; } // filter the sort type with the user setting and re-evaluate @@ -459,7 +459,7 @@ private TranslucentData makeNewTranslucentData(BuiltSectionMeshParts translucent return AnyOrderData.fromMesh(translucentMesh, this.quads, this.sectionPos, buffer); } - if (this.sortType == SortType.DYNAMIC_ALL) { + if (this.sortType == SortType.DYNAMIC) { try { return BSPDynamicData.fromMesh( translucentMesh, cameraPos, this.quads, this.sectionPos, diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicData.java index a863f90264..1e8c1c9a94 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicData.java @@ -16,7 +16,7 @@ public abstract class DynamicData extends MixedDirectionData { @Override public SortType getSortType() { - return SortType.DYNAMIC_ALL; + return SortType.DYNAMIC; } public GeometryPlanes getGeometryPlanes() { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticTopoAcyclicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticTopoAcyclicData.java index 48c342dd8d..7ee48d2570 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticTopoAcyclicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticTopoAcyclicData.java @@ -21,7 +21,7 @@ public class StaticTopoAcyclicData extends MixedDirectionData { @Override public SortType getSortType() { - return SortType.STATIC_TOPO_ACYCLIC; + return SortType.STATIC_TOPO; } public static StaticTopoAcyclicData fromMesh(BuiltSectionMeshParts translucentMesh, diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java index 9c1435769e..35e530d3e3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java @@ -194,8 +194,8 @@ public void addDebugStrings(List list) { list.add(String.format("N=%05d SNR=%05d STA=%04d DYN=%04d (DIR=%04d)", this.sortTypeCounters[SortType.NONE.ordinal()], this.sortTypeCounters[SortType.STATIC_NORMAL_RELATIVE.ordinal()], - this.sortTypeCounters[SortType.STATIC_TOPO_ACYCLIC.ordinal()], - this.sortTypeCounters[SortType.DYNAMIC_ALL.ordinal()], + this.sortTypeCounters[SortType.STATIC_TOPO.ordinal()], + this.sortTypeCounters[SortType.DYNAMIC.ordinal()], this.direct.getDirectTriggerCount())); } } From 0413472b280c70ea73f02baff7bbfa73a8a2aad6 Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 22 Dec 2023 18:29:25 +0100 Subject: [PATCH 201/256] display current sorting mode in debug info --- .../sodium/client/gui/SodiumGameOptions.java | 14 +++++--- .../trigger/SortTriggering.java | 33 ++++++++++++------- 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java index 1c4ba5c1ae..ba74e4524d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java @@ -50,20 +50,26 @@ public static class PerformanceSettings { } public enum SortBehavior implements TextProvider { - OFF("options.off"), - STATIC("sodium.options.sort_behavior.reduced"), - DYNAMIC("sodium.options.sort_behavior.accurate"); + OFF("options.off", "OFF"), + STATIC("sodium.options.sort_behavior.reduced", "S"), + DYNAMIC("sodium.options.sort_behavior.accurate", "D"); private final Text name; + private final String shortName; - SortBehavior(String name) { + SortBehavior(String name, String shortName) { this.name = Text.translatable(name); + this.shortName = shortName; } @Override public Text getLocalizedName() { return this.name; } + + public String getShortName() { + return this.shortName; + } } public static class AdvancedSettings { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java index 35e530d3e3..fad5d4e182 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java @@ -6,6 +6,8 @@ import org.joml.Vector3dc; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import me.jellysquid.mods.sodium.client.SodiumClientMod; +import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions.SortBehavior; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.AlignableNormal; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortType; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.DynamicData; @@ -18,7 +20,8 @@ * of translucent data objects for each sort type and delegates triggering of * sections for dynamic sorting to the trigger components. * - * TODO: Incompatible with rendering anything through Indium because it doesn't run + * TODO: Incompatible with rendering anything through Indium because it doesn't + * run * the translucent geometry collector properly. It doesn't run Sodium's * BlockRenderer which is required for lines 166-167 of BlockRenderer to work. * @@ -186,16 +189,22 @@ public void integrateTranslucentData(TranslucentData oldData, TranslucentData ne } public void addDebugStrings(List list) { - list.add(String.format("TS NL=%02d TrN=%02d TrS=G%03d/D%03d", - this.gfni.getUniqueNormalCount(), - this.triggeredNormalCount, - this.gfniTriggerCount, - this.directTriggerCount)); - list.add(String.format("N=%05d SNR=%05d STA=%04d DYN=%04d (DIR=%04d)", - this.sortTypeCounters[SortType.NONE.ordinal()], - this.sortTypeCounters[SortType.STATIC_NORMAL_RELATIVE.ordinal()], - this.sortTypeCounters[SortType.STATIC_TOPO.ordinal()], - this.sortTypeCounters[SortType.DYNAMIC.ordinal()], - this.direct.getDirectTriggerCount())); + var sortBehavior = SodiumClientMod.options().performance.sortBehavior; + if (sortBehavior == SortBehavior.OFF) { + list.add("TS OFF"); + } else { + list.add("TS (%s) NL=%02d TrN=%02d TrS=G%03d/D%03d".formatted( + sortBehavior.getShortName(), + this.gfni.getUniqueNormalCount(), + this.triggeredNormalCount, + this.gfniTriggerCount, + this.directTriggerCount)); + list.add("N=%05d SNR=%05d STA=%04d DYN=%04d (DIR=%04d)".formatted( + this.sortTypeCounters[SortType.NONE.ordinal()], + this.sortTypeCounters[SortType.STATIC_NORMAL_RELATIVE.ordinal()], + this.sortTypeCounters[SortType.STATIC_TOPO.ordinal()], + this.sortTypeCounters[SortType.DYNAMIC.ordinal()], + this.direct.getDirectTriggerCount())); + } } } From 4f8e7218c34c1b9e3459845e2ca99baf637e680d Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 22 Dec 2023 18:53:30 +0100 Subject: [PATCH 202/256] remove todo about indium compat as it's fixed --- .../chunk/translucent_sorting/trigger/SortTriggering.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java index fad5d4e182..ac9628fa05 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java @@ -20,11 +20,6 @@ * of translucent data objects for each sort type and delegates triggering of * sections for dynamic sorting to the trigger components. * - * TODO: Incompatible with rendering anything through Indium because it doesn't - * run - * the translucent geometry collector properly. It doesn't run Sodium's - * BlockRenderer which is required for lines 166-167 of BlockRenderer to work. - * * @author douira (the translucent_sorting package) */ public class SortTriggering { From c10f8220983a07a9dcab8e5a0b1bd8ce7b7bcc3c Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 22 Dec 2023 20:48:04 +0100 Subject: [PATCH 203/256] documentation --- .../TranslucentGeometryCollector.java | 21 +++++++++++++++++++ .../trigger/SortTriggering.java | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java index 759258e650..d29286c7dc 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java @@ -11,6 +11,7 @@ import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions.SortBehavior; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildOutput; import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.FluidRenderer; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree.BSPBuildFailureException; @@ -34,6 +35,26 @@ * determines the best sort type for the section and constructs various types of * translucent data objects that then perform sorting and get registered with * GFNI for triggering. + * + * An instance of this class is created for each meshing task. It goes through + * three stages: + * 1. During meshing it collects the geometry and calculates some metrics on the + * fly. These are later used for the sort type heuristic. + * 2. With {@link #finishRendering()} it finishes the geometry collection, + * generates the quad list, and calculates additional metrics. Then the sort + * type is determined with a heuristic based on the collected metrics. This + * determines if block face culling can be enabled. + * - Now the {@link BuiltSectionMeshParts} is generates which yields the vertex + * ranges. + * 3. The vertex ranges and the mesh parts object are used by the collector in + * the construction of the {@link TranslucentData} object. The data object + * allocates memory for the index data and performs the first (and for static + * sort types, only) sort. + * - The data object is put into the {@link ChunkBuildOutput}. + * + * When dynamic sorting is enabled, trigger information from {@link DynamicData} + * object is integrated into {@link SortTriggering} when the task result is + * received by the main thread. */ public class TranslucentGeometryCollector { private static final Logger LOGGER = LogManager.getLogger(TranslucentGeometryCollector.class); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java index ac9628fa05..bdc8feccb6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java @@ -16,7 +16,7 @@ import net.minecraft.util.math.ChunkSectionPos; /** - * This class is the central point in translucency sorting. It counts the number + * This class is a central point in translucency sorting. It counts the number * of translucent data objects for each sort type and delegates triggering of * sections for dynamic sorting to the trigger components. * From 49c551e4746b594b4ac640eb6691d3c3bb1e606f Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 23 Dec 2023 05:09:53 +0100 Subject: [PATCH 204/256] indexed rendering cleanup minor details --- .../client/render/chunk/DefaultChunkRenderer.java | 1 - .../client/render/chunk/RenderSectionManager.java | 5 ++++- .../render/chunk/data/SectionRenderDataStorage.java | 10 ++++------ .../client/render/chunk/region/RenderRegion.java | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java index eb9b67bdbc..989ffee70e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java @@ -54,7 +54,6 @@ public void render(ChunkRenderMatrices matrices, CameraTransform camera) { super.begin(renderPass); - // TODO: also disable this if there is only NONE-type sorting or no translucent geometry in the region boolean isTranslucent = renderPass == DefaultTerrainRenderPasses.TRANSLUCENT && SodiumClientMod.options().performance.sortBehavior != SortBehavior.OFF; boolean useBlockFaceCulling = SodiumClientMod.options().performance.useBlockFaceCulling; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index e6a4090af9..0f9f3c5664 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -99,13 +99,14 @@ public RenderSectionManager(ClientWorld world, int renderDistance, CommandList c this.chunkRenderer = new DefaultChunkRenderer(RenderDevice.INSTANCE, ChunkMeshFormats.COMPACT); this.world = world; - this.ts = new SortTriggering(); this.builder = new ChunkBuilder(world, ChunkMeshFormats.COMPACT); this.needsGraphUpdate = true; this.renderDistance = renderDistance; + this.ts = new SortTriggering(); + this.regions = new RenderRegionManager(commandList); this.sectionCache = new ClonedChunkSectionCache(this.world); @@ -343,6 +344,8 @@ private void processChunkBuildResults(ArrayList results) { var job = result.render.getTaskCancellationToken(); + // clear the cancellation token (thereby marking the section as not having an + // active task) if this job is the most recent submitted job for this section if (job != null && result.submitTime >= result.render.getLastSubmittedFrame()) { result.render.setTaskCancellationToken(null); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java index 9134d7e28a..edbb59a92f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java @@ -163,12 +163,10 @@ public void onIndexBufferResized() { } private void updateIndexes(int sectionIndex) { - if (this.storesIndices) { - var data = this.getDataPointer(sectionIndex); - var indexAllocation = this.allocations[sectionIndex + RenderRegion.REGION_SIZE]; - if (indexAllocation != null) { - SectionRenderDataUnsafe.setIndexOffset(data, indexAllocation.getOffset()); - } + var data = this.getDataPointer(sectionIndex); + var indexAllocation = this.allocations[sectionIndex + RenderRegion.REGION_SIZE]; + if (indexAllocation != null) { + SectionRenderDataUnsafe.setIndexOffset(data, indexAllocation.getOffset()); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java index ebeaf039bb..569f20e8fd 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java @@ -124,7 +124,7 @@ public SectionRenderDataStorage createStorage(TerrainRenderPass pass) { public void refreshTesselation(CommandList commandList) { if (this.resources != null) { - this.resources.deleteTessellations(commandList); + this.resources.deleteTessellation(commandList); this.resources.deleteIndexedTessellation(commandList); } @@ -246,7 +246,7 @@ public GlTessellation getIndexedTessellation() { return this.indexedTessellation; } - public void deleteTessellations(CommandList commandList) { + public void deleteTessellation(CommandList commandList) { if (this.tessellation != null) { this.tessellation.delete(commandList); this.tessellation = null; @@ -269,7 +269,7 @@ public GlBuffer getIndexBuffer() { } public void delete(CommandList commandList) { - this.deleteTessellations(commandList); + this.deleteTessellation(commandList); this.deleteIndexedTessellation(commandList); this.geometryArena.delete(commandList); this.indexArena.delete(commandList); From 80c2a4dc0be688bcaa93a220e87b25044c440d7b Mon Sep 17 00:00:00 2001 From: douira Date: Sun, 24 Dec 2023 01:37:10 +0100 Subject: [PATCH 205/256] don't submit tasks if sections are not in a matching queue, potentially fixes some issues with rebuilds going missing --- .../sodium/client/render/chunk/RenderSectionManager.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index 0f9f3c5664..39a500b2ce 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -410,6 +410,12 @@ private void submitSectionTasks(ChunkJobCollector collector, ChunkUpdateType typ continue; } + // stop if the section is in this list but doesn't have this update type + var pendingUpdate = section.getPendingUpdate(); + if (pendingUpdate != null && pendingUpdate != type) { + continue; + } + int frame = this.lastUpdatedFrame; ChunkBuilderTask task; if (type == ChunkUpdateType.SORT || type == ChunkUpdateType.IMPORTANT_SORT) { @@ -509,8 +515,6 @@ public int getVisibleChunkCount() { } public void scheduleSort(long sectionPos, boolean isDirectTrigger) { - // TODO: Does this need to invalidate the section cache? - RenderSection section = this.sectionByPosition.get(sectionPos); if (section != null) { From f02a17e33205cb78ae611b25f1f8a02f819a16d2 Mon Sep 17 00:00:00 2001 From: douira Date: Sun, 24 Dec 2023 14:55:42 +0100 Subject: [PATCH 206/256] change when what jobs are scheduled, fixes flawless frames, makes important sort tasks complete in the same frame --- .../client/render/SodiumWorldRenderer.java | 32 ++++++------ .../render/chunk/RenderSectionManager.java | 50 +++++++++++++++---- .../trigger/SortTriggering.java | 4 ++ 3 files changed, 58 insertions(+), 28 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index 77a9135b56..e59d27a5ba 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -176,17 +176,19 @@ public void setupTerrain(Camera camera, this.lastCameraPos = new Vector3d(pos); } boolean cameraLocationChanged = !pos.equals(this.lastCameraPos); - boolean dirty = cameraLocationChanged || - pitch != this.lastCameraPitch || yaw != this.lastCameraYaw || fogDistance != this.lastFogDistance; + boolean cameraAngleChanged = pitch != this.lastCameraPitch || yaw != this.lastCameraYaw || fogDistance != this.lastFogDistance; - if (dirty) { + this.lastCameraPitch = pitch; + this.lastCameraYaw = yaw; + + if (cameraLocationChanged || cameraAngleChanged) { this.renderSectionManager.markGraphDirty(); } - this.lastCameraPitch = pitch; - this.lastCameraYaw = yaw; this.lastFogDistance = fogDistance; + this.renderSectionManager.updateCameraState(pos, camera); + if (cameraLocationChanged) { profiler.swap("translucent_triggering"); @@ -194,26 +196,20 @@ public void setupTerrain(Camera camera, this.lastCameraPos = new Vector3d(pos); } - profiler.swap("chunk_update"); - - this.renderSectionManager.updateCameraState(pos, camera); - this.renderSectionManager.updateChunks(updateChunksImmediately); - - profiler.swap("chunk_upload"); - - this.renderSectionManager.uploadChunks(); - if (this.renderSectionManager.needsUpdate()) { profiler.swap("chunk_render_lists"); this.renderSectionManager.update(camera, viewport, frame, spectator); } - if (updateChunksImmediately) { - profiler.swap("chunk_upload_immediately"); + profiler.swap("chunk_update"); - this.renderSectionManager.uploadChunks(); - } + this.renderSectionManager.cleanupAndFlip(); + this.renderSectionManager.updateChunks(updateChunksImmediately); + + profiler.swap("chunk_upload"); + + this.renderSectionManager.uploadChunks(); profiler.swap("chunk_render_tick"); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index 39a500b2ce..c363ce8a57 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -82,6 +82,8 @@ public class RenderSectionManager { private final SortTriggering ts; + private ChunkJobCollector lastBlockingCollector; + @NotNull private SortedRenderLists renderLists; @@ -286,21 +288,49 @@ public boolean isSectionVisible(int x, int y, int z) { return render.getLastVisibleFrame() == this.lastUpdatedFrame; } - public void updateChunks(boolean updateImmediately) { + public void cleanupAndFlip() { this.sectionCache.cleanup(); this.regions.update(); + } + + public void updateChunks(boolean updateImmediately) { + var thisFrameBlockingCollector = this.lastBlockingCollector; + if (thisFrameBlockingCollector == null) { + thisFrameBlockingCollector = new ChunkJobCollector(Integer.MAX_VALUE, this.buildResults::add); + } - var blockingCollector = new ChunkJobCollector(Integer.MAX_VALUE, this.buildResults::add); - var deferredCollector = new ChunkJobCollector(this.builder.getSchedulingBudget(), this.buildResults::add); - var maybeBlockingCollector = updateImmediately ? blockingCollector : deferredCollector; + if (updateImmediately) { + // for a perfect frame where everything is finished use the last frame's blocking collector + // and add all tasks to it so that they're waited on + this.submitSectionTasks(thisFrameBlockingCollector, thisFrameBlockingCollector, thisFrameBlockingCollector); - this.submitSectionTasks(blockingCollector, ChunkUpdateType.IMPORTANT_REBUILD); - this.submitSectionTasks(blockingCollector, ChunkUpdateType.IMPORTANT_SORT); - this.submitSectionTasks(maybeBlockingCollector, ChunkUpdateType.REBUILD); - this.submitSectionTasks(maybeBlockingCollector, ChunkUpdateType.INITIAL_BUILD); - this.submitSectionTasks(maybeBlockingCollector, ChunkUpdateType.SORT); + thisFrameBlockingCollector.awaitCompletion(this.builder); + this.lastBlockingCollector = null; + } else { + var nextFrameBlockingCollector = new ChunkJobCollector(Integer.MAX_VALUE, this.buildResults::add); + var deferredCollector = new ChunkJobCollector(this.builder.getSchedulingBudget(), this.buildResults::add); + + // TODO: with a user-facing option disable using a same-frame blocking collector and just use previous-frame if the user wants to avoid blocking at all costs + this.submitSectionTasks(thisFrameBlockingCollector, nextFrameBlockingCollector, deferredCollector); + + // wait on this frame's blocking collector which contains the important tasks from this frame + // and semi-important tasks from the last frame + thisFrameBlockingCollector.awaitCompletion(this.builder); + + // store the semi-important collector to wait on it in the next frame + this.lastBlockingCollector = nextFrameBlockingCollector; + } + } - blockingCollector.awaitCompletion(this.builder); + private void submitSectionTasks( + ChunkJobCollector importantCollector, + ChunkJobCollector semiImportantCollector, + ChunkJobCollector deferredCollector) { + this.submitSectionTasks(importantCollector, ChunkUpdateType.IMPORTANT_SORT); + this.submitSectionTasks(semiImportantCollector, ChunkUpdateType.IMPORTANT_REBUILD); + this.submitSectionTasks(deferredCollector, ChunkUpdateType.REBUILD); + this.submitSectionTasks(deferredCollector, ChunkUpdateType.INITIAL_BUILD); + this.submitSectionTasks(deferredCollector, ChunkUpdateType.SORT); } public void uploadChunks() { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java index bdc8feccb6..1ca67c60a2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java @@ -20,6 +20,10 @@ * of translucent data objects for each sort type and delegates triggering of * sections for dynamic sorting to the trigger components. * + * TODO: see if the duplicated geometry bug happens when: + * - hashing for triggering is removed + * - hashing for translucent data reuse is removed + * * @author douira (the translucent_sorting package) */ public class SortTriggering { From 70d2f5ef562b6c01f8fd9b7b6f2c1d26a04df20d Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 25 Dec 2023 01:29:28 +0100 Subject: [PATCH 207/256] reorder RSM to be more coherent --- .../render/chunk/RenderSectionManager.java | 89 +++++++++---------- 1 file changed, 44 insertions(+), 45 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index c363ce8a57..1bb825673b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -288,51 +288,6 @@ public boolean isSectionVisible(int x, int y, int z) { return render.getLastVisibleFrame() == this.lastUpdatedFrame; } - public void cleanupAndFlip() { - this.sectionCache.cleanup(); - this.regions.update(); - } - - public void updateChunks(boolean updateImmediately) { - var thisFrameBlockingCollector = this.lastBlockingCollector; - if (thisFrameBlockingCollector == null) { - thisFrameBlockingCollector = new ChunkJobCollector(Integer.MAX_VALUE, this.buildResults::add); - } - - if (updateImmediately) { - // for a perfect frame where everything is finished use the last frame's blocking collector - // and add all tasks to it so that they're waited on - this.submitSectionTasks(thisFrameBlockingCollector, thisFrameBlockingCollector, thisFrameBlockingCollector); - - thisFrameBlockingCollector.awaitCompletion(this.builder); - this.lastBlockingCollector = null; - } else { - var nextFrameBlockingCollector = new ChunkJobCollector(Integer.MAX_VALUE, this.buildResults::add); - var deferredCollector = new ChunkJobCollector(this.builder.getSchedulingBudget(), this.buildResults::add); - - // TODO: with a user-facing option disable using a same-frame blocking collector and just use previous-frame if the user wants to avoid blocking at all costs - this.submitSectionTasks(thisFrameBlockingCollector, nextFrameBlockingCollector, deferredCollector); - - // wait on this frame's blocking collector which contains the important tasks from this frame - // and semi-important tasks from the last frame - thisFrameBlockingCollector.awaitCompletion(this.builder); - - // store the semi-important collector to wait on it in the next frame - this.lastBlockingCollector = nextFrameBlockingCollector; - } - } - - private void submitSectionTasks( - ChunkJobCollector importantCollector, - ChunkJobCollector semiImportantCollector, - ChunkJobCollector deferredCollector) { - this.submitSectionTasks(importantCollector, ChunkUpdateType.IMPORTANT_SORT); - this.submitSectionTasks(semiImportantCollector, ChunkUpdateType.IMPORTANT_REBUILD); - this.submitSectionTasks(deferredCollector, ChunkUpdateType.REBUILD); - this.submitSectionTasks(deferredCollector, ChunkUpdateType.INITIAL_BUILD); - this.submitSectionTasks(deferredCollector, ChunkUpdateType.SORT); - } - public void uploadChunks() { var results = this.collectChunkBuildResults(); @@ -430,6 +385,50 @@ private ArrayList collectChunkBuildResults() { return results; } + public void cleanupAndFlip() { + this.sectionCache.cleanup(); + this.regions.update(); + } + + public void updateChunks(boolean updateImmediately) { + var thisFrameBlockingCollector = this.lastBlockingCollector; + if (thisFrameBlockingCollector == null) { + thisFrameBlockingCollector = new ChunkJobCollector(Integer.MAX_VALUE, this.buildResults::add); + } + + if (updateImmediately) { + // for a perfect frame where everything is finished use the last frame's blocking collector + // and add all tasks to it so that they're waited on + this.submitSectionTasks(thisFrameBlockingCollector, thisFrameBlockingCollector, thisFrameBlockingCollector); + + thisFrameBlockingCollector.awaitCompletion(this.builder); + this.lastBlockingCollector = null; + } else { + var nextFrameBlockingCollector = new ChunkJobCollector(Integer.MAX_VALUE, this.buildResults::add); + var deferredCollector = new ChunkJobCollector(this.builder.getSchedulingBudget(), this.buildResults::add); + + this.submitSectionTasks(thisFrameBlockingCollector, nextFrameBlockingCollector, deferredCollector); + + // wait on this frame's blocking collector which contains the important tasks from this frame + // and semi-important tasks from the last frame + thisFrameBlockingCollector.awaitCompletion(this.builder); + + // store the semi-important collector to wait on it in the next frame + this.lastBlockingCollector = nextFrameBlockingCollector; + } + } + + private void submitSectionTasks( + ChunkJobCollector importantCollector, + ChunkJobCollector semiImportantCollector, + ChunkJobCollector deferredCollector) { + this.submitSectionTasks(importantCollector, ChunkUpdateType.IMPORTANT_SORT); + this.submitSectionTasks(semiImportantCollector, ChunkUpdateType.IMPORTANT_REBUILD); + this.submitSectionTasks(deferredCollector, ChunkUpdateType.REBUILD); + this.submitSectionTasks(deferredCollector, ChunkUpdateType.INITIAL_BUILD); + this.submitSectionTasks(deferredCollector, ChunkUpdateType.SORT); + } + private void submitSectionTasks(ChunkJobCollector collector, ChunkUpdateType type) { var queue = this.taskLists.get(type); From 97c108f6e4f84717f2bdd163ae76648609551416 Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 25 Dec 2023 01:54:10 +0100 Subject: [PATCH 208/256] add option to control how much sorting is deferred --- .../client/gui/SodiumGameOptionPages.java | 8 ++++++++ .../sodium/client/gui/SodiumGameOptions.java | 18 ++++++++++++++++++ .../render/chunk/RenderSectionManager.java | 19 +++++++++++++++++-- .../resources/assets/sodium/lang/en_us.json | 7 ++++++- 4 files changed, 49 insertions(+), 3 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java index e612ff6fe8..02342efabf 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java @@ -259,6 +259,14 @@ public static OptionPage performance() { .setBinding((opts, value) -> opts.performance.alwaysDeferChunkUpdates = value, opts -> opts.performance.alwaysDeferChunkUpdates) .setFlags(OptionFlag.REQUIRES_RENDERER_UPDATE) .build()) + .add(OptionImpl.createBuilder(SodiumGameOptions.DeferSortMode.class, sodiumOpts) + .setName(Text.translatable("sodium.options.defer_sorting.name")) + .setTooltip(Text.translatable("sodium.options.defer_sorting.tooltip")) + .setControl(option -> new CyclingControl<>(option, SodiumGameOptions.DeferSortMode.class)) + .setImpact(OptionImpact.HIGH) + .setBinding((opts, value) -> opts.performance.deferSortMode = value, opts -> opts.performance.deferSortMode) + .setFlags(OptionFlag.REQUIRES_RENDERER_UPDATE) + .build()) .build()); groups.add(OptionGroup.createBuilder() diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java index ba74e4524d..52a683aa68 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java @@ -39,6 +39,7 @@ public static class PerformanceSettings { public int chunkBuilderThreads = 0; @SerializedName("always_defer_chunk_updates_v2") // this will reset the option in older configs public boolean alwaysDeferChunkUpdates = true; + public DeferSortMode deferSortMode = DeferSortMode.DEFER_ONE_FRAME; public boolean animateOnlyVisibleTextures = true; public boolean useEntityCulling = true; @@ -49,6 +50,23 @@ public static class PerformanceSettings { public SortBehavior sortBehavior = SortBehavior.DYNAMIC; } + public enum DeferSortMode implements TextProvider { + ALWAYS("sodium.options.defer_sorting.always"), + DEFER_ONE_FRAME("sodium.options.defer_sorting.defer_one_frame"), + DEFER_ZERO_FRAMES("sodium.options.defer_sorting.defer_zero_frames"); + + private final Text name; + + DeferSortMode(String name) { + this.name = Text.translatable(name); + } + + @Override + public Text getLocalizedName() { + return this.name; + } + } + public enum SortBehavior implements TextProvider { OFF("options.off", "OFF"), STATIC("sodium.options.sort_behavior.reduced", "S"), diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index 1bb825673b..8fbead31a9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -11,6 +11,7 @@ import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.gl.device.CommandList; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; +import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions.DeferSortMode; import me.jellysquid.mods.sodium.client.render.chunk.compile.BuilderTaskOutput; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildOutput; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkSortOutput; @@ -407,7 +408,13 @@ public void updateChunks(boolean updateImmediately) { var nextFrameBlockingCollector = new ChunkJobCollector(Integer.MAX_VALUE, this.buildResults::add); var deferredCollector = new ChunkJobCollector(this.builder.getSchedulingBudget(), this.buildResults::add); - this.submitSectionTasks(thisFrameBlockingCollector, nextFrameBlockingCollector, deferredCollector); + // if zero frame delay is allowed, submit important sorts with the current frame blocking collector. + // otherwise submit with the collector that the next frame is blocking on. + if (allowZeroFrameSortWait()) { + this.submitSectionTasks(thisFrameBlockingCollector, nextFrameBlockingCollector, deferredCollector); + } else { + this.submitSectionTasks(nextFrameBlockingCollector, nextFrameBlockingCollector, deferredCollector); + } // wait on this frame's blocking collector which contains the important tasks from this frame // and semi-important tasks from the last frame @@ -548,7 +555,7 @@ public void scheduleSort(long sectionPos, boolean isDirectTrigger) { if (section != null) { var pendingUpdate = ChunkUpdateType.SORT; - if (this.shouldPrioritizeTask(section)) { + if (allowImportantSorts() && this.shouldPrioritizeTask(section)) { pendingUpdate = ChunkUpdateType.IMPORTANT_SORT; } pendingUpdate = ChunkUpdateType.getPromotionUpdateType(section.getPendingUpdate(), pendingUpdate); @@ -594,6 +601,14 @@ private static boolean allowImportantRebuilds() { return !SodiumClientMod.options().performance.alwaysDeferChunkUpdates; } + private static boolean allowImportantSorts() { + return SodiumClientMod.options().performance.deferSortMode != DeferSortMode.ALWAYS; + } + + private static boolean allowZeroFrameSortWait() { + return SodiumClientMod.options().performance.deferSortMode == DeferSortMode.DEFER_ZERO_FRAMES; + } + private float getEffectiveRenderDistance() { var color = RenderSystem.getShaderFogColor(); var distance = RenderSystem.getShaderFogEnd(); diff --git a/src/main/resources/assets/sodium/lang/en_us.json b/src/main/resources/assets/sodium/lang/en_us.json index abcaaffe17..73a9ba9829 100644 --- a/src/main/resources/assets/sodium/lang/en_us.json +++ b/src/main/resources/assets/sodium/lang/en_us.json @@ -46,9 +46,14 @@ "sodium.options.use_persistent_mapping.name": "Use Persistent Mapping", "sodium.options.use_persistent_mapping.tooltip": "If enabled, a small amount of memory will be persistently mapped as a staging buffer for chunk uploading, helping to reduce CPU overhead and frame time instability when loading or updating chunks.\n\nRequires OpenGL 4.4 or ARB_buffer_storage.", "sodium.options.chunk_update_threads.name": "Chunk Update Threads", - "sodium.options.chunk_update_threads.tooltip": "Specifies the number of threads to use for chunk building. Using more threads can speed up chunk loading and update speed, but may negatively impact frame times.", + "sodium.options.chunk_update_threads.tooltip": "Specifies the number of threads to use for chunk building and sorting. Using more threads can speed up chunk loading and update speed, but may negatively impact frame times.", "sodium.options.always_defer_chunk_updates.name": "Always Defer Chunk Updates", "sodium.options.always_defer_chunk_updates.tooltip": "If enabled, rendering will never wait for chunk updates to finish, even if they are important. This can greatly improve frame rates in some scenarios, but it may create significant visual lag in the world.", + "sodium.options.defer_sorting.name": "Defer Sorting", + "sodium.options.defer_sorting.always": "Always", + "sodium.options.defer_sorting.defer_one_frame": "Medium", + "sodium.options.defer_sorting.defer_zero_frames": "Least", + "sodium.options.defer_sorting.tooltip": "Controls how much rendering waits for translucency sorting to finish, even if it is important. Brief holes in translucent blocks may be visible unless set to \"Least\".", "sodium.options.use_no_error_context.name": "Use No Error Context", "sodium.options.use_no_error_context.tooltip": "If enabled, the OpenGL context will be created with error checking disabled. This may slightly improve performance, but it also increases the risk that the game will crash instead of gracefully handling OpenGL errors. You should disable this option if you are experiencing sudden unexplained crashes.", "sodium.options.buttons.undo": "Undo", From bb3098c230ef1e9e6a4ae08e9c310dca3ffa289a Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 25 Dec 2023 03:10:38 +0100 Subject: [PATCH 209/256] defer sorting feels like medium impact --- .../mods/sodium/client/gui/SodiumGameOptionPages.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java index 02342efabf..8ad4c32b44 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java @@ -263,7 +263,7 @@ public static OptionPage performance() { .setName(Text.translatable("sodium.options.defer_sorting.name")) .setTooltip(Text.translatable("sodium.options.defer_sorting.tooltip")) .setControl(option -> new CyclingControl<>(option, SodiumGameOptions.DeferSortMode.class)) - .setImpact(OptionImpact.HIGH) + .setImpact(OptionImpact.MEDIUM) .setBinding((opts, value) -> opts.performance.deferSortMode = value, opts -> opts.performance.deferSortMode) .setFlags(OptionFlag.REQUIRES_RENDERER_UPDATE) .build()) From 94d83c387f969ab96094d2bf878dce5b71203fcd Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 25 Dec 2023 04:37:49 +0100 Subject: [PATCH 210/256] fix float sorting in SNR --- .../data/StaticNormalRelativeData.java | 9 ++++++--- .../me/jellysquid/mods/sodium/client/util/MathUtil.java | 8 ++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java index a301f0eeca..30be400be3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java @@ -10,6 +10,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortType; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; +import me.jellysquid.mods.sodium.client.util.MathUtil; import me.jellysquid.mods.sodium.client.util.NativeBuffer; import me.jellysquid.mods.sodium.client.util.sorting.VertexSorters; import net.minecraft.util.math.ChunkSectionPos; @@ -40,8 +41,9 @@ private static StaticNormalRelativeData fromDoubleUnaligned(BuiltSectionMeshPart TQuad[] quads, ChunkSectionPos sectionPos) { long[] sortData = new long[quads.length]; - for (int i = 0; i < quads.length; i++) { - sortData[i] = (long) quads[i].getDotProduct() << 32 | i; + for (int quadIndex = 0; quadIndex < quads.length; quadIndex++) { + int dotProductComponent = MathUtil.floatToComparableInt(quads[quadIndex].getDotProduct()); + sortData[quadIndex] = (long) dotProductComponent << 32 | quadIndex; } var buffer = PresentTranslucentData.nativeBufferForQuads(quads); @@ -63,7 +65,8 @@ private static StaticNormalRelativeData fromMixed(BuiltSectionMeshParts transluc for (int quadIndex = 0; quadIndex < quads.length; quadIndex++) { var quad = quads[quadIndex]; - sortData[quadIndex] = (long) quad.getDotProduct() << 32 | quadIndex; + int dotProductComponent = MathUtil.floatToComparableInt(quad.getDotProduct()); + sortData[quadIndex] = (long) dotProductComponent << 32 | quadIndex; } var buffer = PresentTranslucentData.nativeBufferForQuads(quads); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/MathUtil.java b/src/main/java/me/jellysquid/mods/sodium/client/util/MathUtil.java index c95a224de6..da14232293 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/MathUtil.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/MathUtil.java @@ -11,4 +11,12 @@ public static boolean isPowerOfTwo(int n) { public static long toMib(long bytes) { return bytes / (1024L * 1024L); // 1 MiB = 1048576 (2^20) bytes } + + /** + * Converts a float to a comparable integer value. This is used to compare + * floating point values by their int bits (for example packed in a long). + */ + public static int floatToComparableInt(float f) { + return Float.floatToRawIntBits(f) ^ (f >= 0 ? 0x80000000 : 0xffffffff); + } } From c81f53a7dbbaa406aab2b3dceaab97b7aac59e68 Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 25 Dec 2023 04:38:11 +0100 Subject: [PATCH 211/256] remove unused mixed and split direction data fields --- .../translucent_sorting/TranslucentGeometryCollector.java | 6 +++--- .../chunk/translucent_sorting/data/MixedDirectionData.java | 2 -- .../chunk/translucent_sorting/data/SplitDirectionData.java | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java index d29286c7dc..b775f4fe56 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java @@ -358,7 +358,7 @@ private SortType sortTypeHeuristic() { } if (!this.hasUnaligned) { - boolean twoOpposingNormals = this.alignedFacingBitmap == ModelQuadFacing.OPPOSING_X + boolean opposingAlignedNormals = this.alignedFacingBitmap == ModelQuadFacing.OPPOSING_X || this.alignedFacingBitmap == ModelQuadFacing.OPPOSING_Y || this.alignedFacingBitmap == ModelQuadFacing.OPPOSING_Z; @@ -366,7 +366,7 @@ private SortType sortTypeHeuristic() { // if there are just two normals, they are exact opposites of eachother and they // each only have one distance, there is no way to see through one face to the // other. - if (planeCount == 2 && twoOpposingNormals) { + if (planeCount == 2 && opposingAlignedNormals) { return SortType.NONE; } @@ -396,7 +396,7 @@ private SortType sortTypeHeuristic() { // there are up to two normals that are opposing, this means no dynamic sorting // is necessary. Without static sorting, the geometry to trigger on could be // reduced but this isn't done here as we assume static sorting is possible. - if (twoOpposingNormals || alignedNormalCount == 1) { + if (opposingAlignedNormals || alignedNormalCount == 1) { return SortType.STATIC_NORMAL_RELATIVE; } } else if (alignedNormalCount == 0) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/MixedDirectionData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/MixedDirectionData.java index 930fd77b5f..b9cf0df144 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/MixedDirectionData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/MixedDirectionData.java @@ -6,12 +6,10 @@ import net.minecraft.util.math.ChunkSectionPos; public abstract class MixedDirectionData extends PresentTranslucentData { - public final VertexRange range; private final VertexRange[] ranges = new VertexRange[ModelQuadFacing.COUNT]; MixedDirectionData(ChunkSectionPos sectionPos, NativeBuffer buffer, VertexRange range) { super(sectionPos, buffer); - this.range = range; this.ranges[ModelQuadFacing.UNASSIGNED.ordinal()] = range; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/SplitDirectionData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/SplitDirectionData.java index 0982875245..0116f0121c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/SplitDirectionData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/SplitDirectionData.java @@ -10,7 +10,7 @@ * starting at zero for each facing. */ public abstract class SplitDirectionData extends PresentTranslucentData { - public final VertexRange[] ranges; + private final VertexRange[] ranges; public SplitDirectionData(ChunkSectionPos sectionPos, NativeBuffer buffer, VertexRange[] ranges) { super(sectionPos, buffer); From 8ff7cfedb440a2aaed52c701655e6cec32273c21 Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 25 Dec 2023 04:40:13 +0100 Subject: [PATCH 212/256] remove unused vertex sorters code --- .../data/StaticNormalRelativeData.java | 12 ----- .../client/util/sorting/VertexSorters.java | 51 ------------------- 2 files changed, 63 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java index 30be400be3..f24571f570 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java @@ -3,16 +3,12 @@ import java.nio.IntBuffer; import java.util.Arrays; -import com.mojang.blaze3d.systems.VertexSorter; - import me.jellysquid.mods.sodium.client.gl.util.VertexRange; -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortType; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; import me.jellysquid.mods.sodium.client.util.MathUtil; import me.jellysquid.mods.sodium.client.util.NativeBuffer; -import me.jellysquid.mods.sodium.client.util.sorting.VertexSorters; import net.minecraft.util.math.ChunkSectionPos; /** @@ -29,14 +25,6 @@ public SortType getSortType() { return SortType.STATIC_NORMAL_RELATIVE; } - private static final VertexSorter[] SORTERS = new VertexSorter[ModelQuadFacing.DIRECTIONS]; - - static { - for (int i = 0; i < ModelQuadFacing.DIRECTIONS; i++) { - SORTERS[i] = VertexSorters.sortByAxis(ModelQuadFacing.VALUES[i]); - } - } - private static StaticNormalRelativeData fromDoubleUnaligned(BuiltSectionMeshParts translucentMesh, TQuad[] quads, ChunkSectionPos sectionPos) { long[] sortData = new long[quads.length]; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/VertexSorters.java b/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/VertexSorters.java index 1be7fca4a3..c6601a7b90 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/VertexSorters.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/VertexSorters.java @@ -11,29 +11,6 @@ public static VertexSorter sortByDistance(Vector3f origin) { return new SortByDistance(origin); } - public static VertexSorter sortByAxis(ModelQuadFacing facing) { - switch (facing) { - case POS_X: - return new SortByAxis(0, 1.0F); - case NEG_X: - return new SortByAxis(0, -1.0F); - case POS_Y: - return new SortByAxis(1, 1.0F); - case NEG_Y: - return new SortByAxis(1, -1.0F); - case POS_Z: - return new SortByAxis(2, 1.0F); - case NEG_Z: - return new SortByAxis(2, -1.0F); - default: - throw new IllegalArgumentException("Unknown facing: " + facing); - } - } - - public static VertexSorter sortByNormalRelative(Vector3f normal) { - return new SortNormalRelative(normal); - } - private static class SortByDistance extends AbstractVertexSorter { private final Vector3f origin; @@ -48,34 +25,6 @@ protected float getKey(Vector3f position) { } } - private static class SortByAxis extends AbstractVertexSorter { - private final int axis; - private final float sign; - - private SortByAxis(int axis, float sign) { - this.axis = axis; - this.sign = sign; - } - - @Override - protected float getKey(Vector3f position) { - return -sign * position.get(this.axis); - } - } - - private static class SortNormalRelative extends AbstractVertexSorter { - private final Vector3f normal; - - private SortNormalRelative(Vector3f normal) { - this.normal = normal; - } - - @Override - protected float getKey(Vector3f position) { - return this.normal.dot(position); - } - } - /** * Sorts the keys given by the subclass by descending value. */ From 405e922ea05aca9c638c057d3c16c0758dbc9a1d Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 25 Dec 2023 04:40:33 +0100 Subject: [PATCH 213/256] unused import --- .../mods/sodium/client/util/sorting/VertexSorters.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/VertexSorters.java b/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/VertexSorters.java index c6601a7b90..54479d9de4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/VertexSorters.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/VertexSorters.java @@ -2,8 +2,6 @@ import com.mojang.blaze3d.systems.VertexSorter; -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; - import org.joml.Vector3f; public class VertexSorters { From 9873b0552332f070db7da1e68ff1ed1e36c0204e Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 25 Dec 2023 05:35:45 +0100 Subject: [PATCH 214/256] formatting --- .../mods/sodium/client/render/chunk/region/RenderRegion.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java index 569f20e8fd..d9c601cbb8 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java @@ -115,8 +115,8 @@ public SectionRenderDataStorage createStorage(TerrainRenderPass pass) { var storage = this.sectionRenderData.get(pass); if (storage == null) { - this.sectionRenderData.put(pass, storage = new SectionRenderDataStorage( - pass == DefaultTerrainRenderPasses.TRANSLUCENT)); + storage = new SectionRenderDataStorage(pass == DefaultTerrainRenderPasses.TRANSLUCENT); + this.sectionRenderData.put(pass, storage); } return storage; From deeaa6f8cef7221d81261454396965f2b378fdf4 Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 25 Dec 2023 06:05:07 +0100 Subject: [PATCH 215/256] fix snr sorting --- .../data/AnyOrderData.java | 23 +++++---- .../data/StaticNormalRelativeData.java | 51 ++++++++++++------- .../trigger/SortTriggering.java | 4 -- 3 files changed, 46 insertions(+), 32 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/AnyOrderData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/AnyOrderData.java index 9206160464..b0cbb34dbb 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/AnyOrderData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/AnyOrderData.java @@ -31,20 +31,25 @@ public SortType getSortType() { return SortType.NONE; } + /** + * Important: The vertex indexes must start at zero for each facing. + */ public static AnyOrderData fromMesh(BuiltSectionMeshParts translucentMesh, TQuad[] quads, ChunkSectionPos sectionPos, NativeBuffer buffer) { buffer = PresentTranslucentData.nativeBufferForQuads(buffer, quads); var indexBuffer = buffer.getDirectBuffer().asIntBuffer(); - var counter = 0; - var lastFacing = quads[0].getFacing(); - for (int i = 0; i < quads.length; i++) { - var currentFacing = quads[i].getFacing(); - if (i > 0 && currentFacing != lastFacing) { - counter = 0; + + var ranges = translucentMesh.getVertexRanges(); + for (var range : ranges) { + if (range == null) { + continue; + } + + int count = TranslucentData.vertexCountToQuadCount(range.vertexCount()); + for (int i = 0; i < count; i++) { + TranslucentData.writeQuadVertexIndexes(indexBuffer, i); } - lastFacing = currentFacing; - TranslucentData.writeQuadVertexIndexes(indexBuffer, counter++); } - return new AnyOrderData(sectionPos, buffer, translucentMesh.getVertexRanges()); + return new AnyOrderData(sectionPos, buffer, ranges); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java index f24571f570..e5facbb41e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java @@ -27,6 +27,9 @@ public SortType getSortType() { private static StaticNormalRelativeData fromDoubleUnaligned(BuiltSectionMeshParts translucentMesh, TQuad[] quads, ChunkSectionPos sectionPos) { + var buffer = PresentTranslucentData.nativeBufferForQuads(quads); + IntBuffer bufferBuilder = buffer.getDirectBuffer().asIntBuffer(); + long[] sortData = new long[quads.length]; for (int quadIndex = 0; quadIndex < quads.length; quadIndex++) { @@ -34,9 +37,6 @@ private static StaticNormalRelativeData fromDoubleUnaligned(BuiltSectionMeshPart sortData[quadIndex] = (long) dotProductComponent << 32 | quadIndex; } - var buffer = PresentTranslucentData.nativeBufferForQuads(quads); - IntBuffer bufferBuilder = buffer.getDirectBuffer().asIntBuffer(); - Arrays.sort(sortData); for (int i = 0; i < quads.length; i++) { @@ -46,32 +46,45 @@ private static StaticNormalRelativeData fromDoubleUnaligned(BuiltSectionMeshPart return new StaticNormalRelativeData(sectionPos, buffer, translucentMesh.getVertexRanges()); } + /** + * Important: The vertex indexes must start at zero for each facing. + */ private static StaticNormalRelativeData fromMixed(BuiltSectionMeshParts translucentMesh, TQuad[] quads, ChunkSectionPos sectionPos) { - var ranges = translucentMesh.getVertexRanges(); - long[] sortData = new long[quads.length]; - - for (int quadIndex = 0; quadIndex < quads.length; quadIndex++) { - var quad = quads[quadIndex]; - int dotProductComponent = MathUtil.floatToComparableInt(quad.getDotProduct()); - sortData[quadIndex] = (long) dotProductComponent << 32 | quadIndex; - } - var buffer = PresentTranslucentData.nativeBufferForQuads(quads); IntBuffer bufferBuilder = buffer.getDirectBuffer().asIntBuffer(); + var ranges = translucentMesh.getVertexRanges(); + var maxRangeSize = 0; for (var range : ranges) { if (range != null) { - int start = TranslucentData.vertexCountToQuadCount(range.vertexStart()); - int count = TranslucentData.vertexCountToQuadCount(range.vertexCount()); - if (count > 1) { - Arrays.sort(sortData, start, start + count); - } + maxRangeSize = Math.max(maxRangeSize, range.vertexCount()); } } - for (int i = 0; i < quads.length; i++) { - TranslucentData.writeQuadVertexIndexes(bufferBuilder, (int) sortData[i]); + long[] sortData = new long[TranslucentData.vertexCountToQuadCount(maxRangeSize)]; + + int quadIndex = 0; + for (var range : ranges) { + if (range == null) { + continue; + } + + int count = TranslucentData.vertexCountToQuadCount(range.vertexCount()); + + for (int i = 0; i < count; i++) { + var quad = quads[quadIndex++]; + int dotProductComponent = MathUtil.floatToComparableInt(quad.getDotProduct()); + sortData[i] = (long) dotProductComponent << 32 | i; + } + + if (count > 1) { + Arrays.sort(sortData, 0, count); + } + + for (int i = 0; i < count; i++) { + TranslucentData.writeQuadVertexIndexes(bufferBuilder, (int) sortData[i]); + } } return new StaticNormalRelativeData(sectionPos, buffer, ranges); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java index 1ca67c60a2..bdc8feccb6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java @@ -20,10 +20,6 @@ * of translucent data objects for each sort type and delegates triggering of * sections for dynamic sorting to the trigger components. * - * TODO: see if the duplicated geometry bug happens when: - * - hashing for triggering is removed - * - hashing for translucent data reuse is removed - * * @author douira (the translucent_sorting package) */ public class SortTriggering { From 04ee500c2fb2be2862882e074a4a8f6693b5ff58 Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 25 Dec 2023 17:11:17 +0100 Subject: [PATCH 216/256] static topo sort is taken care of by heuristic already --- .../translucent_sorting/data/StaticTopoAcyclicData.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticTopoAcyclicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticTopoAcyclicData.java index 7ee48d2570..c6cf93949e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticTopoAcyclicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticTopoAcyclicData.java @@ -13,8 +13,6 @@ * needs to change. */ public class StaticTopoAcyclicData extends MixedDirectionData { - private static final int MAX_STATIC_TOPO_SORT_QUADS = 1000; - StaticTopoAcyclicData(ChunkSectionPos sectionPos, NativeBuffer buffer, VertexRange range) { super(sectionPos, buffer, range); } @@ -26,10 +24,6 @@ public SortType getSortType() { public static StaticTopoAcyclicData fromMesh(BuiltSectionMeshParts translucentMesh, TQuad[] quads, ChunkSectionPos sectionPos, NativeBuffer buffer) { - if (quads.length > MAX_STATIC_TOPO_SORT_QUADS) { - return null; - } - VertexRange range = TranslucentData.getUnassignedVertexRange(translucentMesh); var indexBuffer = buffer.getDirectBuffer().asIntBuffer(); From ba00170ca415be99bd983564f4979e830a5f6235 Mon Sep 17 00:00:00 2001 From: douira Date: Tue, 26 Dec 2023 00:25:15 +0100 Subject: [PATCH 217/256] add sort defer mode to debug string --- .../mods/sodium/client/gui/SodiumGameOptions.java | 14 ++++++++++---- .../trigger/SortTriggering.java | 5 +++-- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java index 52a683aa68..45578b5f17 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java @@ -51,20 +51,26 @@ public static class PerformanceSettings { } public enum DeferSortMode implements TextProvider { - ALWAYS("sodium.options.defer_sorting.always"), - DEFER_ONE_FRAME("sodium.options.defer_sorting.defer_one_frame"), - DEFER_ZERO_FRAMES("sodium.options.defer_sorting.defer_zero_frames"); + ALWAYS("sodium.options.defer_sorting.always", "A"), + DEFER_ONE_FRAME("sodium.options.defer_sorting.defer_one_frame", "1"), + DEFER_ZERO_FRAMES("sodium.options.defer_sorting.defer_zero_frames", "0"); private final Text name; + private final String shortName; - DeferSortMode(String name) { + DeferSortMode(String name, String shortName) { this.name = Text.translatable(name); + this.shortName = shortName; } @Override public Text getLocalizedName() { return this.name; } + + public String getShortName() { + return this.shortName; + } } public enum SortBehavior implements TextProvider { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java index bdc8feccb6..5eda69dc68 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java @@ -188,13 +188,14 @@ public void addDebugStrings(List list) { if (sortBehavior == SortBehavior.OFF) { list.add("TS OFF"); } else { - list.add("TS (%s) NL=%02d TrN=%02d TrS=G%03d/D%03d".formatted( + list.add("TS (%s,%s) NL=%02d TrN=%02d TrS=G%03d/D%03d".formatted( sortBehavior.getShortName(), + SodiumClientMod.options().performance.deferSortMode.getShortName(), this.gfni.getUniqueNormalCount(), this.triggeredNormalCount, this.gfniTriggerCount, this.directTriggerCount)); - list.add("N=%05d SNR=%05d STA=%04d DYN=%04d (DIR=%04d)".formatted( + list.add("N=%05d SNR=%05d STA=%05d DYN=%05d (DIR=%02d)".formatted( this.sortTypeCounters[SortType.NONE.ordinal()], this.sortTypeCounters[SortType.STATIC_NORMAL_RELATIVE.ordinal()], this.sortTypeCounters[SortType.STATIC_TOPO.ordinal()], From 9376d9c9ea7c66125f637a5960d1bfdce8de3eec Mon Sep 17 00:00:00 2001 From: douira Date: Tue, 26 Dec 2023 19:26:47 +0100 Subject: [PATCH 218/256] clearly label as absolute camera pos in meshing task --- .../render/chunk/compile/tasks/ChunkBuilderMeshingTask.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java index 78202b5552..88ada98e8e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java @@ -46,8 +46,8 @@ public class ChunkBuilderMeshingTask extends ChunkBuilderTask { private final ChunkRenderContext renderContext; - public ChunkBuilderMeshingTask(RenderSection render, int buildTime, Vector3dc cameraPos, ChunkRenderContext renderContext) { - super(render, buildTime, cameraPos); + public ChunkBuilderMeshingTask(RenderSection render, int buildTime, Vector3dc absoluteCameraPos, ChunkRenderContext renderContext) { + super(render, buildTime, absoluteCameraPos); this.renderContext = renderContext; } From 9dc0eacd544625c8e4afdd12ed8a80bc6b6cd03f Mon Sep 17 00:00:00 2001 From: douira Date: Wed, 27 Dec 2023 00:25:06 +0100 Subject: [PATCH 219/256] catch up rebuilt sections on movement that happened during their build task and would've triggered them had the build task been instant --- .../client/render/chunk/RenderSection.java | 4 +- .../render/chunk/RenderSectionManager.java | 2 +- .../tasks/ChunkBuilderMeshingTask.java | 2 +- .../chunk/compile/tasks/ChunkBuilderTask.java | 15 ++- .../TranslucentGeometryCollector.java | 6 +- .../data/BSPDynamicData.java | 12 ++- .../data/CombinedCameraPos.java | 10 ++ .../translucent_sorting/data/DynamicData.java | 10 +- .../data/TopoSortDynamicData.java | 26 ++--- .../trigger/CameraMovement.java | 5 +- .../trigger/DirectTriggers.java | 99 +++++++++++-------- .../trigger/GFNITriggers.java | 10 +- .../translucent_sorting/trigger/Group.java | 10 +- .../trigger/NormalList.java | 13 ++- .../trigger/SortTriggering.java | 61 ++++++++++-- 15 files changed, 201 insertions(+), 84 deletions(-) create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/CombinedCameraPos.java diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java index d25647c39b..ae5eb64070 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java @@ -347,7 +347,9 @@ public void setPendingUpdate(@Nullable ChunkUpdateType type) { } public void prepareTrigger(boolean isDirectTrigger) { - this.translucentData.prepareTrigger(isDirectTrigger); + if (this.translucentData != null) { + this.translucentData.prepareTrigger(isDirectTrigger); + } } public int getLastUploadFrame() { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index 8fbead31a9..9faf851009 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -318,7 +318,7 @@ private void processChunkBuildResults(ArrayList results) { if (result instanceof ChunkBuildOutput chunkBuildOutput) { this.updateSectionInfo(result.render, chunkBuildOutput.info); if (chunkBuildOutput.translucentData != null) { - this.ts.integrateTranslucentData(oldData, chunkBuildOutput.translucentData, this.cameraPosition); + this.ts.integrateTranslucentData(oldData, chunkBuildOutput.translucentData, this.cameraPosition, this::scheduleSort); // a rebuild always generates new translucent data which means applyTriggerChanges isn't necessary result.render.setTranslucentData(chunkBuildOutput.translucentData); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java index 88ada98e8e..fe6d18495b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java @@ -169,7 +169,7 @@ public ChunkBuildOutput execute(ChunkBuildContext buildContext, CancellationToke TranslucentData translucentData = null; if (collector != null) { translucentData = collector.getTranslucentData( - render.getTranslucentData(), meshes.get(DefaultTerrainRenderPasses.TRANSLUCENT), cameraPos); + render.getTranslucentData(), meshes.get(DefaultTerrainRenderPasses.TRANSLUCENT), this); } renderData.setOcclusionData(occluder.build()); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderTask.java index 78f0bfc7af..11e8996569 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderTask.java @@ -7,6 +7,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; import me.jellysquid.mods.sodium.client.render.chunk.compile.BuilderTaskOutput; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildContext; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.CombinedCameraPos; import me.jellysquid.mods.sodium.client.util.task.CancellationToken; /** @@ -19,9 +20,10 @@ * After the task completes, it returns a "build result" which contains any computed data that needs to be handled * on the main thread. */ -public abstract class ChunkBuilderTask { +public abstract class ChunkBuilderTask implements CombinedCameraPos { protected final RenderSection render; protected final int submitTime; + protected final Vector3dc absoluteCameraPos; protected final Vector3fc cameraPos; /** @@ -34,6 +36,7 @@ public abstract class ChunkBuilderTask { public ChunkBuilderTask(RenderSection render, int time, Vector3dc absoluteCameraPos) { this.render = render; this.submitTime = time; + this.absoluteCameraPos = absoluteCameraPos; this.cameraPos = new Vector3f( (float) (absoluteCameraPos.x() - (double) render.getOriginX()), (float) (absoluteCameraPos.y() - (double) render.getOriginY()), @@ -50,4 +53,14 @@ public ChunkBuilderTask(RenderSection render, int time, Vector3dc absoluteCamera * if the task was cancelled. */ public abstract OUTPUT execute(ChunkBuildContext context, CancellationToken cancellationToken); + + @Override + public Vector3fc getRelativeCameraPos() { + return this.cameraPos; + } + + @Override + public Vector3dc getAbsoluteCameraPos() { + return this.absoluteCameraPos; + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java index b775f4fe56..da341f2aa0 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java @@ -4,6 +4,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.joml.Vector3dc; import org.joml.Vector3f; import org.joml.Vector3fc; @@ -17,6 +18,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree.BSPBuildFailureException; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.AnyOrderData; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.BSPDynamicData; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.CombinedCameraPos; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.NoData; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.PresentTranslucentData; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.StaticNormalRelativeData; @@ -451,7 +453,7 @@ public SortType finishRendering() { return this.sortType; } - private TranslucentData makeNewTranslucentData(BuiltSectionMeshParts translucentMesh, Vector3fc cameraPos, + private TranslucentData makeNewTranslucentData(BuiltSectionMeshParts translucentMesh, CombinedCameraPos cameraPos, TranslucentData oldData) { if (this.sortType == SortType.NONE) { return AnyOrderData.fromMesh(translucentMesh, this.quads, this.sectionPos, null); @@ -513,7 +515,7 @@ private int getQuadHash(TQuad[] quads) { } public TranslucentData getTranslucentData( - TranslucentData oldData, BuiltSectionMeshParts translucentMesh, Vector3fc cameraPos) { + TranslucentData oldData, BuiltSectionMeshParts translucentMesh, CombinedCameraPos cameraPos) { // means there is no translucent geometry if (translucentMesh == null) { return new NoData(sectionPos); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java index 18db437bce..c2ca871315 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java @@ -1,5 +1,6 @@ package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data; +import org.joml.Vector3dc; import org.joml.Vector3fc; import me.jellysquid.mods.sodium.client.gl.util.VertexRange; @@ -23,8 +24,8 @@ public class BSPDynamicData extends DynamicData { private final int generation; private BSPDynamicData(ChunkSectionPos sectionPos, - NativeBuffer buffer, VertexRange range, BSPResult result, int generation) { - super(sectionPos, buffer, range, result); + NativeBuffer buffer, VertexRange range, BSPResult result, Vector3dc cameraPos, int generation) { + super(sectionPos, buffer, range, result, cameraPos); this.rootNode = result.getRootNode(); this.generation = generation; } @@ -41,7 +42,7 @@ private void sort(Vector3fc cameraPos) { } public static BSPDynamicData fromMesh(BuiltSectionMeshParts translucentMesh, - Vector3fc cameraPos, TQuad[] quads, ChunkSectionPos sectionPos, + CombinedCameraPos cameraPos, TQuad[] quads, ChunkSectionPos sectionPos, NativeBuffer buffer, TranslucentData oldData) { BSPNode oldRoot = null; int generation = 0; @@ -59,8 +60,9 @@ public static BSPDynamicData fromMesh(BuiltSectionMeshParts translucentMesh, VertexRange range = TranslucentData.getUnassignedVertexRange(translucentMesh); buffer = PresentTranslucentData.nativeBufferForQuads(buffer, quads); - var dynamicData = new BSPDynamicData(sectionPos, buffer, range, result, generation); - dynamicData.sort(cameraPos); + var dynamicData = new BSPDynamicData(sectionPos, buffer, range, result, + cameraPos.getAbsoluteCameraPos(), generation); + dynamicData.sort(cameraPos.getRelativeCameraPos()); // prepare geometry planes for integration into GFNI triggering result.prepareIntegration(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/CombinedCameraPos.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/CombinedCameraPos.java new file mode 100644 index 0000000000..684f57726a --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/CombinedCameraPos.java @@ -0,0 +1,10 @@ +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data; + +import org.joml.Vector3dc; +import org.joml.Vector3fc; + +public interface CombinedCameraPos { + Vector3fc getRelativeCameraPos(); + + Vector3dc getAbsoluteCameraPos(); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicData.java index 1e8c1c9a94..d84ee0f75c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicData.java @@ -1,5 +1,7 @@ package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data; +import org.joml.Vector3dc; + import me.jellysquid.mods.sodium.client.gl.util.VertexRange; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortType; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger.GeometryPlanes; @@ -8,10 +10,12 @@ public abstract class DynamicData extends MixedDirectionData { private GeometryPlanes geometryPlanes; + private final Vector3dc initialCameraPos; - DynamicData(ChunkSectionPos sectionPos, NativeBuffer buffer, VertexRange range, GeometryPlanes geometryPlanes) { + DynamicData(ChunkSectionPos sectionPos, NativeBuffer buffer, VertexRange range, GeometryPlanes geometryPlanes, Vector3dc initialCameraPos) { super(sectionPos, buffer, range); this.geometryPlanes = geometryPlanes; + this.initialCameraPos = initialCameraPos; } @Override @@ -26,4 +30,8 @@ public GeometryPlanes getGeometryPlanes() { public void clearGeometryPlanes() { this.geometryPlanes = null; } + + public Vector3dc getInitialCameraPos() { + return this.initialCameraPos; + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java index 98e604fa7a..49238c927c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java @@ -3,6 +3,7 @@ import java.nio.IntBuffer; import java.util.Arrays; +import org.joml.Vector3dc; import org.joml.Vector3fc; import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; @@ -37,7 +38,7 @@ public class TopoSortDynamicData extends DynamicData { private boolean turnDirectTriggerOff = false; private double directTriggerKey = -1; private int consecutiveTopoSortFailures = 0; - private boolean pendingTriggerIsAngle; + private boolean pendingTriggerIsDirect; private Object2ReferenceOpenHashMap distancesByNormal; private static final int MAX_TOPO_SORT_QUADS = 1000; @@ -49,9 +50,9 @@ public class TopoSortDynamicData extends DynamicData { private TopoSortDynamicData(ChunkSectionPos sectionPos, NativeBuffer buffer, VertexRange range, TQuad[] quads, - GeometryPlanes geometryPlanes, + GeometryPlanes geometryPlanes, Vector3dc cameraPos, Object2ReferenceOpenHashMap distancesByNormal) { - super(sectionPos, buffer, range, geometryPlanes); + super(sectionPos, buffer, range, geometryPlanes, cameraPos); this.quads = quads; this.distancesByNormal = distancesByNormal; } @@ -118,20 +119,20 @@ public void setDirectTriggerKey(double key) { } @Override - public void prepareTrigger(boolean isAngleTrigger) { - this.pendingTriggerIsAngle = isAngleTrigger; + public void prepareTrigger(boolean isDirectTrigger) { + this.pendingTriggerIsDirect = isDirectTrigger; } @Override public void sortOnTrigger(Vector3fc cameraPos) { - this.sort(cameraPos, this.pendingTriggerIsAngle, false); + this.sort(cameraPos, this.pendingTriggerIsDirect, false); } private static int getAttemptsForTime(long ns) { return ns <= MAX_TOPO_SORT_PATIENT_TIME_NS ? PATIENT_TOPO_ATTEMPTS : REGULAR_TOPO_ATTEMPTS; } - private void sort(Vector3fc cameraPos, boolean isAngleTrigger, boolean initial) { + private void sort(Vector3fc cameraPos, boolean isDirectTrigger, boolean initial) { // mark as not being reused to ensure the updated buffer is actually uploaded this.unsetReuseUploadedData(); @@ -143,7 +144,7 @@ private void sort(Vector3fc cameraPos, boolean isAngleTrigger, boolean initial) this.turnDirectTriggerOn(); } - if (this.GFNITrigger && !isAngleTrigger) { + if (this.GFNITrigger && !isDirectTrigger) { var sortStart = initial ? 0 : System.nanoTime(); var result = TopoGraphSorting.topoSortDepthFirstCyclic( @@ -160,7 +161,6 @@ private void sort(Vector3fc cameraPos, boolean isAngleTrigger, boolean initial) : MAX_TOPO_SORT_TIME_NS)) { this.turnGFNITriggerOff(); this.turnDirectTriggerOn(); - System.out.println("topo sort took too long"); } else if (result) { // disable distance sorting because topo sort seems to be possible. this.turnDirectTriggerOff(); @@ -202,7 +202,8 @@ private static void distanceSortDirect(IntBuffer indexBuffer, TQuad[] quads, Vec } public static TopoSortDynamicData fromMesh(BuiltSectionMeshParts translucentMesh, - Vector3fc cameraPos, TQuad[] quads, ChunkSectionPos sectionPos, GeometryPlanes geometryPlanes, + CombinedCameraPos cameraPos, TQuad[] quads, ChunkSectionPos sectionPos, + GeometryPlanes geometryPlanes, NativeBuffer buffer) { var distancesByNormal = geometryPlanes.prepareAndGetDistances(); @@ -211,9 +212,10 @@ public static TopoSortDynamicData fromMesh(BuiltSectionMeshParts translucentMesh buffer = PresentTranslucentData.nativeBufferForQuads(quads); } - var dynamicData = new TopoSortDynamicData(sectionPos, buffer, range, quads, geometryPlanes, distancesByNormal); + var dynamicData = new TopoSortDynamicData(sectionPos, buffer, range, quads, geometryPlanes, + cameraPos.getAbsoluteCameraPos(), distancesByNormal); - dynamicData.sort(cameraPos, false, true); + dynamicData.sort(cameraPos.getRelativeCameraPos(), false, true); return dynamicData; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/CameraMovement.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/CameraMovement.java index 8a07580b31..6d4dfb2d01 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/CameraMovement.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/CameraMovement.java @@ -2,5 +2,8 @@ import org.joml.Vector3dc; -public record CameraMovement(Vector3dc lastCamera, Vector3dc currentCamera) { +public record CameraMovement(Vector3dc start, Vector3dc end) { + public boolean hasChanged() { + return !this.start.equals(this.end); + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/DirectTriggers.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/DirectTriggers.java index 51f45e0aa0..876b3e97a5 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/DirectTriggers.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/DirectTriggers.java @@ -95,6 +95,17 @@ Vector3dc getSectionCenter() { return this.sectionCenter; } + double centerRelativeAngleCos(Vector3dc a, Vector3dc b) { + Vector3dc sectionCenter = this.getSectionCenter(); + return angleCos( + sectionCenter.x() - a.x(), + sectionCenter.y() - a.y(), + sectionCenter.z() - a.z(), + sectionCenter.x() - b.x(), + sectionCenter.y() - b.y(), + sectionCenter.z() - b.z()); + } + /** * Returns the distance between the sort camera pos and the center of the * section. @@ -140,8 +151,8 @@ private void insertTrigger(double key, DirectTriggerData data) { @Override public void processTriggers(SortTriggering ts, CameraMovement movement) { - Vector3dc lastCamera = movement.lastCamera(); - Vector3dc camera = movement.currentCamera(); + Vector3dc lastCamera = movement.start(); + Vector3dc camera = movement.end(); this.accumulatedDistance += lastCamera.distance(camera); // iterate all elements with a key of at most accumulatedDistance @@ -153,45 +164,40 @@ public void processTriggers(SortTriggering ts, CameraMovement movement) { // get the next element before it's modified by the data being re-inserted into // the tree var next = data.next; + this.processSingleTrigger(data, ts, camera); + data = next; + } + } + } - if (data.isAngleTriggering(camera)) { - double remainingAngle = TRIGGER_ANGLE; - - // check if the angle since the last sort exceeds the threshold - Vector3dc sectionCenter = data.getSectionCenter(); - double angleCos = angleCos( - sectionCenter.x() - data.triggerCameraPos.x(), - sectionCenter.y() - data.triggerCameraPos.y(), - sectionCenter.z() - data.triggerCameraPos.z(), - sectionCenter.x() - camera.x(), - sectionCenter.y() - camera.y(), - sectionCenter.z() - camera.z()); - - // compare angles inverted because cosine flips it - if (angleCos <= EARLY_TRIGGER_ANGLE_COS) { - ts.triggerSectionDirect(data.sectionPos); - data.triggerCameraPos = camera; - } else { - remainingAngle -= Math.acos(angleCos); - } - - this.insertDirectAngleTrigger(data, camera, remainingAngle); - } else { - double remainingDistance = DIRECT_TRIGGER_DISTANCE; - double lastTriggerCurrentCameraDistSquared = data.triggerCameraPos.distanceSquared(camera); - - if (lastTriggerCurrentCameraDistSquared >= EARLY_DIRECT_TRIGGER_DISTANCE_SQUARED) { - ts.triggerSectionDirect(data.sectionPos); - data.triggerCameraPos = camera; - } else { - remainingDistance -= Math.sqrt(lastTriggerCurrentCameraDistSquared); - } - - this.insertDirectDistanceTrigger(data, camera, remainingDistance); - } + private void processSingleTrigger(DirectTriggerData data, SortTriggering ts, Vector3dc camera) { + if (data.isAngleTriggering(camera)) { + double remainingAngle = TRIGGER_ANGLE; - data = next; + // check if the angle since the last sort exceeds the threshold + double angleCos = data.centerRelativeAngleCos(data.triggerCameraPos, camera); + + // compare angles inverted because cosine flips it + if (angleCos <= EARLY_TRIGGER_ANGLE_COS) { + ts.triggerSectionDirect(data.sectionPos); + data.triggerCameraPos = camera; + } else { + remainingAngle -= Math.acos(angleCos); + } + + this.insertDirectAngleTrigger(data, camera, remainingAngle); + } else { + double remainingDistance = DIRECT_TRIGGER_DISTANCE; + double lastTriggerCurrentCameraDistSquared = data.triggerCameraPos.distanceSquared(camera); + + if (lastTriggerCurrentCameraDistSquared >= EARLY_DIRECT_TRIGGER_DISTANCE_SQUARED) { + ts.triggerSectionDirect(data.sectionPos); + data.triggerCameraPos = camera; + } else { + remainingDistance -= Math.sqrt(lastTriggerCurrentCameraDistSquared); } + + this.insertDirectDistanceTrigger(data, camera, remainingDistance); } } @@ -207,12 +213,21 @@ public void removeSection(long sectionPos, TranslucentData data) { } @Override - public void addSection(ChunkSectionPos sectionPos, TopoSortDynamicData data, Vector3dc cameraPos) { + public void integrateSection(SortTriggering ts, ChunkSectionPos sectionPos, TopoSortDynamicData data, + CameraMovement movement) { + // create data with last camera position + var cameraPos = movement.start(); var newData = new DirectTriggerData(data, sectionPos, cameraPos); - if (newData.isAngleTriggering(cameraPos)) { - this.insertDirectAngleTrigger(newData, cameraPos, TRIGGER_ANGLE); + + if (movement.hasChanged()) { + // process it with the current camera position, this also initially inserts it + this.processSingleTrigger(newData, ts, movement.end()); } else { - this.insertDirectDistanceTrigger(newData, cameraPos, DIRECT_TRIGGER_DISTANCE); + if (newData.isAngleTriggering(cameraPos)) { + this.insertDirectAngleTrigger(newData, cameraPos, TRIGGER_ANGLE); + } else { + this.insertDirectDistanceTrigger(newData, cameraPos, DIRECT_TRIGGER_DISTANCE); + } } } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GFNITriggers.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GFNITriggers.java index b715c58443..75947d0f74 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GFNITriggers.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GFNITriggers.java @@ -1,6 +1,5 @@ package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger; -import org.joml.Vector3dc; import org.joml.Vector3fc; import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; @@ -68,7 +67,7 @@ public void removeSection(long sectionPos, TranslucentData data) { } @Override - public void addSection(ChunkSectionPos pos, DynamicData data, Vector3dc cameraPos) { + public void integrateSection(SortTriggering ts, ChunkSectionPos pos, DynamicData data, CameraMovement movement) { long sectionPos = pos.asLong(); var geometryPlanes = data.getGeometryPlanes(); @@ -114,5 +113,12 @@ public void addSection(ChunkSectionPos pos, DynamicData data, Vector3dc cameraPo } data.clearGeometryPlanes(); + + // check if catchup trigger is necessary + if (movement.hasChanged()) { + for (var normalList : this.normalLists.values()) { + normalList.processCatchup(ts, movement, sectionPos); + } + } } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/Group.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/Group.java index 5d89684eb5..21ece6e010 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/Group.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/Group.java @@ -51,13 +51,17 @@ void replaceWith(NormalPlanes normalPlanes) { this.normal = normalPlanes.normal; } + private boolean planeTriggered(double start, double end) { + return start < this.distances.getEnd() && end > this.distances.getStart() + && AlignableNormal.queryRange(this.facePlaneDistances, + (float) (start - this.baseDistance), (float) (end - this.baseDistance)); + } + void triggerRange(SortTriggering ts, double start, double end) { // trigger self on the section if the query range overlaps with the group // testing for strict inequality because if the two intervals just touch at the // start/end, there can be no overlap - if (start < this.distances.getEnd() && end > this.distances.getStart() - && AlignableNormal.queryRange(this.facePlaneDistances, - (float) (start - this.baseDistance), (float) (end - this.baseDistance))) { + if (this.planeTriggered(start, end)) { ts.triggerSectionGFNI(this.sectionPos, this.normal); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalList.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalList.java index 328e7c0925..c781045dce 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalList.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalList.java @@ -77,8 +77,8 @@ private double normalDotDouble(Vector3dc v) { void processMovement(SortTriggering ts, CameraMovement movement) { // calculate the distance range of the movement with respect to the normal - double start = this.normalDotDouble(movement.lastCamera()); - double end = this.normalDotDouble(movement.currentCamera()); + double start = this.normalDotDouble(movement.start()); + double end = this.normalDotDouble(movement.end()); // stop if the movement is reverse with regards to the normal // since this means it's moving against the normal @@ -96,6 +96,15 @@ void processMovement(SortTriggering ts, CameraMovement movement) { } } + void processCatchup(SortTriggering ts, CameraMovement movement, long sectionPos) { + double start = this.normalDotDouble(movement.start()); + double end = this.normalDotDouble(movement.end()); + if (start >= end) { + return; + } + groupsBySection.get(sectionPos).triggerRange(ts, start, end); + } + private void removeGroupInterval(Group group) { var groups = this.groupsByInterval.get(group.distances); if (groups != null) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java index 5eda69dc68..6c817ce89f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java @@ -31,6 +31,15 @@ public class SortTriggering { */ private BiConsumer triggerSectionCallback; + /** + * The dynamic data being caught up. When a section is rebuilt (initially or + * later) it might not have the required trigger data registered yet so that it + * might miss being triggered between being scheduled for rebuild and being + * integrated. This is solved by catching up the section being integrated with + * the movement that has happened in the mean time. + */ + private DynamicData catchupData = null; + /** * The number of triggered sections and normals. The normals are kept in a * hashmap to count them, triggered sections are not deduplicated. @@ -53,7 +62,7 @@ interface SectionTriggers { void removeSection(long sectionPos, TranslucentData data); - void addSection(ChunkSectionPos sectionPos, T data, Vector3dc cameraPos); + void integrateSection(SortTriggering ts, ChunkSectionPos sectionPos, T data, CameraMovement movement); } /** @@ -88,23 +97,52 @@ public void triggerSections(BiConsumer triggerSectionCallback, Ca triggerSectionCallback = null; } + private boolean isCatchingUp() { + return this.catchupData != null; + } + void triggerSectionGFNI(long sectionPos, AlignableNormal normal) { + if (this.isCatchingUp()) { + this.triggerSectionCatchup(sectionPos, false); + return; + } + this.triggeredNormals.add(normal); this.triggerSectionCallback.accept(sectionPos, false); this.gfniTriggerCount++; } void triggerSectionDirect(ChunkSectionPos sectionPos) { + if (this.isCatchingUp()) { + this.triggerSectionCatchup(sectionPos.asLong(), true); + return; + } + this.triggerSectionCallback.accept(sectionPos.asLong(), true); this.directTriggerCount++; } + private void triggerSectionCatchup(long sectionPos, boolean isDirectTrigger) { + // catchup triggering might be disabled + if (this.triggerSectionCallback != null) { + // do prepare triggere here since it can't be done through the render section as + // it hasn't been put there yet or it contains an old data object + this.catchupData.prepareTrigger(isDirectTrigger); + + // schedule the section to be re-sorted + this.triggerSectionCallback.accept(sectionPos, isDirectTrigger); + } + } + public void applyTriggerChanges(TopoSortDynamicData data, ChunkSectionPos pos, Vector3dc cameraPos) { if (data.getAndFlushTurnGFNITriggerOff()) { this.gfni.removeSection(pos.asLong(), data); } if (data.getAndFlushTurnDirectTriggerOn()) { - this.direct.addSection(pos, data, cameraPos); + // use dummy camera movement since there's no risk of the camera moving between + // the section being scheduled and integrated (there's no building going on + // here) + this.direct.integrateSection(this, pos, data, new CameraMovement(cameraPos, cameraPos)); } if (data.getAndFlushTurnDirectTriggerOff()) { this.direct.removeSection(pos.asLong(), data); @@ -141,12 +179,9 @@ public void removeSection(TranslucentData oldData, long sectionPos) { * Integrates the data from a geometry collector into GFNI. The geometry * collector contains the translucent face planes of a single section. This * method may also remove the section if it has become irrelevant. - * - * @param builder the geometry collector to integrate - * @return the sort type that the geometry collector's relevance heuristic - * determined */ - public void integrateTranslucentData(TranslucentData oldData, TranslucentData newData, Vector3dc cameraPos) { + public void integrateTranslucentData(TranslucentData oldData, TranslucentData newData, Vector3dc cameraPos, + BiConsumer triggerSectionCallback) { if (oldData == newData) { return; } @@ -158,25 +193,31 @@ public void integrateTranslucentData(TranslucentData oldData, TranslucentData ne if (newData instanceof DynamicData dynamicData) { this.direct.removeSection(pos.asLong(), oldData); this.decrementSortTypeCounter(oldData); + this.triggerSectionCallback = triggerSectionCallback; + this.catchupData = dynamicData; + var movement = new CameraMovement(dynamicData.getInitialCameraPos(), cameraPos); if (dynamicData instanceof TopoSortDynamicData topoSortData) { if (topoSortData.GFNITriggerEnabled()) { - this.gfni.addSection(pos, topoSortData, cameraPos); + this.gfni.integrateSection(this, pos, topoSortData, movement); } else { // remove the trigger data since this section is never going to get gfni // triggering (there's no option to add sections to GFNI later currently) topoSortData.clearGeometryPlanes(); } if (topoSortData.directTriggerEnabled()) { - this.direct.addSection(pos, topoSortData, cameraPos); + this.direct.integrateSection(this, pos, topoSortData, movement); } // clear trigger changes on data change because the current state of trigger // types was just applied topoSortData.clearTriggerChanges(); } else { - this.gfni.addSection(pos, dynamicData, cameraPos); + this.gfni.integrateSection(this, pos, dynamicData, movement); } + + this.triggerSectionCallback = null; + this.catchupData = null; } else { this.removeSection(oldData, pos.asLong()); return; From ac0d98635aed18078a62fdc12b7422147eef7930 Mon Sep 17 00:00:00 2001 From: douira Date: Wed, 27 Dec 2023 00:41:41 +0100 Subject: [PATCH 220/256] cleanup comment --- .../client/render/chunk/translucent_sorting/trigger/Group.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/Group.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/Group.java index 21ece6e010..497e9ca555 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/Group.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/Group.java @@ -6,9 +6,6 @@ /** * A group represents a set of face planes of the same normal within a section. - * - * group keeps a tree of its face plane distances to determine if it needs to be - * triggered. */ class Group { /** From ef490ba60b37ecad639e8394989962dee9ac3d60 Mon Sep 17 00:00:00 2001 From: douira Date: Wed, 27 Dec 2023 00:46:12 +0100 Subject: [PATCH 221/256] avoid NPE when a section doesn't have all normals --- .../render/chunk/translucent_sorting/trigger/NormalList.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalList.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalList.java index c781045dce..8f12f2e8d2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalList.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalList.java @@ -102,7 +102,10 @@ void processCatchup(SortTriggering ts, CameraMovement movement, long sectionPos) if (start >= end) { return; } - groupsBySection.get(sectionPos).triggerRange(ts, start, end); + var group = this.groupsBySection.get(sectionPos); + if (group != null) { + group.triggerRange(ts, start, end); + } } private void removeGroupInterval(Group group) { From f7c84b0561dbceb570c2cd0ad1e776112a0371d3 Mon Sep 17 00:00:00 2001 From: douira Date: Wed, 27 Dec 2023 18:45:22 +0100 Subject: [PATCH 222/256] fix SNR sorting by handling negative zero dot products --- .../java/me/jellysquid/mods/sodium/client/util/MathUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/MathUtil.java b/src/main/java/me/jellysquid/mods/sodium/client/util/MathUtil.java index da14232293..70b77013e2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/MathUtil.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/MathUtil.java @@ -17,6 +17,6 @@ public static long toMib(long bytes) { * floating point values by their int bits (for example packed in a long). */ public static int floatToComparableInt(float f) { - return Float.floatToRawIntBits(f) ^ (f >= 0 ? 0x80000000 : 0xffffffff); + return Float.floatToRawIntBits(f) ^ (Float.compare(f, 0f) > 0 ? 0x80000000 : 0xffffffff); } } From d411598814e586f7aa772e994b2d0f7d2786e711 Mon Sep 17 00:00:00 2001 From: douira Date: Thu, 28 Dec 2023 03:23:41 +0100 Subject: [PATCH 223/256] comment on why float.compare is necessary --- .../java/me/jellysquid/mods/sodium/client/util/MathUtil.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/MathUtil.java b/src/main/java/me/jellysquid/mods/sodium/client/util/MathUtil.java index 70b77013e2..140bfe1cc4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/MathUtil.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/MathUtil.java @@ -17,6 +17,7 @@ public static long toMib(long bytes) { * floating point values by their int bits (for example packed in a long). */ public static int floatToComparableInt(float f) { + // uses Float.compare to avoid issues comparing -0.0f and 0.0f return Float.floatToRawIntBits(f) ^ (Float.compare(f, 0f) > 0 ? 0x80000000 : 0xffffffff); } } From f9121f385a74a4e8a4399d8192bf1ede42c1ebe6 Mon Sep 17 00:00:00 2001 From: douira Date: Thu, 28 Dec 2023 04:52:09 +0100 Subject: [PATCH 224/256] fix sections going missing in rare scenarios where the dynamic data of a section is replaced with non-dynamic data after it has already been scheduled for a sort task which wrongly produced a null task that removed the section's data --- .../render/chunk/RenderSectionManager.java | 45 ++++++++++++------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index 9faf851009..1469a75f18 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -456,28 +456,39 @@ private void submitSectionTasks(ChunkJobCollector collector, ChunkUpdateType typ ChunkBuilderTask task; if (type == ChunkUpdateType.SORT || type == ChunkUpdateType.IMPORTANT_SORT) { task = this.createSortTask(section, frame); + + if (task == null) { + // when a sort task is null it means the render section has no dynamic data and + // doesn't need to be sorted. Nothing needs to be done. + continue; + } } else { task = this.createRebuildTask(section, frame); + + if (task == null) { + // if the section is empty or doesn't exist submit this null-task to set the + // built flag on the render section. + // It's important to use a NoData instead of null translucency data here in + // order for it to clear the old data from the translucency sorting system. + // This doesn't apply to sorting tasks as that would result in the section being + // marked as empty just because it was scheduled to be sorted and its dynamic + // data has since been removed. In that case simply nothing is done as the + // rebuild that must have happened in the mean time includes new non-dynamic + // index data. + var result = ChunkJobResult.successfully(new ChunkBuildOutput( + section, frame, new NoData(section.getPosition()), + BuiltSectionInfo.EMPTY, Collections.emptyMap())); + this.buildResults.add(result); + + section.setTaskCancellationToken(null); + } } - if (task != null) { - var job = this.builder.scheduleTask(task, type.isImportant(), collector::onJobFinished); - collector.addSubmittedJob(job); + // the task is ensured to be non-null here + var job = this.builder.scheduleTask(task, type.isImportant(), collector::onJobFinished); + collector.addSubmittedJob(job); - section.setTaskCancellationToken(job); - } else { - // if the section is empty, doesn't exist or no sort task needs to be created - // for non-dynamic data, submit this null-task to set the built flag on the - // render section. - // It's important to use a NoData instead of null translucency data here in - // order for it to clear the old data from the translucency sorting system - var result = ChunkJobResult.successfully(new ChunkBuildOutput( - section, frame, new NoData(section.getPosition()), - BuiltSectionInfo.EMPTY, Collections.emptyMap())); - this.buildResults.add(result); - - section.setTaskCancellationToken(null); - } + section.setTaskCancellationToken(job); section.setLastSubmittedFrame(frame); section.setPendingUpdate(null); From dad006388044650f035c5fc9bda3ed59d09938c8 Mon Sep 17 00:00:00 2001 From: douira Date: Thu, 28 Dec 2023 04:53:02 +0100 Subject: [PATCH 225/256] fix wrong assumption about null jobs --- .../sodium/client/render/chunk/RenderSectionManager.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index 1469a75f18..2110d78bc9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -484,11 +484,12 @@ section, frame, new NoData(section.getPosition()), } } - // the task is ensured to be non-null here - var job = this.builder.scheduleTask(task, type.isImportant(), collector::onJobFinished); - collector.addSubmittedJob(job); + if (task != null) { + var job = this.builder.scheduleTask(task, type.isImportant(), collector::onJobFinished); + collector.addSubmittedJob(job); - section.setTaskCancellationToken(job); + section.setTaskCancellationToken(job); + } section.setLastSubmittedFrame(frame); section.setPendingUpdate(null); From 83ab7d229ada5d7e61d50d78d682f1ae7aad7c60 Mon Sep 17 00:00:00 2001 From: douira Date: Thu, 4 Jan 2024 00:17:46 +0100 Subject: [PATCH 226/256] fix display of chunk queues with sort task types --- .../sodium/client/render/chunk/RenderSectionManager.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index 2110d78bc9..99c1babb5b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -393,6 +393,7 @@ public void cleanupAndFlip() { public void updateChunks(boolean updateImmediately) { var thisFrameBlockingCollector = this.lastBlockingCollector; + this.lastBlockingCollector = null; if (thisFrameBlockingCollector == null) { thisFrameBlockingCollector = new ChunkJobCollector(Integer.MAX_VALUE, this.buildResults::add); } @@ -403,7 +404,6 @@ public void updateChunks(boolean updateImmediately) { this.submitSectionTasks(thisFrameBlockingCollector, thisFrameBlockingCollector, thisFrameBlockingCollector); thisFrameBlockingCollector.awaitCompletion(this.builder); - this.lastBlockingCollector = null; } else { var nextFrameBlockingCollector = new ChunkJobCollector(Integer.MAX_VALUE, this.buildResults::add); var deferredCollector = new ChunkJobCollector(this.builder.getSchedulingBudget(), this.buildResults::add); @@ -699,8 +699,8 @@ public Collection getDebugStrings() { list.add(String.format("Chunk Queues: U=%02d (P0=%03d | P1=%03d | P2=%03d)", this.buildResults.size(), - this.taskLists.get(ChunkUpdateType.IMPORTANT_REBUILD).size(), - this.taskLists.get(ChunkUpdateType.REBUILD).size(), + this.taskLists.get(ChunkUpdateType.IMPORTANT_REBUILD).size() + this.taskLists.get(ChunkUpdateType.IMPORTANT_SORT).size(), + this.taskLists.get(ChunkUpdateType.REBUILD).size() + this.taskLists.get(ChunkUpdateType.SORT).size(), this.taskLists.get(ChunkUpdateType.INITIAL_BUILD).size()) ); From 7899b93cca2dacc91f2800a898791eb965dcfc1a Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 5 Jan 2024 21:15:23 +0100 Subject: [PATCH 227/256] allow scheduling more sort tasks, broken on world load (too many NONE sections) --- .../client/render/chunk/ChunkUpdateType.java | 21 +++++++++++++------ .../render/chunk/RenderSectionManager.java | 6 +++--- .../chunk/compile/executor/ChunkBuilder.java | 21 ++++++++++++++++--- .../chunk/compile/executor/ChunkJob.java | 2 ++ .../compile/executor/ChunkJobCollector.java | 6 ++++-- .../chunk/compile/executor/ChunkJobQueue.java | 20 ++++++++++++++++-- .../chunk/compile/executor/ChunkJobTyped.java | 5 +++++ .../tasks/ChunkBuilderMeshingTask.java | 8 +++++++ .../tasks/ChunkBuilderSortingTask.java | 7 +++++++ .../chunk/compile/tasks/ChunkBuilderTask.java | 2 ++ .../trigger/SortTriggering.java | 4 +++- 11 files changed, 85 insertions(+), 17 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkUpdateType.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkUpdateType.java index 0c00fb0ecd..6942f322fa 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkUpdateType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkUpdateType.java @@ -1,16 +1,21 @@ package me.jellysquid.mods.sodium.client.render.chunk; +import me.jellysquid.mods.sodium.client.render.chunk.compile.tasks.ChunkBuilderMeshingTask; +import me.jellysquid.mods.sodium.client.render.chunk.compile.tasks.ChunkBuilderSortingTask; + public enum ChunkUpdateType { - SORT(Integer.MAX_VALUE), - INITIAL_BUILD(128), - REBUILD(Integer.MAX_VALUE), - IMPORTANT_REBUILD(Integer.MAX_VALUE), - IMPORTANT_SORT(Integer.MAX_VALUE); + SORT(Integer.MAX_VALUE, ChunkBuilderSortingTask.SORT_TASK_EFFORT), + INITIAL_BUILD(128, ChunkBuilderMeshingTask.MESH_TASK_EFFORT), + REBUILD(Integer.MAX_VALUE, ChunkBuilderMeshingTask.MESH_TASK_EFFORT), + IMPORTANT_REBUILD(Integer.MAX_VALUE, ChunkBuilderMeshingTask.MESH_TASK_EFFORT), + IMPORTANT_SORT(Integer.MAX_VALUE, ChunkBuilderSortingTask.SORT_TASK_EFFORT); private final int maximumQueueSize; + private final int taskEffort; - ChunkUpdateType(int maximumQueueSize) { + ChunkUpdateType(int maximumQueueSize, int taskEffort) { this.maximumQueueSize = maximumQueueSize; + this.taskEffort = taskEffort; } public static ChunkUpdateType getPromotionUpdateType(ChunkUpdateType prev, ChunkUpdateType next) { @@ -32,4 +37,8 @@ public int getMaximumQueueSize() { public boolean isImportant() { return this == IMPORTANT_REBUILD || this == IMPORTANT_SORT; } + + public int getTaskEffort() { + return this.taskEffort; + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index 99c1babb5b..6e641c83a2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -439,7 +439,7 @@ private void submitSectionTasks( private void submitSectionTasks(ChunkJobCollector collector, ChunkUpdateType type) { var queue = this.taskLists.get(type); - while (!queue.isEmpty() && collector.canOffer()) { + while (!queue.isEmpty() && collector.hasBudgetFor(type.getTaskEffort())) { RenderSection section = queue.remove(); if (section.isDisposed()) { @@ -693,8 +693,8 @@ public Collection getDebugStrings() { list.add(String.format("Geometry Pool: %d/%d MiB (%d buffers)", MathUtil.toMib(deviceUsed), MathUtil.toMib(deviceAllocated), count)); list.add(String.format("Transfer Queue: %s", this.regions.getStagingBuffer().toString())); - list.add(String.format("Chunk Builder: Permits=%02d | Busy=%02d | Total=%02d", - this.builder.getScheduledJobCount(), this.builder.getBusyThreadCount(), this.builder.getTotalThreadCount()) + list.add(String.format("Chunk Builder: Permits=%02d (E %02d) | Busy=%02d | Total=%02d", + this.builder.getScheduledJobCount(), this.builder.getScheduledEffort(), this.builder.getBusyThreadCount(), this.builder.getTotalThreadCount()) ); list.add(String.format("Chunk Queues: U=%02d (P0=%03d | P1=%03d | P2=%03d)", diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkBuilder.java index 178c5ea033..98b8ae4ddd 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkBuilder.java @@ -5,7 +5,6 @@ import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildContext; import me.jellysquid.mods.sodium.client.render.chunk.compile.tasks.ChunkBuilderTask; import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexType; -import me.jellysquid.mods.sodium.client.util.task.CancellationToken; import net.minecraft.client.world.ClientWorld; import net.minecraft.util.math.MathHelper; import org.apache.commons.lang3.Validate; @@ -14,11 +13,23 @@ import java.util.ArrayList; import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; public class ChunkBuilder { + /** + * The effort of a mesh task compared to a sorting task, which always has effort + * 1. This is used to schedule more sorting tasks compared to mesh tasks because + * they're faster. This also needs to capture that there's a limit to how much + * data can be uploaded per frame. Since sort tasks generate index data, which + * is smaller per quad and (on average) per section, more of their results can + * be uploaded in one frame. This number should essentially be a conservative + * estimate of min((mesh task upload size) / (sort task upload size), (mesh task + * time) / (sort task time)). + */ + public static final int MESH_TASK_EFFORT_FACTOR = 10; + public static final int EFFORT_PER_THREAD_PER_FRAME = MESH_TASK_EFFORT_FACTOR; + static final Logger LOGGER = LogManager.getLogger("ChunkBuilder"); private final ChunkJobQueue queue = new ChunkJobQueue(); @@ -53,7 +64,7 @@ public ChunkBuilder(ClientWorld world, ChunkVertexType vertexType) { * spawn more tasks than the budget allows, it will block until resources become available. */ public int getSchedulingBudget() { - return Math.max(0, this.threads.size() - this.queue.size()); + return Math.max(0, this.threads.size() * EFFORT_PER_THREAD_PER_FRAME - this.queue.getEffortSum()); } /** @@ -147,6 +158,10 @@ public int getScheduledJobCount() { return this.queue.size(); } + public int getScheduledEffort() { + return this.queue.getEffortSum(); + } + public int getBusyThreadCount() { return this.busyThreadCount.get(); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJob.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJob.java index e9a1f53ff9..be2852bd74 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJob.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJob.java @@ -7,4 +7,6 @@ public interface ChunkJob extends CancellationToken { void execute(ChunkBuildContext context); boolean isStarted(); + + int getEffort(); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJobCollector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJobCollector.java index ebeba8a5d0..8e79cc472e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJobCollector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJobCollector.java @@ -11,6 +11,7 @@ public class ChunkJobCollector { private final Semaphore semaphore = new Semaphore(0); private final Consumer> collector; private final List submitted = new ArrayList<>(); + private int submittedEffort = 0; private final int budget; @@ -42,9 +43,10 @@ public void awaitCompletion(ChunkBuilder builder) { public void addSubmittedJob(ChunkJob job) { this.submitted.add(job); + this.submittedEffort += job.getEffort(); } - public boolean canOffer() { - return (this.budget - this.submitted.size()) > 0; + public boolean hasBudgetFor(int effort) { + return (this.budget - this.submittedEffort) >= effort; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJobQueue.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJobQueue.java index 539228e439..b7c7dadb78 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJobQueue.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJobQueue.java @@ -8,10 +8,13 @@ import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.Semaphore; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; class ChunkJobQueue { private final ConcurrentLinkedDeque jobs = new ConcurrentLinkedDeque<>(); + private final AtomicInteger jobEffortSum = new AtomicInteger(); + private final Semaphore semaphore = new Semaphore(0); private final AtomicBoolean isRunning = new AtomicBoolean(true); @@ -28,6 +31,7 @@ public void add(ChunkJob job, boolean important) { } else { this.jobs.addLast(job); } + this.jobEffortSum.addAndGet(job.getEffort()); this.semaphore.release(1); } @@ -40,7 +44,11 @@ public ChunkJob waitForNextJob() throws InterruptedException { this.semaphore.acquire(); - return this.getNextTask(); + var job = this.getNextTask(); + if (job != null) { + this.jobEffortSum.addAndGet(-job.getEffort()); + } + return job; } public boolean stealJob(ChunkJob job) { @@ -50,7 +58,9 @@ public boolean stealJob(ChunkJob job) { var success = this.jobs.remove(job); - if (!success) { + if (success) { + this.jobEffortSum.addAndGet(-job.getEffort()); + } else { // If we didn't manage to actually steal the task, then we need to release the permit which we did steal this.semaphore.release(1); } @@ -80,6 +90,8 @@ public Collection shutdown() { // force the worker threads to wake up and exit this.semaphore.release(Runtime.getRuntime().availableProcessors()); + this.jobEffortSum.set(0); + return list; } @@ -87,6 +99,10 @@ public int size() { return this.semaphore.availablePermits(); } + public int getEffortSum() { + return this.jobEffortSum.get(); + } + public boolean isEmpty() { return this.size() == 0; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJobTyped.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJobTyped.java index 9bcb969f88..53b9a648bb 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJobTyped.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJobTyped.java @@ -66,4 +66,9 @@ public void execute(ChunkBuildContext context) { public boolean isStarted() { return this.started; } + + @Override + public int getEffort() { + return this.task.getEffort(); + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java index fe6d18495b..8404fc7057 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java @@ -7,6 +7,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildBuffers; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildContext; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildOutput; +import me.jellysquid.mods.sodium.client.render.chunk.compile.executor.ChunkBuilder; import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.BlockRenderCache; import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.BlockRenderContext; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionInfo; @@ -44,6 +45,8 @@ * array allocations, they are pooled to ensure that the garbage collector doesn't become overloaded. */ public class ChunkBuilderMeshingTask extends ChunkBuilderTask { + public static final int MESH_TASK_EFFORT = ChunkBuilderSortingTask.SORT_TASK_EFFORT * ChunkBuilder.MESH_TASK_EFFORT_FACTOR; + private final ChunkRenderContext renderContext; public ChunkBuilderMeshingTask(RenderSection render, int buildTime, Vector3dc absoluteCameraPos, ChunkRenderContext renderContext) { @@ -193,4 +196,9 @@ private CrashException fillCrashInfo(CrashReport report, WorldSlice slice, Block return new CrashException(report); } + + @Override + public int getEffort() { + return MESH_TASK_EFFORT; + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java index 3d4a420ae2..d1a1f802d9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java @@ -9,6 +9,8 @@ import me.jellysquid.mods.sodium.client.util.task.CancellationToken; public class ChunkBuilderSortingTask extends ChunkBuilderTask { + public static final int SORT_TASK_EFFORT = 1; + private final DynamicData dynamicData; public ChunkBuilderSortingTask(RenderSection render, int frame, Vector3dc absoluteCameraPos, @@ -32,4 +34,9 @@ public static ChunkBuilderSortingTask createTask(RenderSection render, int frame } return null; } + + @Override + public int getEffort() { + return SORT_TASK_EFFORT; + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderTask.java index 11e8996569..d01ce40f03 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderTask.java @@ -54,6 +54,8 @@ public ChunkBuilderTask(RenderSection render, int time, Vector3dc absoluteCamera */ public abstract OUTPUT execute(ChunkBuildContext context, CancellationToken cancellationToken); + public abstract int getEffort(); + @Override public Vector3fc getRelativeCameraPos() { return this.cameraPos; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java index 6c817ce89f..1da71aa9db 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java @@ -20,6 +20,9 @@ * of translucent data objects for each sort type and delegates triggering of * sections for dynamic sorting to the trigger components. * + * TODO: + * - investigate why there's a similar number of STA and DYN sections. This might be normal, the counters might be broken or the heuristic is actually wrong. + * * @author douira (the translucent_sorting package) */ public class SortTriggering { @@ -220,7 +223,6 @@ public void integrateTranslucentData(TranslucentData oldData, TranslucentData ne this.catchupData = null; } else { this.removeSection(oldData, pos.asLong()); - return; } } From 0af463dc55e84f97329892396bb667e746f9992d Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 8 Jan 2024 20:30:14 +0100 Subject: [PATCH 228/256] only mark as needing a graph update if the uploads could have changed the graph, since sort results never change the graph --- .../render/chunk/RenderSectionManager.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index 99c1babb5b..a7f7db5bc2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -296,27 +296,29 @@ public void uploadChunks() { return; } - this.processChunkBuildResults(results); + // only mark as needing a graph update if the uploads could have changed the graph + // (sort results never change the graph) + // generally there's no sort results without a camera movement, which would also trigger + // a graph update, but it can sometimes happen because of async task execution + this.needsGraphUpdate = this.needsGraphUpdate || this.processChunkBuildResults(results); for (var result : results) { result.deleteAfterUploadSafe(); } - - // TODO: only needed if the tasks actually changed the visibility (sort tasks - // don't count, though there would never be a sort task without camera movement - // so it likely doesn't matter) - this.needsGraphUpdate = true; } - private void processChunkBuildResults(ArrayList results) { + private boolean processChunkBuildResults(ArrayList results) { var filtered = filterChunkBuildResults(results); this.regions.uploadResults(RenderDevice.INSTANCE.createCommandList(), filtered); + boolean touchedSectionInfo = false; for (var result : filtered) { TranslucentData oldData = result.render.getTranslucentData(); if (result instanceof ChunkBuildOutput chunkBuildOutput) { this.updateSectionInfo(result.render, chunkBuildOutput.info); + touchedSectionInfo = true; + if (chunkBuildOutput.translucentData != null) { this.ts.integrateTranslucentData(oldData, chunkBuildOutput.translucentData, this.cameraPosition, this::scheduleSort); @@ -338,6 +340,8 @@ private void processChunkBuildResults(ArrayList results) { result.render.setLastUploadFrame(result.submitTime); } + + return touchedSectionInfo; } private void updateSectionInfo(RenderSection render, BuiltSectionInfo info) { From f10dfbadda66d9f4663c0ba47f3c44fa93cab89c Mon Sep 17 00:00:00 2001 From: douira Date: Sun, 14 Jan 2024 04:18:50 +0100 Subject: [PATCH 229/256] use radix sort for sorting large arrays, in distance sorting and SNR sorting --- .../data/StaticNormalRelativeData.java | 96 ++++++++++++++----- .../data/TopoSortDynamicData.java | 37 +++++-- .../mods/sodium/client/util/MathUtil.java | 13 ++- .../sodium/client/util/sorting/RadixSort.java | 82 ++++++++++++++++ 4 files changed, 194 insertions(+), 34 deletions(-) create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/util/sorting/RadixSort.java diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java index e5facbb41e..b38f802a96 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java @@ -9,11 +9,15 @@ import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; import me.jellysquid.mods.sodium.client.util.MathUtil; import me.jellysquid.mods.sodium.client.util.NativeBuffer; +import me.jellysquid.mods.sodium.client.util.sorting.RadixSort; import net.minecraft.util.math.ChunkSectionPos; /** * Static normal relative sorting orders quads by the dot product of their * normal and position. (referred to as "distance" throughout the code) + * + * Unlike sorting by distance, which is descending for translucent rendering to + * be correct, sorting by dot product is ascending instead. */ public class StaticNormalRelativeData extends SplitDirectionData { public StaticNormalRelativeData(ChunkSectionPos sectionPos, NativeBuffer buffer, VertexRange[] ranges) { @@ -28,19 +32,35 @@ public SortType getSortType() { private static StaticNormalRelativeData fromDoubleUnaligned(BuiltSectionMeshParts translucentMesh, TQuad[] quads, ChunkSectionPos sectionPos) { var buffer = PresentTranslucentData.nativeBufferForQuads(quads); - IntBuffer bufferBuilder = buffer.getDirectBuffer().asIntBuffer(); + IntBuffer indexBuffer = buffer.getDirectBuffer().asIntBuffer(); - long[] sortData = new long[quads.length]; + if (quads.length <= 1) { + TranslucentData.writeQuadVertexIndexes(indexBuffer, 0); + } else if (RadixSort.useRadixSort(quads.length)) { + final var keys = new int[quads.length]; - for (int quadIndex = 0; quadIndex < quads.length; quadIndex++) { - int dotProductComponent = MathUtil.floatToComparableInt(quads[quadIndex].getDotProduct()); - sortData[quadIndex] = (long) dotProductComponent << 32 | quadIndex; - } + for (int q = 0; q < quads.length; q++) { + keys[q] = MathUtil.floatToComparableInt(quads[q].getDotProduct()); + } + + var indices = RadixSort.sort(keys); + + for (int i = 0; i < quads.length; i++) { + TranslucentData.writeQuadVertexIndexes(indexBuffer, indices[i]); + } + } else { + final var sortData = new long[quads.length]; + + for (int q = 0; q < quads.length; q++) { + int dotProductComponent = MathUtil.floatToComparableInt(quads[q].getDotProduct()); + sortData[q] = (long) dotProductComponent << 32 | q; + } - Arrays.sort(sortData); + Arrays.sort(sortData); - for (int i = 0; i < quads.length; i++) { - TranslucentData.writeQuadVertexIndexes(bufferBuilder, (int) sortData[i]); + for (int i = 0; i < quads.length; i++) { + TranslucentData.writeQuadVertexIndexes(indexBuffer, (int) sortData[i]); + } } return new StaticNormalRelativeData(sectionPos, buffer, translucentMesh.getVertexRanges()); @@ -52,17 +72,23 @@ private static StaticNormalRelativeData fromDoubleUnaligned(BuiltSectionMeshPart private static StaticNormalRelativeData fromMixed(BuiltSectionMeshParts translucentMesh, TQuad[] quads, ChunkSectionPos sectionPos) { var buffer = PresentTranslucentData.nativeBufferForQuads(quads); - IntBuffer bufferBuilder = buffer.getDirectBuffer().asIntBuffer(); + IntBuffer indexBuffer = buffer.getDirectBuffer().asIntBuffer(); var ranges = translucentMesh.getVertexRanges(); var maxRangeSize = 0; + boolean anyNeedsSortData = false; for (var range : ranges) { if (range != null) { - maxRangeSize = Math.max(maxRangeSize, range.vertexCount()); + var count = range.vertexCount(); + maxRangeSize = Math.max(maxRangeSize, count); + anyNeedsSortData |= !RadixSort.useRadixSort(count) && count > 1; } } - long[] sortData = new long[TranslucentData.vertexCountToQuadCount(maxRangeSize)]; + long[] sortData = null; + if (anyNeedsSortData) { + sortData = new long[TranslucentData.vertexCountToQuadCount(maxRangeSize)]; + } int quadIndex = 0; for (var range : ranges) { @@ -70,20 +96,42 @@ private static StaticNormalRelativeData fromMixed(BuiltSectionMeshParts transluc continue; } - int count = TranslucentData.vertexCountToQuadCount(range.vertexCount()); - - for (int i = 0; i < count; i++) { - var quad = quads[quadIndex++]; - int dotProductComponent = MathUtil.floatToComparableInt(quad.getDotProduct()); - sortData[i] = (long) dotProductComponent << 32 | i; - } - - if (count > 1) { - Arrays.sort(sortData, 0, count); + int vertexCount = range.vertexCount(); + if (vertexCount == 0) { + continue; } - for (int i = 0; i < count; i++) { - TranslucentData.writeQuadVertexIndexes(bufferBuilder, (int) sortData[i]); + int count = TranslucentData.vertexCountToQuadCount(vertexCount); + + if (count == 1) { + TranslucentData.writeQuadVertexIndexes(indexBuffer, 0); + quadIndex++; + } else if (RadixSort.useRadixSort(count)) { + final var keys = new int[count]; + + for (int q = 0; q < count; q++) { + keys[q] = MathUtil.floatToComparableInt(quads[quadIndex++].getDotProduct()); + } + + var indices = RadixSort.sort(keys); + + for (int i = 0; i < count; i++) { + TranslucentData.writeQuadVertexIndexes(indexBuffer, indices[i]); + } + } else { + for (int i = 0; i < count; i++) { + var quad = quads[quadIndex++]; + int dotProductComponent = MathUtil.floatToComparableInt(quad.getDotProduct()); + sortData[i] = (long) dotProductComponent << 32 | i; + } + + if (count > 1) { + Arrays.sort(sortData, 0, count); + } + + for (int i = 0; i < count; i++) { + TranslucentData.writeQuadVertexIndexes(indexBuffer, (int) sortData[i]); + } } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java index 49238c927c..386eba5e74 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java @@ -12,6 +12,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger.GeometryPlanes; import me.jellysquid.mods.sodium.client.util.NativeBuffer; +import me.jellysquid.mods.sodium.client.util.sorting.RadixSort; import net.minecraft.util.math.ChunkSectionPos; /** @@ -187,17 +188,37 @@ private void sort(Vector3fc cameraPos, boolean isDirectTrigger, boolean initial) } } + /** + * Sorts the given quads by descending center distance to the camera and writes + * the resulting order to the given index buffer. + */ private static void distanceSortDirect(IntBuffer indexBuffer, TQuad[] quads, Vector3fc cameraPos) { - var data = new long[quads.length]; - for (int i = 0; i < quads.length; i++) { - float distance = cameraPos.distanceSquared(quads[i].getCenter()); - data[i] = (long) ~Float.floatToRawIntBits(distance) << 32 | i; - } + if (quads.length <= 1) { + TranslucentData.writeQuadVertexIndexes(indexBuffer, 0); + } else if (RadixSort.useRadixSort(quads.length)) { + final var keys = new int[quads.length]; + + for (int q = 0; q < quads.length; q++) { + keys[q] = ~Float.floatToRawIntBits(quads[q].getCenter().distanceSquared(cameraPos)); + } + + var indices = RadixSort.sort(keys); - Arrays.sort(data); + for (int i = 0; i < quads.length; i++) { + TranslucentData.writeQuadVertexIndexes(indexBuffer, indices[i]); + } + } else { + final var data = new long[quads.length]; + for (int q = 0; q < quads.length; q++) { + float distance = quads[q].getCenter().distanceSquared(cameraPos); + data[q] = (long) ~Float.floatToRawIntBits(distance) << 32 | q; + } - for (int i = 0; i < quads.length; i++) { - TranslucentData.writeQuadVertexIndexes(indexBuffer, (int) data[i]); + Arrays.sort(data); + + for (int i = 0; i < quads.length; i++) { + TranslucentData.writeQuadVertexIndexes(indexBuffer, (int) data[i]); + } } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/MathUtil.java b/src/main/java/me/jellysquid/mods/sodium/client/util/MathUtil.java index 140bfe1cc4..85a5390083 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/MathUtil.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/MathUtil.java @@ -12,12 +12,21 @@ public static long toMib(long bytes) { return bytes / (1024L * 1024L); // 1 MiB = 1048576 (2^20) bytes } + private static final int BIT_COUNT = 32; + private static final int FLIP_SIGN_MASK = 1 << (BIT_COUNT - 1); + /** * Converts a float to a comparable integer value. This is used to compare * floating point values by their int bits (for example packed in a long). + * + * The resulting integer can be treated as if it's unsigned and numbers the + * floats from the smallest negative to the largest positive value. */ public static int floatToComparableInt(float f) { - // uses Float.compare to avoid issues comparing -0.0f and 0.0f - return Float.floatToRawIntBits(f) ^ (Float.compare(f, 0f) > 0 ? 0x80000000 : 0xffffffff); + // // uses Float.compare to avoid issues comparing -0.0f and 0.0f + // return Float.floatToRawIntBits(f) ^ (Float.compare(f, 0f) > 0 ? 0x80000000 : 0xffffffff); + + var bits = Float.floatToRawIntBits(f); + return bits ^ ((bits >> (BIT_COUNT - 1)) | FLIP_SIGN_MASK); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/RadixSort.java b/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/RadixSort.java new file mode 100644 index 0000000000..9ce87308f6 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/RadixSort.java @@ -0,0 +1,82 @@ +package me.jellysquid.mods.sodium.client.util.sorting; + +public class RadixSort extends AbstractSort { + public static final int RADIX_SORT_THRESHOLD = 64; + + private static final int DIGIT_BITS = 8; + private static final int RADIX_KEY_BITS = Integer.BYTES * 8; + private static final int BUCKET_COUNT = 1 << DIGIT_BITS; + private static final int DIGIT_COUNT = (RADIX_KEY_BITS + DIGIT_BITS - 1) / DIGIT_BITS; + private static final int DIGIT_MASK = (1 << DIGIT_BITS) - 1; + + public static int[] sort(int[] keys) { + if (keys.length <= 1) { + return new int[keys.length]; + } + + return radixSort(keys, createHistogram(keys)); + } + + private static int[][] createHistogram(int[] keys) { + var histogram = new int[DIGIT_COUNT][BUCKET_COUNT]; + + for (final int key : keys) { + for (int digit = 0; digit < DIGIT_COUNT; digit++) { + histogram[digit][extractDigit(key, digit)] += 1; + } + } + + return histogram; + } + + private static void prefixSum(int[][] offsets) { + for (int digit = 0; digit < DIGIT_COUNT; digit++) { + final var buckets = offsets[digit]; + var sum = 0; + + for (int bucket_idx = 0; bucket_idx < BUCKET_COUNT; bucket_idx++) { + final var offset = sum; + sum += buckets[bucket_idx]; + buckets[bucket_idx] = offset; + } + } + } + + private static int[] radixSort(int[] keys, int[][] offsets) { + prefixSum(offsets); + + final var length = keys.length; + + int[] cur = createIndexBuffer(length); + int[] next = new int[length]; + + for (int digit = 0; digit < DIGIT_COUNT; digit++) { + final var buckets = offsets[digit]; + + for (int pos = 0; pos < length; pos++) { + final var index = cur[pos]; + final var bucket_idx = extractDigit(keys[index], digit); + + next[buckets[bucket_idx]] = index; + buckets[bucket_idx] += 1; + } + + { + // (cur, next) = (next, cur) + var temp = next; + next = cur; + cur = temp; + } + } + + return cur; + } + + private static int extractDigit(int key, int digit) { + return ((key >>> (digit * DIGIT_BITS)) & DIGIT_MASK); + } + + public static boolean useRadixSort(int length) { + return length >= RADIX_SORT_THRESHOLD; + } +} From fd42f5f3384ad7e991abd2a94ee437e61b26f6d0 Mon Sep 17 00:00:00 2001 From: douira Date: Sun, 14 Jan 2024 16:17:06 +0100 Subject: [PATCH 230/256] fix box test heuristic --- .../TranslucentGeometryCollector.java | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java index da341f2aa0..7be4d9da3a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java @@ -4,9 +4,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.joml.Vector3dc; import org.joml.Vector3f; -import org.joml.Vector3fc; import it.unimi.dsi.fastutil.objects.ReferenceArrayList; import me.jellysquid.mods.sodium.client.SodiumClientMod; @@ -19,6 +17,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.AnyOrderData; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.BSPDynamicData; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.CombinedCameraPos; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.DynamicData; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.NoData; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.PresentTranslucentData; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.StaticNormalRelativeData; @@ -26,6 +25,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TopoSortDynamicData; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger.GeometryPlanes; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger.SortTriggering; import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexEncoder; import me.jellysquid.mods.sodium.client.util.NativeBuffer; import net.caffeinemc.mods.sodium.api.util.NormI8; @@ -70,7 +70,10 @@ public class TranslucentGeometryCollector { private int alignedFacingBitmap = 0; // AABB of the geometry - private float[] extents = new float[ModelQuadFacing.DIRECTIONS]; + private float[] extents = new float[] { + Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY, + Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY + }; // true if one of the extents has more than one plane private boolean alignedExtentsMultiple = false; @@ -192,8 +195,6 @@ public void appendQuad(int packedNormal, ChunkVertexEncoder.Vertex[] vertices, M if (quadList == null) { quadList = new ReferenceArrayList<>(); this.quadLists[direction] = quadList; - } else if (facing.isAligned()) { - this.alignedExtentsMultiple = true; } if (facing.isAligned()) { @@ -213,7 +214,15 @@ public void appendQuad(int packedNormal, ChunkVertexEncoder.Vertex[] vertices, M var extreme = this.alignedExtremes[direction]; var distance = quad.getDotProduct(); - if (facing.getSign() > 1) { + + // check if this is a new dot product for this distance + var existingExtreme = this.alignedExtremes[direction]; + if (!this.alignedExtentsMultiple && !Float.isInfinite(existingExtreme) && existingExtreme != distance) { + this.alignedExtentsMultiple = true; + } + + // update the aligned extremes (which are the direction dependent dot products) + if (facing.getSign() > 0) { this.alignedExtremes[direction] = Math.max(extreme, distance); } else { this.alignedExtremes[direction] = Math.min(extreme, distance); From 497d1ff7d5c25dd5754f42b55a96a7af480d736a Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 15 Jan 2024 01:22:42 +0100 Subject: [PATCH 231/256] fix wrong handling of array lengths in SNR --- .../data/StaticNormalRelativeData.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java index b38f802a96..10b292bbbe 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java @@ -75,19 +75,19 @@ private static StaticNormalRelativeData fromMixed(BuiltSectionMeshParts transluc IntBuffer indexBuffer = buffer.getDirectBuffer().asIntBuffer(); var ranges = translucentMesh.getVertexRanges(); - var maxRangeSize = 0; + var maxQuadCount = 0; boolean anyNeedsSortData = false; for (var range : ranges) { if (range != null) { - var count = range.vertexCount(); - maxRangeSize = Math.max(maxRangeSize, count); - anyNeedsSortData |= !RadixSort.useRadixSort(count) && count > 1; + var quadCount = TranslucentData.vertexCountToQuadCount(range.vertexCount()); + maxQuadCount = Math.max(maxQuadCount, quadCount); + anyNeedsSortData |= !RadixSort.useRadixSort(quadCount) && quadCount > 1; } } long[] sortData = null; if (anyNeedsSortData) { - sortData = new long[TranslucentData.vertexCountToQuadCount(maxRangeSize)]; + sortData = new long[maxQuadCount]; } int quadIndex = 0; From 864ff124c133c340aca924111758a9f78cb5b059 Mon Sep 17 00:00:00 2001 From: douira Date: Wed, 24 Jan 2024 19:50:28 +0100 Subject: [PATCH 232/256] expand sort type to differentiate between the three different NONE situations --- .../render/chunk/RenderSectionManager.java | 2 +- .../chunk/compile/ChunkBuildOutput.java | 2 +- .../chunk/translucent_sorting/SortType.java | 23 ++++++++++++------- .../TranslucentGeometryCollector.java | 2 +- .../translucent_sorting/data/DynamicData.java | 5 ++++ .../translucent_sorting/data/NoData.java | 15 ++++++++++-- .../data/TranslucentData.java | 4 ++++ 7 files changed, 40 insertions(+), 13 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index a7f7db5bc2..83f349d50d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -480,7 +480,7 @@ private void submitSectionTasks(ChunkJobCollector collector, ChunkUpdateType typ // rebuild that must have happened in the mean time includes new non-dynamic // index data. var result = ChunkJobResult.successfully(new ChunkBuildOutput( - section, frame, new NoData(section.getPosition()), + section, frame, NoData.forEmptySection(section.getPosition()), BuiltSectionInfo.EMPTY, Collections.emptyMap())); this.buildResults.add(result); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java index 51daa27273..b099540053 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java @@ -46,7 +46,7 @@ public void deleteAfterUpload() { super.deleteAfterUpload(); // delete translucent data if it's not persisted for dynamic sorting - if (this.translucentData != null && !this.translucentData.getSortType().needsTrigger) { + if (this.translucentData != null && !this.translucentData.retainAfterUpload()) { this.translucentData.delete(); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SortType.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SortType.java index cc22f54a79..f4f611852d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SortType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SortType.java @@ -5,10 +5,20 @@ * building a section. */ public enum SortType { + /** + * The section is fully empty, no index buffer is needed. + */ + EMPTY_SECTION(false, false), + + /** + * The section has no translucent geometry, no index buffer is needed. + */ + NO_TRANSLUCENT(false, false), + /** * No sorting is required and the sort order doesn't matter. */ - NONE(false, false, false), + NONE(false, false), /** * There is only one sort order. No active sorting is required, but an initial @@ -19,31 +29,28 @@ public enum SortType { * changes, remove this note and adjust StaticTranslucentData and anything that * reads from it to handle UNASSIGNED quads. */ - STATIC_NORMAL_RELATIVE(true, false, false), + STATIC_NORMAL_RELATIVE(true, false), /** * There is only one sort order and not active sorting is required, but * determining the static sort order involves doing a toplogical sort of the * quads. */ - STATIC_TOPO(true, true, false), + STATIC_TOPO(true, true), /** * There are multiple sort orders. Sorting is required every time GFNI triggers * this section. */ - DYNAMIC(true, true, true); + DYNAMIC(true, true); public final boolean needsIndexBuffer; public final boolean needsDirectionMixing; - public final boolean needsTrigger; private SortType( boolean needsIndexBuffer, - boolean needsDirectionMixing, - boolean needsTrigger) { + boolean needsDirectionMixing) { this.needsIndexBuffer = needsIndexBuffer; this.needsDirectionMixing = needsDirectionMixing; - this.needsTrigger = needsTrigger; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java index 7be4d9da3a..0f5f58bfc1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java @@ -527,7 +527,7 @@ public TranslucentData getTranslucentData( TranslucentData oldData, BuiltSectionMeshParts translucentMesh, CombinedCameraPos cameraPos) { // means there is no translucent geometry if (translucentMesh == null) { - return new NoData(sectionPos); + return NoData.forNoTranslucent(sectionPos); } // re-use the original translucent data if it's the same. This reduces the diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicData.java index d84ee0f75c..0450de8da6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicData.java @@ -23,6 +23,11 @@ public SortType getSortType() { return SortType.DYNAMIC; } + @Override + public boolean retainAfterUpload() { + return true; + } + public GeometryPlanes getGeometryPlanes() { return this.geometryPlanes; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/NoData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/NoData.java index f1007a7683..db995e38d4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/NoData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/NoData.java @@ -11,12 +11,23 @@ * passed instead. */ public class NoData extends TranslucentData { - public NoData(ChunkSectionPos sectionPos) { + private final SortType reason; + + private NoData(ChunkSectionPos sectionPos, SortType reason) { super(sectionPos); + this.reason = reason; } @Override public SortType getSortType() { - return SortType.NONE; + return reason; + } + + public static NoData forEmptySection(ChunkSectionPos sectionPos) { + return new NoData(sectionPos, SortType.EMPTY_SECTION); + } + + public static NoData forNoTranslucent(ChunkSectionPos sectionPos) { + return new NoData(sectionPos, SortType.NO_TRANSLUCENT); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TranslucentData.java index b3c36bc87d..c7764ab559 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TranslucentData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TranslucentData.java @@ -28,6 +28,10 @@ public abstract class TranslucentData { public abstract SortType getSortType(); + public boolean retainAfterUpload() { + return false; + } + public void delete() { } From 04a39792cd0a861b0762650fe796c21630201d5a Mon Sep 17 00:00:00 2001 From: douira Date: Wed, 24 Jan 2024 23:20:39 +0100 Subject: [PATCH 233/256] remove unused field in sort type enum --- .../chunk/translucent_sorting/SortType.java | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SortType.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SortType.java index f4f611852d..5016034129 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SortType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SortType.java @@ -8,17 +8,17 @@ public enum SortType { /** * The section is fully empty, no index buffer is needed. */ - EMPTY_SECTION(false, false), + EMPTY_SECTION(false), /** * The section has no translucent geometry, no index buffer is needed. */ - NO_TRANSLUCENT(false, false), + NO_TRANSLUCENT(false), /** * No sorting is required and the sort order doesn't matter. */ - NONE(false, false), + NONE(false), /** * There is only one sort order. No active sorting is required, but an initial @@ -29,28 +29,24 @@ public enum SortType { * changes, remove this note and adjust StaticTranslucentData and anything that * reads from it to handle UNASSIGNED quads. */ - STATIC_NORMAL_RELATIVE(true, false), + STATIC_NORMAL_RELATIVE(false), /** * There is only one sort order and not active sorting is required, but * determining the static sort order involves doing a toplogical sort of the * quads. */ - STATIC_TOPO(true, true), + STATIC_TOPO(true), /** * There are multiple sort orders. Sorting is required every time GFNI triggers * this section. */ - DYNAMIC(true, true); + DYNAMIC(true); - public final boolean needsIndexBuffer; public final boolean needsDirectionMixing; - private SortType( - boolean needsIndexBuffer, - boolean needsDirectionMixing) { - this.needsIndexBuffer = needsIndexBuffer; + private SortType(boolean needsDirectionMixing) { this.needsDirectionMixing = needsDirectionMixing; } } From c7141ee8bbf33fa6a52a8c5e2d3bfc19765dcab4 Mon Sep 17 00:00:00 2001 From: douira Date: Thu, 25 Jan 2024 01:24:46 +0100 Subject: [PATCH 234/256] add setting options to customize defer mode --- .../sodium/client/gui/SodiumGameOptions.java | 34 +++++++++++++++---- .../render/chunk/RenderSectionManager.java | 19 ++++------- .../resources/assets/sodium/lang/en_us.json | 6 ++-- 3 files changed, 39 insertions(+), 20 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java index 45578b5f17..6e5e45cc38 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java @@ -39,7 +39,7 @@ public static class PerformanceSettings { public int chunkBuilderThreads = 0; @SerializedName("always_defer_chunk_updates_v2") // this will reset the option in older configs public boolean alwaysDeferChunkUpdates = true; - public DeferSortMode deferSortMode = DeferSortMode.DEFER_ONE_FRAME; + public DeferSortMode deferSortMode = DeferSortMode.DEFER_NEARBY_ONE_FRAME; public boolean animateOnlyVisibleTextures = true; public boolean useEntityCulling = true; @@ -51,16 +51,22 @@ public static class PerformanceSettings { } public enum DeferSortMode implements TextProvider { - ALWAYS("sodium.options.defer_sorting.always", "A"), - DEFER_ONE_FRAME("sodium.options.defer_sorting.defer_one_frame", "1"), - DEFER_ZERO_FRAMES("sodium.options.defer_sorting.defer_zero_frames", "0"); + ALWAYS("sodium.options.defer_sorting.always", "DF", PriorityMode.NONE, DeferMode.ALWAYS), + DEFER_NEARBY_ONE_FRAME("sodium.options.defer_sorting.defer_one_frame", "N1", PriorityMode.NEARBY, DeferMode.ONE_FRAME), + DEFER_NEARBY_ZERO_FRAMES("sodium.options.defer_sorting.defer_zero_frames", "N0", PriorityMode.NEARBY, DeferMode.ZERO_FRAMES), + DEFER_ALL_ONE_FRAME("sodium.options.defer_sorting.defer_all_one_frame", "A1", PriorityMode.ALL, DeferMode.ONE_FRAME), + DEFER_ALL_ZERO_FRAMES("sodium.options.defer_sorting.defer_all_zero_frames", "A0", PriorityMode.ALL, DeferMode.ZERO_FRAMES); private final Text name; - private final String shortName; + private final String shortName; + private final PriorityMode priorityMode; + private final DeferMode deferMode; - DeferSortMode(String name, String shortName) { + DeferSortMode(String name, String shortName, PriorityMode priorityMode, DeferMode deferMode) { this.name = Text.translatable(name); this.shortName = shortName; + this.priorityMode = priorityMode; + this.deferMode = deferMode; } @Override @@ -71,6 +77,22 @@ public Text getLocalizedName() { public String getShortName() { return this.shortName; } + + public PriorityMode getPriorityMode() { + return this.priorityMode; + } + + public DeferMode getDeferMode() { + return this.deferMode; + } + + public static enum PriorityMode { + NONE, NEARBY, ALL + } + + public static enum DeferMode { + ALWAYS, ONE_FRAME, ZERO_FRAMES + } } public enum SortBehavior implements TextProvider { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index 709b1e7617..87a8a2dae3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -11,7 +11,8 @@ import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.gl.device.CommandList; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; -import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions.DeferSortMode; +import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions.DeferSortMode.DeferMode; +import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions.DeferSortMode.PriorityMode; import me.jellysquid.mods.sodium.client.render.chunk.compile.BuilderTaskOutput; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildOutput; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkSortOutput; @@ -414,7 +415,7 @@ public void updateChunks(boolean updateImmediately) { // if zero frame delay is allowed, submit important sorts with the current frame blocking collector. // otherwise submit with the collector that the next frame is blocking on. - if (allowZeroFrameSortWait()) { + if (SodiumClientMod.options().performance.deferSortMode.getDeferMode() == DeferMode.ZERO_FRAMES) { this.submitSectionTasks(thisFrameBlockingCollector, nextFrameBlockingCollector, deferredCollector); } else { this.submitSectionTasks(nextFrameBlockingCollector, nextFrameBlockingCollector, deferredCollector); @@ -571,7 +572,9 @@ public void scheduleSort(long sectionPos, boolean isDirectTrigger) { if (section != null) { var pendingUpdate = ChunkUpdateType.SORT; - if (allowImportantSorts() && this.shouldPrioritizeTask(section)) { + var priorityMode = SodiumClientMod.options().performance.deferSortMode.getPriorityMode(); + if (priorityMode == PriorityMode.ALL + || priorityMode == PriorityMode.NEARBY && this.shouldPrioritizeTask(section)) { pendingUpdate = ChunkUpdateType.IMPORTANT_SORT; } pendingUpdate = ChunkUpdateType.getPromotionUpdateType(section.getPendingUpdate(), pendingUpdate); @@ -617,14 +620,6 @@ private static boolean allowImportantRebuilds() { return !SodiumClientMod.options().performance.alwaysDeferChunkUpdates; } - private static boolean allowImportantSorts() { - return SodiumClientMod.options().performance.deferSortMode != DeferSortMode.ALWAYS; - } - - private static boolean allowZeroFrameSortWait() { - return SodiumClientMod.options().performance.deferSortMode == DeferSortMode.DEFER_ZERO_FRAMES; - } - private float getEffectiveRenderDistance() { var color = RenderSystem.getShaderFogColor(); var distance = RenderSystem.getShaderFogEnd(); @@ -697,7 +692,7 @@ public Collection getDebugStrings() { list.add(String.format("Geometry Pool: %d/%d MiB (%d buffers)", MathUtil.toMib(deviceUsed), MathUtil.toMib(deviceAllocated), count)); list.add(String.format("Transfer Queue: %s", this.regions.getStagingBuffer().toString())); - list.add(String.format("Chunk Builder: Permits=%02d (E %02d) | Busy=%02d | Total=%02d", + list.add(String.format("Chunk Builder: Permits=%02d (E %03d) | Busy=%02d | Total=%02d", this.builder.getScheduledJobCount(), this.builder.getScheduledEffort(), this.builder.getBusyThreadCount(), this.builder.getTotalThreadCount()) ); diff --git a/src/main/resources/assets/sodium/lang/en_us.json b/src/main/resources/assets/sodium/lang/en_us.json index bf8c4b57d9..6fad3e65d0 100644 --- a/src/main/resources/assets/sodium/lang/en_us.json +++ b/src/main/resources/assets/sodium/lang/en_us.json @@ -51,8 +51,10 @@ "sodium.options.always_defer_chunk_updates.tooltip": "If enabled, rendering will never wait for chunk updates to finish, even if they are important. This can greatly improve frame rates in some scenarios, but it may create significant visual lag where blocks take a while to appear or disappear.", "sodium.options.defer_sorting.name": "Defer Sorting", "sodium.options.defer_sorting.always": "Always", - "sodium.options.defer_sorting.defer_one_frame": "Medium", - "sodium.options.defer_sorting.defer_zero_frames": "Least", + "sodium.options.defer_sorting.defer_one_frame": "Nearby Medium", + "sodium.options.defer_sorting.defer_zero_frames": "Nearby None", + "sodium.options.defer_sorting.defer_all_one_frame": "All Medium", + "sodium.options.defer_sorting.defer_all_zero_frames": "All None", "sodium.options.defer_sorting.tooltip": "Controls how much rendering waits for translucency sorting to finish, even if it is important. Brief holes in translucent blocks may be visible unless set to \"Least\".", "sodium.options.use_no_error_context.name": "Use No Error Context", "sodium.options.use_no_error_context.tooltip": "When enabled, the OpenGL context will be created with error checking disabled. This slightly improves rendering performance, but it can make debugging sudden unexplained crashes much harder.", From a410311a5acc31f5b8853a262d4a97137e0e3c7d Mon Sep 17 00:00:00 2001 From: douira Date: Thu, 25 Jan 2024 02:18:07 +0100 Subject: [PATCH 235/256] implement separate effort categories to fix issues when thread count divides the high effort factor --- .../client/render/chunk/ChunkUpdateType.java | 13 ++++--- .../render/chunk/RenderSectionManager.java | 29 +++++++++------ .../chunk/compile/executor/ChunkBuilder.java | 35 ++++++++++++------- .../compile/executor/ChunkJobCollector.java | 33 +++++++++++++---- .../tasks/ChunkBuilderMeshingTask.java | 4 +-- .../tasks/ChunkBuilderSortingTask.java | 5 ++- 6 files changed, 77 insertions(+), 42 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkUpdateType.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkUpdateType.java index 6942f322fa..262a2d8a35 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkUpdateType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkUpdateType.java @@ -1,14 +1,13 @@ package me.jellysquid.mods.sodium.client.render.chunk; -import me.jellysquid.mods.sodium.client.render.chunk.compile.tasks.ChunkBuilderMeshingTask; -import me.jellysquid.mods.sodium.client.render.chunk.compile.tasks.ChunkBuilderSortingTask; +import me.jellysquid.mods.sodium.client.render.chunk.compile.executor.ChunkBuilder; public enum ChunkUpdateType { - SORT(Integer.MAX_VALUE, ChunkBuilderSortingTask.SORT_TASK_EFFORT), - INITIAL_BUILD(128, ChunkBuilderMeshingTask.MESH_TASK_EFFORT), - REBUILD(Integer.MAX_VALUE, ChunkBuilderMeshingTask.MESH_TASK_EFFORT), - IMPORTANT_REBUILD(Integer.MAX_VALUE, ChunkBuilderMeshingTask.MESH_TASK_EFFORT), - IMPORTANT_SORT(Integer.MAX_VALUE, ChunkBuilderSortingTask.SORT_TASK_EFFORT); + SORT(Integer.MAX_VALUE, ChunkBuilder.LOW_EFFORT), + INITIAL_BUILD(128, ChunkBuilder.HIGH_EFFORT), + REBUILD(Integer.MAX_VALUE, ChunkBuilder.HIGH_EFFORT), + IMPORTANT_REBUILD(Integer.MAX_VALUE, ChunkBuilder.HIGH_EFFORT), + IMPORTANT_SORT(Integer.MAX_VALUE, ChunkBuilder.LOW_EFFORT); private final int maximumQueueSize; private final int taskEffort; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index 87a8a2dae3..0d9297989e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -400,7 +400,7 @@ public void updateChunks(boolean updateImmediately) { var thisFrameBlockingCollector = this.lastBlockingCollector; this.lastBlockingCollector = null; if (thisFrameBlockingCollector == null) { - thisFrameBlockingCollector = new ChunkJobCollector(Integer.MAX_VALUE, this.buildResults::add); + thisFrameBlockingCollector = new ChunkJobCollector(this.buildResults::add); } if (updateImmediately) { @@ -410,8 +410,11 @@ public void updateChunks(boolean updateImmediately) { thisFrameBlockingCollector.awaitCompletion(this.builder); } else { - var nextFrameBlockingCollector = new ChunkJobCollector(Integer.MAX_VALUE, this.buildResults::add); - var deferredCollector = new ChunkJobCollector(this.builder.getSchedulingBudget(), this.buildResults::add); + var nextFrameBlockingCollector = new ChunkJobCollector(this.buildResults::add); + var deferredCollector = new ChunkJobCollector( + this.builder.getHighEffortSchedulingBudget(), + this.builder.getLowEffortSchedulingBudget(), + this.buildResults::add); // if zero frame delay is allowed, submit important sorts with the current frame blocking collector. // otherwise submit with the collector that the next frame is blocking on. @@ -434,17 +437,22 @@ private void submitSectionTasks( ChunkJobCollector importantCollector, ChunkJobCollector semiImportantCollector, ChunkJobCollector deferredCollector) { - this.submitSectionTasks(importantCollector, ChunkUpdateType.IMPORTANT_SORT); - this.submitSectionTasks(semiImportantCollector, ChunkUpdateType.IMPORTANT_REBUILD); - this.submitSectionTasks(deferredCollector, ChunkUpdateType.REBUILD); - this.submitSectionTasks(deferredCollector, ChunkUpdateType.INITIAL_BUILD); - this.submitSectionTasks(deferredCollector, ChunkUpdateType.SORT); + this.submitSectionTasks(importantCollector, ChunkUpdateType.IMPORTANT_SORT, true); + this.submitSectionTasks(semiImportantCollector, ChunkUpdateType.IMPORTANT_REBUILD, true); + + // since the sort tasks are run last, the effort category can be ignored and + // simply fills up the remaining budget. Splitting effort categories is still + // important to prevent high effort tasks from using up the entire budget if it + // happens to divide evenly. + this.submitSectionTasks(deferredCollector, ChunkUpdateType.REBUILD, false); + this.submitSectionTasks(deferredCollector, ChunkUpdateType.INITIAL_BUILD, false); + this.submitSectionTasks(deferredCollector, ChunkUpdateType.SORT, true); } - private void submitSectionTasks(ChunkJobCollector collector, ChunkUpdateType type) { + private void submitSectionTasks(ChunkJobCollector collector, ChunkUpdateType type, boolean ignoreEffortCategory) { var queue = this.taskLists.get(type); - while (!queue.isEmpty() && collector.hasBudgetFor(type.getTaskEffort())) { + while (!queue.isEmpty() && collector.hasBudgetFor(type.getTaskEffort(), ignoreEffortCategory)) { RenderSection section = queue.remove(); if (section.isDisposed()) { @@ -498,6 +506,7 @@ private void submitSectionTasks(ChunkJobCollector collector, ChunkUpdateType typ section.setLastSubmittedFrame(frame); section.setPendingUpdate(null); + System.out.println(frame + " " + section.getPosition() + " " + type); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkBuilder.java index 98b8ae4ddd..a6f01d15de 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkBuilder.java @@ -18,17 +18,20 @@ public class ChunkBuilder { /** - * The effort of a mesh task compared to a sorting task, which always has effort - * 1. This is used to schedule more sorting tasks compared to mesh tasks because - * they're faster. This also needs to capture that there's a limit to how much - * data can be uploaded per frame. Since sort tasks generate index data, which - * is smaller per quad and (on average) per section, more of their results can - * be uploaded in one frame. This number should essentially be a conservative - * estimate of min((mesh task upload size) / (sort task upload size), (mesh task - * time) / (sort task time)). + * The low and high efforts given to the sorting and meshing tasks, + * respectively. This split into two separate effort categories means more + * sorting tasks, which are faster, can be scheduled compared to mesh tasks. + * These values need to capture that there's a limit to how much data can be + * uploaded per frame. Since sort tasks generate index data, which is smaller + * per quad and (on average) per section, more of their results can be uploaded + * in one frame. This number should essentially be a conservative estimate of + * min((mesh task upload size) / (sort task upload size), (mesh task time) / + * (sort task time)). */ - public static final int MESH_TASK_EFFORT_FACTOR = 10; - public static final int EFFORT_PER_THREAD_PER_FRAME = MESH_TASK_EFFORT_FACTOR; + public static final int HIGH_EFFORT = 10; + public static final int LOW_EFFORT = 1; + public static final int EFFORT_PER_THREAD_PER_FRAME = HIGH_EFFORT + LOW_EFFORT; + private static final float HIGH_EFFORT_BUDGET_FACTOR = (float)HIGH_EFFORT / EFFORT_PER_THREAD_PER_FRAME; static final Logger LOGGER = LogManager.getLogger("ChunkBuilder"); @@ -60,13 +63,21 @@ public ChunkBuilder(ClientWorld world, ChunkVertexType vertexType) { } /** - * Returns the remaining number of build tasks which should be scheduled this frame. If an attempt is made to + * Returns the remaining effort for tasks which should be scheduled this frame. If an attempt is made to * spawn more tasks than the budget allows, it will block until resources become available. */ - public int getSchedulingBudget() { + private int getTotalRemainingBudget() { return Math.max(0, this.threads.size() * EFFORT_PER_THREAD_PER_FRAME - this.queue.getEffortSum()); } + public int getHighEffortSchedulingBudget() { + return Math.max(HIGH_EFFORT, (int) (this.getTotalRemainingBudget() * HIGH_EFFORT_BUDGET_FACTOR)); + } + + public int getLowEffortSchedulingBudget() { + return Math.max(LOW_EFFORT, this.getTotalRemainingBudget() - this.getHighEffortSchedulingBudget()); + } + /** *

Notifies all worker threads to stop and blocks until all workers terminate. After the workers have been shut * down, all tasks are cancelled and the pending queues are cleared. If the builder is already stopped, this diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJobCollector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJobCollector.java index 8e79cc472e..050b3be3e5 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJobCollector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJobCollector.java @@ -11,12 +11,20 @@ public class ChunkJobCollector { private final Semaphore semaphore = new Semaphore(0); private final Consumer> collector; private final List submitted = new ArrayList<>(); - private int submittedEffort = 0; + private int submittedHighEffort = 0; + private int submittedLowEffort = 0; - private final int budget; + private final int highEffortBudget; + private final int lowEffortBudget; - public ChunkJobCollector(int budget, Consumer> collector) { - this.budget = budget; + public ChunkJobCollector(Consumer> collector) { + this(Integer.MAX_VALUE, Integer.MAX_VALUE, collector); + } + + public ChunkJobCollector(int highEffortBudget, int lowEffortBudget, + Consumer> collector) { + this.highEffortBudget = highEffortBudget; + this.lowEffortBudget = lowEffortBudget; this.collector = collector; } @@ -43,10 +51,21 @@ public void awaitCompletion(ChunkBuilder builder) { public void addSubmittedJob(ChunkJob job) { this.submitted.add(job); - this.submittedEffort += job.getEffort(); + var effort = job.getEffort(); + if (effort <= ChunkBuilder.LOW_EFFORT) { + this.submittedLowEffort += effort; + } else { + this.submittedHighEffort += effort; + } } - public boolean hasBudgetFor(int effort) { - return (this.budget - this.submittedEffort) >= effort; + public boolean hasBudgetFor(int effort, boolean ignoreEffortCategory) { + if (ignoreEffortCategory) { + return this.submittedLowEffort + this.submittedHighEffort + effort + <= this.highEffortBudget + this.lowEffortBudget; + } + return effort <= ChunkBuilder.LOW_EFFORT + ? this.submittedLowEffort + effort <= this.lowEffortBudget + : this.submittedHighEffort + effort <= this.highEffortBudget; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java index 8404fc7057..290a450ad2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java @@ -45,8 +45,6 @@ * array allocations, they are pooled to ensure that the garbage collector doesn't become overloaded. */ public class ChunkBuilderMeshingTask extends ChunkBuilderTask { - public static final int MESH_TASK_EFFORT = ChunkBuilderSortingTask.SORT_TASK_EFFORT * ChunkBuilder.MESH_TASK_EFFORT_FACTOR; - private final ChunkRenderContext renderContext; public ChunkBuilderMeshingTask(RenderSection render, int buildTime, Vector3dc absoluteCameraPos, ChunkRenderContext renderContext) { @@ -199,6 +197,6 @@ private CrashException fillCrashInfo(CrashReport report, WorldSlice slice, Block @Override public int getEffort() { - return MESH_TASK_EFFORT; + return ChunkBuilder.HIGH_EFFORT; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java index d1a1f802d9..d5733f918d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java @@ -5,12 +5,11 @@ import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildContext; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkSortOutput; +import me.jellysquid.mods.sodium.client.render.chunk.compile.executor.ChunkBuilder; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.DynamicData; import me.jellysquid.mods.sodium.client.util.task.CancellationToken; public class ChunkBuilderSortingTask extends ChunkBuilderTask { - public static final int SORT_TASK_EFFORT = 1; - private final DynamicData dynamicData; public ChunkBuilderSortingTask(RenderSection render, int frame, Vector3dc absoluteCameraPos, @@ -37,6 +36,6 @@ public static ChunkBuilderSortingTask createTask(RenderSection render, int frame @Override public int getEffort() { - return SORT_TASK_EFFORT; + return ChunkBuilder.LOW_EFFORT; } } From ab364cf7031054c5a060a4375afbbfbe236e95ac Mon Sep 17 00:00:00 2001 From: douira Date: Thu, 25 Jan 2024 03:33:31 +0100 Subject: [PATCH 236/256] remove debug print --- .../mods/sodium/client/render/chunk/RenderSectionManager.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index 0d9297989e..277a44686c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -506,7 +506,6 @@ private void submitSectionTasks(ChunkJobCollector collector, ChunkUpdateType typ section.setLastSubmittedFrame(frame); section.setPendingUpdate(null); - System.out.println(frame + " " + section.getPosition() + " " + type); } } From 79f1ee8219d4cbf058ce2c89eec887e0947c2e6e Mon Sep 17 00:00:00 2001 From: douira Date: Thu, 25 Jan 2024 03:57:01 +0100 Subject: [PATCH 237/256] fix unlimited budget collectors having integer overlow --- .../chunk/compile/executor/ChunkJobCollector.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJobCollector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJobCollector.java index 050b3be3e5..1d6a0f0a32 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJobCollector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJobCollector.java @@ -16,13 +16,18 @@ public class ChunkJobCollector { private final int highEffortBudget; private final int lowEffortBudget; + private final boolean unlimitedBudget; public ChunkJobCollector(Consumer> collector) { - this(Integer.MAX_VALUE, Integer.MAX_VALUE, collector); + this.unlimitedBudget = true; + this.highEffortBudget = 0; + this.lowEffortBudget = 0; + this.collector = collector; } public ChunkJobCollector(int highEffortBudget, int lowEffortBudget, Consumer> collector) { + this.unlimitedBudget = false; this.highEffortBudget = highEffortBudget; this.lowEffortBudget = lowEffortBudget; this.collector = collector; @@ -51,6 +56,10 @@ public void awaitCompletion(ChunkBuilder builder) { public void addSubmittedJob(ChunkJob job) { this.submitted.add(job); + + if (this.unlimitedBudget) { + return; + } var effort = job.getEffort(); if (effort <= ChunkBuilder.LOW_EFFORT) { this.submittedLowEffort += effort; @@ -60,6 +69,9 @@ public void addSubmittedJob(ChunkJob job) { } public boolean hasBudgetFor(int effort, boolean ignoreEffortCategory) { + if (this.unlimitedBudget) { + return true; + } if (ignoreEffortCategory) { return this.submittedLowEffort + this.submittedHighEffort + effort <= this.highEffortBudget + this.lowEffortBudget; From d14571c737a122e1796511e26fb8e06b1fb67231 Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 26 Jan 2024 01:55:35 +0100 Subject: [PATCH 238/256] simplify sort settings without removing options --- .../client/gui/SodiumGameOptionPages.java | 8 --- .../sodium/client/gui/SodiumGameOptions.java | 60 +++++++++---------- .../render/chunk/RenderSectionManager.java | 8 +-- .../TranslucentGeometryCollector.java | 4 +- .../trigger/SortTriggering.java | 3 +- .../resources/assets/sodium/lang/en_us.json | 21 +++---- 6 files changed, 43 insertions(+), 61 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java index dbe2b7aaad..9357c9cede 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java @@ -258,14 +258,6 @@ public static OptionPage performance() { .setBinding((opts, value) -> opts.performance.alwaysDeferChunkUpdates = value, opts -> opts.performance.alwaysDeferChunkUpdates) .setFlags(OptionFlag.REQUIRES_RENDERER_UPDATE) .build()) - .add(OptionImpl.createBuilder(SodiumGameOptions.DeferSortMode.class, sodiumOpts) - .setName(Text.translatable("sodium.options.defer_sorting.name")) - .setTooltip(Text.translatable("sodium.options.defer_sorting.tooltip")) - .setControl(option -> new CyclingControl<>(option, SodiumGameOptions.DeferSortMode.class)) - .setImpact(OptionImpact.MEDIUM) - .setBinding((opts, value) -> opts.performance.deferSortMode = value, opts -> opts.performance.deferSortMode) - .setFlags(OptionFlag.REQUIRES_RENDERER_UPDATE) - .build()) .build()); groups.add(OptionGroup.createBuilder() diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java index 6e5e45cc38..bec2087600 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java @@ -39,7 +39,6 @@ public static class PerformanceSettings { public int chunkBuilderThreads = 0; @SerializedName("always_defer_chunk_updates_v2") // this will reset the option in older configs public boolean alwaysDeferChunkUpdates = true; - public DeferSortMode deferSortMode = DeferSortMode.DEFER_NEARBY_ONE_FRAME; public boolean animateOnlyVisibleTextures = true; public boolean useEntityCulling = true; @@ -47,28 +46,40 @@ public static class PerformanceSettings { public boolean useBlockFaceCulling = true; public boolean useNoErrorGLContext = true; - public SortBehavior sortBehavior = SortBehavior.DYNAMIC; + public SortBehavior sortBehavior = SortBehavior.DYNAMIC_DEFER_NEARBY_ONE_FRAME; } - public enum DeferSortMode implements TextProvider { - ALWAYS("sodium.options.defer_sorting.always", "DF", PriorityMode.NONE, DeferMode.ALWAYS), - DEFER_NEARBY_ONE_FRAME("sodium.options.defer_sorting.defer_one_frame", "N1", PriorityMode.NEARBY, DeferMode.ONE_FRAME), - DEFER_NEARBY_ZERO_FRAMES("sodium.options.defer_sorting.defer_zero_frames", "N0", PriorityMode.NEARBY, DeferMode.ZERO_FRAMES), - DEFER_ALL_ONE_FRAME("sodium.options.defer_sorting.defer_all_one_frame", "A1", PriorityMode.ALL, DeferMode.ONE_FRAME), - DEFER_ALL_ZERO_FRAMES("sodium.options.defer_sorting.defer_all_zero_frames", "A0", PriorityMode.ALL, DeferMode.ZERO_FRAMES); + public enum SortBehavior implements TextProvider { + OFF("options.off", "OFF", SortMode.NONE), + STATIC("sodium.options.sort_behavior.reduced", "S", SortMode.STATIC), + DYNAMIC_DEFER_ALWAYS("sodium.options.defer_sorting.df", "DF", PriorityMode.NONE, DeferMode.ALWAYS), + DYNAMIC_DEFER_NEARBY_ONE_FRAME("sodium.options.defer_sorting.n1", "N1", PriorityMode.NEARBY, DeferMode.ONE_FRAME), + DYNAMIC_DEFER_NEARBY_ZERO_FRAMES("sodium.options.defer_sorting.n0", "N0", PriorityMode.NEARBY, DeferMode.ZERO_FRAMES), + DYNAMIC_DEFER_ALL_ONE_FRAME("sodium.options.defer_sorting.a1", "A1", PriorityMode.ALL, DeferMode.ONE_FRAME), + DYNAMIC_DEFER_ALL_ZERO_FRAMES("sodium.options.defer_sorting.a0", "A0", PriorityMode.ALL, DeferMode.ZERO_FRAMES); private final Text name; private final String shortName; + private final SortMode sortMode; private final PriorityMode priorityMode; private final DeferMode deferMode; - DeferSortMode(String name, String shortName, PriorityMode priorityMode, DeferMode deferMode) { + SortBehavior(String name, String shortName, SortMode sortMode, PriorityMode priorityMode, DeferMode deferMode) { this.name = Text.translatable(name); this.shortName = shortName; + this.sortMode = sortMode; this.priorityMode = priorityMode; this.deferMode = deferMode; } + SortBehavior(String name, String shortName, SortMode sortMode) { + this(name, shortName, sortMode, null, null); + } + + SortBehavior(String name, String shortName, PriorityMode priorityMode, DeferMode deferMode) { + this(name, shortName, SortMode.DYNAMIC, priorityMode, deferMode); + } + @Override public Text getLocalizedName() { return this.name; @@ -78,6 +89,10 @@ public String getShortName() { return this.shortName; } + public SortMode getSortMode() { + return this.sortMode; + } + public PriorityMode getPriorityMode() { return this.priorityMode; } @@ -86,6 +101,10 @@ public DeferMode getDeferMode() { return this.deferMode; } + public static enum SortMode { + NONE, STATIC, DYNAMIC + } + public static enum PriorityMode { NONE, NEARBY, ALL } @@ -95,29 +114,6 @@ public static enum DeferMode { } } - public enum SortBehavior implements TextProvider { - OFF("options.off", "OFF"), - STATIC("sodium.options.sort_behavior.reduced", "S"), - DYNAMIC("sodium.options.sort_behavior.accurate", "D"); - - private final Text name; - private final String shortName; - - SortBehavior(String name, String shortName) { - this.name = Text.translatable(name); - this.shortName = shortName; - } - - @Override - public Text getLocalizedName() { - return this.name; - } - - public String getShortName() { - return this.shortName; - } - } - public static class AdvancedSettings { public boolean enableMemoryTracing = false; public boolean useAdvancedStagingBuffers = true; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index 277a44686c..278d1f16c9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -11,8 +11,8 @@ import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.gl.device.CommandList; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; -import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions.DeferSortMode.DeferMode; -import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions.DeferSortMode.PriorityMode; +import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions.SortBehavior.DeferMode; +import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions.SortBehavior.PriorityMode; import me.jellysquid.mods.sodium.client.render.chunk.compile.BuilderTaskOutput; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildOutput; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkSortOutput; @@ -418,7 +418,7 @@ public void updateChunks(boolean updateImmediately) { // if zero frame delay is allowed, submit important sorts with the current frame blocking collector. // otherwise submit with the collector that the next frame is blocking on. - if (SodiumClientMod.options().performance.deferSortMode.getDeferMode() == DeferMode.ZERO_FRAMES) { + if (SodiumClientMod.options().performance.sortBehavior.getDeferMode() == DeferMode.ZERO_FRAMES) { this.submitSectionTasks(thisFrameBlockingCollector, nextFrameBlockingCollector, deferredCollector); } else { this.submitSectionTasks(nextFrameBlockingCollector, nextFrameBlockingCollector, deferredCollector); @@ -580,7 +580,7 @@ public void scheduleSort(long sectionPos, boolean isDirectTrigger) { if (section != null) { var pendingUpdate = ChunkUpdateType.SORT; - var priorityMode = SodiumClientMod.options().performance.deferSortMode.getPriorityMode(); + var priorityMode = SodiumClientMod.options().performance.sortBehavior.getPriorityMode(); if (priorityMode == PriorityMode.ALL || priorityMode == PriorityMode.NEARBY && this.shouldPrioritizeTask(section)) { pendingUpdate = ChunkUpdateType.IMPORTANT_SORT; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java index 0f5f58bfc1..56681dcc6b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java @@ -279,10 +279,8 @@ private static SortType filterSortType(SortType sortType) { } else { return SortType.NONE; } - case DYNAMIC: - return sortType; default: - throw new IllegalStateException("Unknown sort behavior: " + sortBehavior); + return sortType; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java index 1da71aa9db..a293f9d835 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java @@ -231,9 +231,8 @@ public void addDebugStrings(List list) { if (sortBehavior == SortBehavior.OFF) { list.add("TS OFF"); } else { - list.add("TS (%s,%s) NL=%02d TrN=%02d TrS=G%03d/D%03d".formatted( + list.add("TS (%s) NL=%02d TrN=%02d TrS=G%03d/D%03d".formatted( sortBehavior.getShortName(), - SodiumClientMod.options().performance.deferSortMode.getShortName(), this.gfni.getUniqueNormalCount(), this.triggeredNormalCount, this.gfniTriggerCount, diff --git a/src/main/resources/assets/sodium/lang/en_us.json b/src/main/resources/assets/sodium/lang/en_us.json index 6fad3e65d0..91d3446bce 100644 --- a/src/main/resources/assets/sodium/lang/en_us.json +++ b/src/main/resources/assets/sodium/lang/en_us.json @@ -49,13 +49,14 @@ "sodium.options.chunk_update_threads.tooltip": "Specifies the number of threads to use for chunk building and sorting. Using more threads can speed up chunk loading and update speed, but may negatively impact frame times. The default value is usually good enough for all situations.", "sodium.options.always_defer_chunk_updates.name": "Always Defer Chunk Updates", "sodium.options.always_defer_chunk_updates.tooltip": "If enabled, rendering will never wait for chunk updates to finish, even if they are important. This can greatly improve frame rates in some scenarios, but it may create significant visual lag where blocks take a while to appear or disappear.", - "sodium.options.defer_sorting.name": "Defer Sorting", - "sodium.options.defer_sorting.always": "Always", - "sodium.options.defer_sorting.defer_one_frame": "Nearby Medium", - "sodium.options.defer_sorting.defer_zero_frames": "Nearby None", - "sodium.options.defer_sorting.defer_all_one_frame": "All Medium", - "sodium.options.defer_sorting.defer_all_zero_frames": "All None", - "sodium.options.defer_sorting.tooltip": "Controls how much rendering waits for translucency sorting to finish, even if it is important. Brief holes in translucent blocks may be visible unless set to \"Least\".", + "sodium.options.sort_behavior.name": "Translucency Sorting", + "sodium.options.sort_behavior.tooltip": "Controls when and with how much effort translucency sorting is performed. While in Reduced mode there will be glitches, the other mods attempt accurate sorting with varying degrees of urgency to avoid holes and glitches during camera movement. More sorting has a performance impact on chunk loading and update speeds, but usually not frame rates.", + "sodium.options.sort_behavior.reduced": "Reduced", + "sodium.options.sort_behavior.df": "Accurate DF", + "sodium.options.sort_behavior.n1": "Accurate N1", + "sodium.options.sort_behavior.n0": "Accurate N0", + "sodium.options.sort_behavior.a1": "Accurate A1", + "sodium.options.sort_behavior.a0": "Accurate A0", "sodium.options.use_no_error_context.name": "Use No Error Context", "sodium.options.use_no_error_context.tooltip": "When enabled, the OpenGL context will be created with error checking disabled. This slightly improves rendering performance, but it can make debugging sudden unexplained crashes much harder.", "sodium.options.buttons.undo": "Undo", @@ -66,9 +67,5 @@ "sodium.console.pojav_launcher": "PojavLauncher is not supported when using Sodium.\n * You are very likely to run into extreme performance issues, graphical bugs, and crashes.\n * You will be on your own if you decide to continue -- we will not help you with any bugs or crashes!", "sodium.console.core_shaders_error": "The following resource packs are incompatible with Sodium:", "sodium.console.core_shaders_warn": "The following resource packs may be incompatible with Sodium:", - "sodium.console.core_shaders_info": "Check the game log for detailed information.", - "sodium.options.sort_behavior.name": "Translucency Sorting", - "sodium.options.sort_behavior.tooltip": "Controls when and with how much effort translucency sorting is performed. Accurate mode attempts correct sorting everywhere while in Reduced mode there will be glitches. More sorting has a performance impact on chunk loading and update speeds, but usually not frame rates.", - "sodium.options.sort_behavior.reduced": "Reduced", - "sodium.options.sort_behavior.accurate": "Accurate" + "sodium.console.core_shaders_info": "Check the game log for detailed information." } From bffe18dcf90b2baa7deac0e9c8783f21044a4b57 Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 26 Jan 2024 01:56:15 +0100 Subject: [PATCH 239/256] typo --- src/main/resources/assets/sodium/lang/en_us.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/assets/sodium/lang/en_us.json b/src/main/resources/assets/sodium/lang/en_us.json index 91d3446bce..0b316b4b90 100644 --- a/src/main/resources/assets/sodium/lang/en_us.json +++ b/src/main/resources/assets/sodium/lang/en_us.json @@ -50,7 +50,7 @@ "sodium.options.always_defer_chunk_updates.name": "Always Defer Chunk Updates", "sodium.options.always_defer_chunk_updates.tooltip": "If enabled, rendering will never wait for chunk updates to finish, even if they are important. This can greatly improve frame rates in some scenarios, but it may create significant visual lag where blocks take a while to appear or disappear.", "sodium.options.sort_behavior.name": "Translucency Sorting", - "sodium.options.sort_behavior.tooltip": "Controls when and with how much effort translucency sorting is performed. While in Reduced mode there will be glitches, the other mods attempt accurate sorting with varying degrees of urgency to avoid holes and glitches during camera movement. More sorting has a performance impact on chunk loading and update speeds, but usually not frame rates.", + "sodium.options.sort_behavior.tooltip": "Controls when and with how much effort translucency sorting is performed. While in Reduced mode there will be glitches, the other modes attempt accurate sorting with varying degrees of urgency to avoid holes and glitches during camera movement. More sorting has a performance impact on chunk loading and update speeds, but usually not frame rates.", "sodium.options.sort_behavior.reduced": "Reduced", "sodium.options.sort_behavior.df": "Accurate DF", "sodium.options.sort_behavior.n1": "Accurate N1", From ae789c2ef1d02fed3cd82310d988785dcd233ceb Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 26 Jan 2024 02:17:19 +0100 Subject: [PATCH 240/256] make translucency sorting a binary option --- .../client/gui/SodiumGameOptionPages.java | 8 +-- .../sodium/client/gui/SodiumGameOptions.java | 68 ++----------------- .../render/chunk/DefaultChunkRenderer.java | 4 +- .../render/chunk/RenderSectionManager.java | 8 +-- .../tasks/ChunkBuilderMeshingTask.java | 4 +- .../translucent_sorting/SortBehavior.java | 60 ++++++++++++++++ .../TranslucentGeometryCollector.java | 5 +- .../trigger/SortTriggering.java | 4 +- .../resources/assets/sodium/lang/en_us.json | 8 +-- 9 files changed, 81 insertions(+), 88 deletions(-) create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SortBehavior.java diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java index 9357c9cede..03043622e2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java @@ -308,12 +308,12 @@ public static OptionPage performance() { .build()); groups.add(OptionGroup.createBuilder() - .add(OptionImpl.createBuilder(SodiumGameOptions.SortBehavior.class, sodiumOpts) + .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) .setName(Text.translatable("sodium.options.sort_behavior.name")) .setTooltip(Text.translatable("sodium.options.sort_behavior.tooltip")) - .setControl(option -> new CyclingControl<>(option, SodiumGameOptions.SortBehavior.class)) - .setBinding((opts, value) -> opts.performance.sortBehavior = value, opts -> opts.performance.sortBehavior) - .setImpact(OptionImpact.MEDIUM) + .setControl(TickBoxControl::new) + .setBinding((opts, value) -> opts.performance.sortingEnabled = value, opts -> opts.performance.sortingEnabled) + .setImpact(OptionImpact.LOW) .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) .build()) .build()); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java index bec2087600..49eb66c6ee 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java @@ -5,6 +5,7 @@ import com.google.gson.GsonBuilder; import com.google.gson.annotations.SerializedName; import me.jellysquid.mods.sodium.client.gui.options.TextProvider; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortBehavior; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.client.option.GraphicsMode; import net.minecraft.text.Text; @@ -46,71 +47,10 @@ public static class PerformanceSettings { public boolean useBlockFaceCulling = true; public boolean useNoErrorGLContext = true; - public SortBehavior sortBehavior = SortBehavior.DYNAMIC_DEFER_NEARBY_ONE_FRAME; - } - - public enum SortBehavior implements TextProvider { - OFF("options.off", "OFF", SortMode.NONE), - STATIC("sodium.options.sort_behavior.reduced", "S", SortMode.STATIC), - DYNAMIC_DEFER_ALWAYS("sodium.options.defer_sorting.df", "DF", PriorityMode.NONE, DeferMode.ALWAYS), - DYNAMIC_DEFER_NEARBY_ONE_FRAME("sodium.options.defer_sorting.n1", "N1", PriorityMode.NEARBY, DeferMode.ONE_FRAME), - DYNAMIC_DEFER_NEARBY_ZERO_FRAMES("sodium.options.defer_sorting.n0", "N0", PriorityMode.NEARBY, DeferMode.ZERO_FRAMES), - DYNAMIC_DEFER_ALL_ONE_FRAME("sodium.options.defer_sorting.a1", "A1", PriorityMode.ALL, DeferMode.ONE_FRAME), - DYNAMIC_DEFER_ALL_ZERO_FRAMES("sodium.options.defer_sorting.a0", "A0", PriorityMode.ALL, DeferMode.ZERO_FRAMES); - - private final Text name; - private final String shortName; - private final SortMode sortMode; - private final PriorityMode priorityMode; - private final DeferMode deferMode; - - SortBehavior(String name, String shortName, SortMode sortMode, PriorityMode priorityMode, DeferMode deferMode) { - this.name = Text.translatable(name); - this.shortName = shortName; - this.sortMode = sortMode; - this.priorityMode = priorityMode; - this.deferMode = deferMode; - } - - SortBehavior(String name, String shortName, SortMode sortMode) { - this(name, shortName, sortMode, null, null); - } - - SortBehavior(String name, String shortName, PriorityMode priorityMode, DeferMode deferMode) { - this(name, shortName, SortMode.DYNAMIC, priorityMode, deferMode); - } - - @Override - public Text getLocalizedName() { - return this.name; - } - - public String getShortName() { - return this.shortName; - } - - public SortMode getSortMode() { - return this.sortMode; - } - - public PriorityMode getPriorityMode() { - return this.priorityMode; - } - - public DeferMode getDeferMode() { - return this.deferMode; - } - - public static enum SortMode { - NONE, STATIC, DYNAMIC - } - - public static enum PriorityMode { - NONE, NEARBY, ALL - } + public boolean sortingEnabled = true; - public static enum DeferMode { - ALWAYS, ONE_FRAME, ZERO_FRAMES + public SortBehavior getSortBehavior() { + return this.sortingEnabled ? SortBehavior.DYNAMIC_DEFER_NEARBY_ONE_FRAME : SortBehavior.OFF; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java index 0bbf51ed1a..b8a360431b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java @@ -10,7 +10,6 @@ import me.jellysquid.mods.sodium.client.gl.tessellation.GlPrimitiveType; import me.jellysquid.mods.sodium.client.gl.tessellation.GlTessellation; import me.jellysquid.mods.sodium.client.gl.tessellation.TessellationBinding; -import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions.SortBehavior; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.render.chunk.data.SectionRenderDataStorage; import me.jellysquid.mods.sodium.client.render.chunk.data.SectionRenderDataUnsafe; @@ -21,6 +20,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.shader.ChunkShaderInterface; import me.jellysquid.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses; import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortBehavior; import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkMeshAttribute; import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexType; import me.jellysquid.mods.sodium.client.render.viewport.CameraTransform; @@ -55,7 +55,7 @@ public void render(ChunkRenderMatrices matrices, super.begin(renderPass); boolean isTranslucent = renderPass == DefaultTerrainRenderPasses.TRANSLUCENT - && SodiumClientMod.options().performance.sortBehavior != SortBehavior.OFF; + && SodiumClientMod.options().performance.getSortBehavior() != SortBehavior.OFF; boolean useBlockFaceCulling = SodiumClientMod.options().performance.useBlockFaceCulling; ChunkShaderInterface shader = this.activeProgram.getInterface(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index 278d1f16c9..f93d4f2a04 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -11,8 +11,6 @@ import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.gl.device.CommandList; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; -import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions.SortBehavior.DeferMode; -import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions.SortBehavior.PriorityMode; import me.jellysquid.mods.sodium.client.render.chunk.compile.BuilderTaskOutput; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildOutput; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkSortOutput; @@ -31,6 +29,8 @@ import me.jellysquid.mods.sodium.client.render.chunk.region.RenderRegion; import me.jellysquid.mods.sodium.client.render.chunk.region.RenderRegionManager; import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortBehavior.DeferMode; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortBehavior.PriorityMode; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.NoData; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TopoSortDynamicData; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; @@ -418,7 +418,7 @@ public void updateChunks(boolean updateImmediately) { // if zero frame delay is allowed, submit important sorts with the current frame blocking collector. // otherwise submit with the collector that the next frame is blocking on. - if (SodiumClientMod.options().performance.sortBehavior.getDeferMode() == DeferMode.ZERO_FRAMES) { + if (SodiumClientMod.options().performance.getSortBehavior().getDeferMode() == DeferMode.ZERO_FRAMES) { this.submitSectionTasks(thisFrameBlockingCollector, nextFrameBlockingCollector, deferredCollector); } else { this.submitSectionTasks(nextFrameBlockingCollector, nextFrameBlockingCollector, deferredCollector); @@ -580,7 +580,7 @@ public void scheduleSort(long sectionPos, boolean isDirectTrigger) { if (section != null) { var pendingUpdate = ChunkUpdateType.SORT; - var priorityMode = SodiumClientMod.options().performance.sortBehavior.getPriorityMode(); + var priorityMode = SodiumClientMod.options().performance.getSortBehavior().getPriorityMode(); if (priorityMode == PriorityMode.ALL || priorityMode == PriorityMode.NEARBY && this.shouldPrioritizeTask(section)) { pendingUpdate = ChunkUpdateType.IMPORTANT_SORT; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java index 290a450ad2..a98080a3a3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java @@ -2,7 +2,6 @@ import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; import me.jellysquid.mods.sodium.client.SodiumClientMod; -import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions.SortBehavior; import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildBuffers; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildContext; @@ -14,6 +13,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; import me.jellysquid.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses; import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortBehavior; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortType; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TranslucentGeometryCollector; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; @@ -78,7 +78,7 @@ public ChunkBuildOutput execute(ChunkBuildContext buildContext, CancellationToke BlockPos.Mutable modelOffset = new BlockPos.Mutable(); TranslucentGeometryCollector collector = null; - if (SodiumClientMod.options().performance.sortBehavior != SortBehavior.OFF) { + if (SodiumClientMod.options().performance.getSortBehavior() != SortBehavior.OFF) { collector = new TranslucentGeometryCollector(render.getPosition()); } BlockRenderContext context = new BlockRenderContext(slice, collector); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SortBehavior.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SortBehavior.java new file mode 100644 index 0000000000..e3382a4305 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SortBehavior.java @@ -0,0 +1,60 @@ +package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; + +public enum SortBehavior { + OFF("OFF", SortMode.NONE), + STATIC("S", SortMode.STATIC), + DYNAMIC_DEFER_ALWAYS("DF", PriorityMode.NONE, DeferMode.ALWAYS), + DYNAMIC_DEFER_NEARBY_ONE_FRAME("N1", PriorityMode.NEARBY, DeferMode.ONE_FRAME), + DYNAMIC_DEFER_NEARBY_ZERO_FRAMES("N0", PriorityMode.NEARBY, DeferMode.ZERO_FRAMES), + DYNAMIC_DEFER_ALL_ONE_FRAME("A1", PriorityMode.ALL, DeferMode.ONE_FRAME), + DYNAMIC_DEFER_ALL_ZERO_FRAMES("A0", PriorityMode.ALL, DeferMode.ZERO_FRAMES); + + private final String shortName; + private final SortBehavior.SortMode sortMode; + private final SortBehavior.PriorityMode priorityMode; + private final SortBehavior.DeferMode deferMode; + + SortBehavior(String shortName, SortBehavior.SortMode sortMode, SortBehavior.PriorityMode priorityMode, + SortBehavior.DeferMode deferMode) { + this.shortName = shortName; + this.sortMode = sortMode; + this.priorityMode = priorityMode; + this.deferMode = deferMode; + } + + SortBehavior(String shortName, SortBehavior.SortMode sortMode) { + this(shortName, sortMode, null, null); + } + + SortBehavior(String shortName, SortBehavior.PriorityMode priorityMode, SortBehavior.DeferMode deferMode) { + this(shortName, SortMode.DYNAMIC, priorityMode, deferMode); + } + + public String getShortName() { + return this.shortName; + } + + public SortBehavior.SortMode getSortMode() { + return this.sortMode; + } + + public SortBehavior.PriorityMode getPriorityMode() { + return this.priorityMode; + } + + public SortBehavior.DeferMode getDeferMode() { + return this.deferMode; + } + + public static enum SortMode { + NONE, STATIC, DYNAMIC + } + + public static enum PriorityMode { + NONE, NEARBY, ALL + } + + public static enum DeferMode { + ALWAYS, ONE_FRAME, ZERO_FRAMES + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java index 56681dcc6b..df89966eae 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java @@ -8,7 +8,6 @@ import it.unimi.dsi.fastutil.objects.ReferenceArrayList; import me.jellysquid.mods.sodium.client.SodiumClientMod; -import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions.SortBehavior; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildOutput; import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.FluidRenderer; @@ -269,7 +268,7 @@ public void appendQuad(int packedNormal, ChunkVertexEncoder.Vertex[] vertices, M * @param sortType the sort type to filter */ private static SortType filterSortType(SortType sortType) { - SortBehavior sortBehavior = SodiumClientMod.options().performance.sortBehavior; + SortBehavior sortBehavior = SodiumClientMod.options().performance.getSortBehavior(); switch (sortBehavior) { case OFF: return SortType.NONE; @@ -328,7 +327,7 @@ private static SortType filterSortType(SortType sortType) { * @return the required sort type to ensure this section always looks correct */ private SortType sortTypeHeuristic() { - SortBehavior sortBehavior = SodiumClientMod.options().performance.sortBehavior; + SortBehavior sortBehavior = SodiumClientMod.options().performance.getSortBehavior(); int alignedNormalCount = Integer.bitCount(this.alignedFacingBitmap); int alignedPlaneCount = alignedNormalCount; if (this.alignedExtentsMultiple) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java index a293f9d835..51c9498a00 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java @@ -7,8 +7,8 @@ import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import me.jellysquid.mods.sodium.client.SodiumClientMod; -import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions.SortBehavior; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.AlignableNormal; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortBehavior; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortType; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.DynamicData; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TopoSortDynamicData; @@ -227,7 +227,7 @@ public void integrateTranslucentData(TranslucentData oldData, TranslucentData ne } public void addDebugStrings(List list) { - var sortBehavior = SodiumClientMod.options().performance.sortBehavior; + var sortBehavior = SodiumClientMod.options().performance.getSortBehavior(); if (sortBehavior == SortBehavior.OFF) { list.add("TS OFF"); } else { diff --git a/src/main/resources/assets/sodium/lang/en_us.json b/src/main/resources/assets/sodium/lang/en_us.json index 0b316b4b90..5180844937 100644 --- a/src/main/resources/assets/sodium/lang/en_us.json +++ b/src/main/resources/assets/sodium/lang/en_us.json @@ -50,13 +50,7 @@ "sodium.options.always_defer_chunk_updates.name": "Always Defer Chunk Updates", "sodium.options.always_defer_chunk_updates.tooltip": "If enabled, rendering will never wait for chunk updates to finish, even if they are important. This can greatly improve frame rates in some scenarios, but it may create significant visual lag where blocks take a while to appear or disappear.", "sodium.options.sort_behavior.name": "Translucency Sorting", - "sodium.options.sort_behavior.tooltip": "Controls when and with how much effort translucency sorting is performed. While in Reduced mode there will be glitches, the other modes attempt accurate sorting with varying degrees of urgency to avoid holes and glitches during camera movement. More sorting has a performance impact on chunk loading and update speeds, but usually not frame rates.", - "sodium.options.sort_behavior.reduced": "Reduced", - "sodium.options.sort_behavior.df": "Accurate DF", - "sodium.options.sort_behavior.n1": "Accurate N1", - "sodium.options.sort_behavior.n0": "Accurate N0", - "sodium.options.sort_behavior.a1": "Accurate A1", - "sodium.options.sort_behavior.a0": "Accurate A0", + "sodium.options.sort_behavior.tooltip": "Enables translucency sorting. This avoids glitches in translucent blocks like water and glass when enabled and attempts to correctly present them even when the camera is in motion. This has a small performance impact on chunk loading and update speeds, but is usually not noticeable in frame rates.", "sodium.options.use_no_error_context.name": "Use No Error Context", "sodium.options.use_no_error_context.tooltip": "When enabled, the OpenGL context will be created with error checking disabled. This slightly improves rendering performance, but it can make debugging sudden unexplained crashes much harder.", "sodium.options.buttons.undo": "Undo", From 875cc619b6647eb8f6607106c3e9b4f109e9a9af Mon Sep 17 00:00:00 2001 From: douira Date: Sun, 28 Jan 2024 02:27:58 +0100 Subject: [PATCH 241/256] fix javadoc --- .../translucent_sorting/trigger/SortTriggering.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java index 51c9498a00..3212abeb8c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java @@ -72,12 +72,7 @@ interface SectionTriggers { * Triggers the sections that the given camera movement crosses face planes of. * * @param triggerSectionCallback called for each section that is triggered - * @param lastCameraX the camera x position before the movement - * @param lastCameraY the camera y position before the movement - * @param lastCameraZ the camera z position before the movement - * @param cameraX the camera x position after the movement - * @param cameraY the camera y position after the movement - * @param cameraZ the camera z position after the movement + * @param movement the camera movement to trigger for */ public void triggerSections(BiConsumer triggerSectionCallback, CameraMovement movement) { triggeredNormals.clear(); @@ -97,7 +92,7 @@ public void triggerSections(BiConsumer triggerSectionCallback, Ca this.directTriggerCount = oldDirectTriggerCount; } - triggerSectionCallback = null; + this.triggerSectionCallback = null; } private boolean isCatchingUp() { From 91c8b9a969be9c5b92cbc93dceabcab4cbba3b41 Mon Sep 17 00:00:00 2001 From: douira Date: Sun, 28 Jan 2024 18:02:08 +0100 Subject: [PATCH 242/256] fix merge --- .../me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java index 0866b84e0d..f0f6f453e6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java @@ -6,6 +6,7 @@ import com.google.gson.annotations.SerializedName; import me.jellysquid.mods.sodium.client.gui.options.TextProvider; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortBehavior; +import me.jellysquid.mods.sodium.client.util.FileUtil; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.client.option.GraphicsMode; import net.minecraft.text.Text; From 3a0be7300add83e01b7262b0755a9ec59b958215 Mon Sep 17 00:00:00 2001 From: douira Date: Sun, 28 Jan 2024 18:02:29 +0100 Subject: [PATCH 243/256] use remove if instead --- .../translucent_sorting/trigger/GFNITriggers.java | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GFNITriggers.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GFNITriggers.java index 75947d0f74..e6007f0f76 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GFNITriggers.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GFNITriggers.java @@ -11,7 +11,7 @@ /** * Performs Global Face Normal Indexing-based triggering as described in * https://hackmd.io/@douira100/sodium-sl-gfni - * + * * Note on precision: Global distances are stored as doubles while * section-relative distances are stored as floats. The distances of the camera * are calculated as doubles, but using float normal vectors (furthermore normal @@ -57,13 +57,7 @@ private boolean removeSectionFromList(NormalList normalList, long sectionPos) { @Override public void removeSection(long sectionPos, TranslucentData data) { - var iterator = this.normalLists.values().iterator(); - while (iterator.hasNext()) { - var normalList = iterator.next(); - if (this.removeSectionFromList(normalList, sectionPos)) { - iterator.remove(); - } - } + this.normalLists.values().removeIf(normalList -> this.removeSectionFromList(normalList, sectionPos)); } @Override From 30d689a3f401238803a1bf6473a084199394b73c Mon Sep 17 00:00:00 2001 From: douira Date: Sun, 28 Jan 2024 18:14:41 +0100 Subject: [PATCH 244/256] fix buildscript --- build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle.kts b/build.gradle.kts index c8f0cde90c..9607f4065e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -66,6 +66,7 @@ dependencies { minecraft(group = "com.mojang", name = "minecraft", version = Constants.MINECRAFT_VERSION) mappings(group = "net.fabricmc", name = "yarn", version = Constants.YARN_VERSION, classifier = "v2") modImplementation(group = "net.fabricmc", name = "fabric-loader", version = Constants.FABRIC_LOADER_VERSION) + modImplementation(group = "com.lodborg", name = "interval-tree", version = "1.0.0") fun addEmbeddedFabricModule(name: String) { val module = fabricApi.module(name, Constants.FABRIC_API_VERSION) From a8a0c6b471c6a6ac97ae7dc7120503677f360732 Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 29 Jan 2024 18:06:04 +0100 Subject: [PATCH 245/256] fix javadoc --- .../data/TopoGraphSorting.java | 16 ++++++++-------- .../translucent_sorting/trigger/NormalList.java | 1 - 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoGraphSorting.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoGraphSorting.java index 9def872a4f..61212fb533 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoGraphSorting.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoGraphSorting.java @@ -14,7 +14,7 @@ * This class contains the sorting algorithms that do topological or distance * sorting. The algorithms are combined in this class to separate them from the * general management code in other classes. - * + * * Rough attempts at underapproximation of the visibility graph where the * conditions for visibility between quads are made more strict did not yield * significantly more robust topo sorting. @@ -27,10 +27,10 @@ private TopoGraphSorting() { * Test if the given point is within the half space defined by the plane anchor * and the plane normal. The normal points away from the space considered to be * inside. - * - * @param planeAnchor the anchor of the plane - * @param planeNormal the normal of the plane - * @param point the point to test + * + * @param planeDistance dot product of the plane + * @param planeNormal the normal of the plane + * @param point the point to test */ private static boolean pointOutsideHalfspace(float planeDistance, Vector3fc planeNormal, Vector3fc point) { return planeNormal.dot(point) > planeDistance; @@ -118,14 +118,14 @@ private static boolean visibilityWithSeparator(TQuad quadA, TQuad quadB, /** * Checks if one quad is visible through the other quad. This accepts arbitrary * quads, even unaligned ones. - * + * * @param quad the quad through which the other quad is being * tested * @param other the quad being tested * @param distancesByNormal a map of normals to sorted arrays of face plane * distances for disproving that the quads are visible * through eachother, null to disable - * + * * @return true if the other quad is visible through the first quad */ private static boolean quadVisibleThrough(TQuad quad, TQuad other, @@ -175,7 +175,7 @@ private static boolean quadVisibleThrough(TQuad quad, TQuad other, * Performs a topological sort without constructing the full graph in memory by * doing a DFS on the implicit graph. Edges are tested as they are searched for * and if necessary separator planes are used to disprove visibility. - * + * * @param indexBuffer the buffer to write the topo sort result to * @param allQuads the quads to sort * @param distancesByNormal a map of normals to sorted arrays of face plane diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalList.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalList.java index 8f12f2e8d2..b74a268f6b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalList.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalList.java @@ -59,7 +59,6 @@ public class NormalList { * normal index. * * @param normal The unit normal vector - * @param collectorKey The geometry collector index */ NormalList(AlignableNormal normal) { this.normal = normal; From aac4478e6a1655220faec0305d4d63449af07f93 Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 29 Jan 2024 19:52:09 +0100 Subject: [PATCH 246/256] fix javadoc, missing this. qualifiers, fix use of sort mode --- .../translucent_sorting/AlignableNormal.java | 12 ++- .../translucent_sorting/SortBehavior.java | 6 +- .../chunk/translucent_sorting/SortType.java | 2 +- .../chunk/translucent_sorting/TQuad.java | 16 ++-- .../TranslucentGeometryCollector.java | 75 +++++++++++-------- .../trigger/SortTriggering.java | 2 +- 6 files changed, 63 insertions(+), 50 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AlignableNormal.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AlignableNormal.java index e082a89043..27173c247a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AlignableNormal.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AlignableNormal.java @@ -55,15 +55,19 @@ public int hashCode() { @Override public boolean equals(Object obj) { - if (this == obj) + if (this == obj) { return true; - if (!super.equals(obj)) + } + if (!super.equals(obj)) { return false; - if (getClass() != obj.getClass()) + } + if (getClass() != obj.getClass()) { return false; + } AlignableNormal other = (AlignableNormal) obj; - if (alignedDirection != other.alignedDirection) + if (this.alignedDirection != other.alignedDirection) { return false; + } return true; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SortBehavior.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SortBehavior.java index e3382a4305..939714f0a4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SortBehavior.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SortBehavior.java @@ -46,15 +46,15 @@ public SortBehavior.DeferMode getDeferMode() { return this.deferMode; } - public static enum SortMode { + public enum SortMode { NONE, STATIC, DYNAMIC } - public static enum PriorityMode { + public enum PriorityMode { NONE, NEARBY, ALL } - public static enum DeferMode { + public enum DeferMode { ALWAYS, ONE_FRAME, ZERO_FRAMES } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SortType.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SortType.java index 5016034129..90cf8c5c81 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SortType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SortType.java @@ -46,7 +46,7 @@ public enum SortType { public final boolean needsDirectionMixing; - private SortType(boolean needsDirectionMixing) { + SortType(boolean needsDirectionMixing) { this.needsDirectionMixing = needsDirectionMixing; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java index 581594f449..d9d53a4335 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java @@ -23,12 +23,12 @@ public class TQuad { */ private static final int QUANTIZATION_FACTOR = 4; - private ModelQuadFacing facing; - private float[] extents; + private final ModelQuadFacing facing; + private final float[] extents; + private final int packedNormal; + private final float dotProduct; private Vector3fc center; // null on aligned quads - private int packedNormal; private Vector3fc quantizedNormal; - private float dotProduct; private TQuad(ModelQuadFacing facing, float[] extents, Vector3fc center, int packedNormal) { this.facing = facing; @@ -125,7 +125,7 @@ int getQuadHash() { // the hash code needs to be particularly collision resistant int result = 1; result = 31 * result + Arrays.hashCode(this.extents); - if (facing.isAligned()) { + if (this.facing.isAligned()) { result = 31 * result + this.facing.hashCode(); } else { result = 31 * result + this.packedNormal; @@ -144,11 +144,11 @@ public float getAlignedSurfaceArea() { var dZ = this.extents[5] - this.extents[2]; if (dX == 0) { - return (float) (dY * dZ); + return dY * dZ; } else if (dY == 0) { - return (float) (dX * dZ); + return dX * dZ; } else if (dZ == 0) { - return (float) (dX * dY); + return dX * dY; } else { // non-flat aligned quad, weird edge case return 90; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java index df89966eae..ffa5c26dd7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java @@ -39,13 +39,13 @@ * * An instance of this class is created for each meshing task. It goes through * three stages: - * 1. During meshing it collects the geometry and calculates some metrics on the + * 1. During meshing, it collects the geometry and calculates some metrics on the * fly. These are later used for the sort type heuristic. * 2. With {@link #finishRendering()} it finishes the geometry collection, * generates the quad list, and calculates additional metrics. Then the sort * type is determined with a heuristic based on the collected metrics. This * determines if block face culling can be enabled. - * - Now the {@link BuiltSectionMeshParts} is generates which yields the vertex + * - Now the {@link BuiltSectionMeshParts} is generated, which yields the vertex * ranges. * 3. The vertex ranges and the mesh parts object are used by the collector in * the construction of the {@link TranslucentData} object. The data object @@ -69,7 +69,7 @@ public class TranslucentGeometryCollector { private int alignedFacingBitmap = 0; // AABB of the geometry - private float[] extents = new float[] { + private final float[] extents = new float[] { Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY }; @@ -79,7 +79,7 @@ public class TranslucentGeometryCollector { // the maximum (or minimum for negative directions) of quads with a particular // facing. (Dot product of the normal with a vertex for all aligned facings) - private float[] alignedExtremes = new float[] { + private final float[] alignedExtremes = new float[] { Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY }; @@ -198,7 +198,7 @@ public void appendQuad(int packedNormal, ChunkVertexEncoder.Vertex[] vertices, M if (facing.isAligned()) { // only update global extents if there are no unaligned quads since this is only - // used for the convex box test which doesn't work with unaligned quads anyways + // used for the convex box test which doesn't work with unaligned quads anyway if (!this.hasUnaligned) { this.extents[0] = Math.max(this.extents[0], posXExtent); this.extents[1] = Math.max(this.extents[1], posYExtent); @@ -288,7 +288,7 @@ private static SortType filterSortType(SortType sortType) { * normals so that a static topo sort is attempted on it. -1 means the value is * unused and doesn't make sense to give. */ - private static int[] STATIC_TOPO_SORT_ATTEMPT_LIMITS = new int[] { -1, -1, 250, 100, 50, 30 }; + private static final int[] STATIC_TOPO_SORT_ATTEMPT_LIMITS = new int[] { -1, -1, 250, 100, 50, 30 }; /** * Determines the sort type for the collected geometry from the section. It @@ -319,7 +319,7 @@ private static SortType filterSortType(SortType sortType) { * each other, then a special fixed sort order is always a correct sort order. * This ordering sorts the two sets of face planes by their ascending * normal-relative distance. The ordering between the two normals is irrelevant - * as they can't be seen through each other anyways. + * as they can't be seen through each other anyway. * * More heuristics can be performed here to conservatively determine if this * section could possibly have more than one translucent sort order. @@ -328,40 +328,25 @@ private static SortType filterSortType(SortType sortType) { */ private SortType sortTypeHeuristic() { SortBehavior sortBehavior = SodiumClientMod.options().performance.getSortBehavior(); - int alignedNormalCount = Integer.bitCount(this.alignedFacingBitmap); - int alignedPlaneCount = alignedNormalCount; - if (this.alignedExtentsMultiple) { - alignedPlaneCount = 100; - } - - int unalignedPlaneCount = 0; - if (!Float.isNaN(this.unalignedADistance1)) { - unalignedPlaneCount++; - } - if (!Float.isNaN(this.unalignedADistance2)) { - unalignedPlaneCount++; - } - if (!Float.isNaN(this.unalignedBDistance1)) { - unalignedPlaneCount++; - } - if (!Float.isNaN(this.unalignedBDistance2)) { - unalignedPlaneCount++; + if (sortBehavior.getSortMode() == SortBehavior.SortMode.NONE) { + return SortType.NONE; } - int planeCount = alignedPlaneCount + unalignedPlaneCount; + int alignedNormalCount = Integer.bitCount(this.alignedFacingBitmap); + int planeCount = getPlaneCount(alignedNormalCount); int unalignedNormalCount = 0; - if (unalignedANormal != -1) { + if (this.unalignedANormal != -1) { unalignedNormalCount++; } - if (unalignedBNormal != -1) { + if (this.unalignedBNormal != -1) { unalignedNormalCount++; } int normalCount = alignedNormalCount + unalignedNormalCount; // special case A - if (sortBehavior == SortBehavior.OFF || planeCount <= 1) { + if (planeCount <= 1) { return SortType.NONE; } @@ -371,7 +356,7 @@ private SortType sortTypeHeuristic() { || this.alignedFacingBitmap == ModelQuadFacing.OPPOSING_Z; // special case B - // if there are just two normals, they are exact opposites of eachother and they + // if there are just two normals, they are exact opposites of each other and they // each only have one distance, there is no way to see through one face to the // other. if (planeCount == 2 && opposingAlignedNormals) { @@ -432,6 +417,29 @@ private SortType sortTypeHeuristic() { return SortType.DYNAMIC; } + private int getPlaneCount(int alignedNormalCount) { + int alignedPlaneCount = alignedNormalCount; + if (this.alignedExtentsMultiple) { + alignedPlaneCount = 100; + } + + int unalignedPlaneCount = 0; + if (!Float.isNaN(this.unalignedADistance1)) { + unalignedPlaneCount++; + } + if (!Float.isNaN(this.unalignedADistance2)) { + unalignedPlaneCount++; + } + if (!Float.isNaN(this.unalignedBDistance1)) { + unalignedPlaneCount++; + } + if (!Float.isNaN(this.unalignedBDistance2)) { + unalignedPlaneCount++; + } + + return alignedPlaneCount + unalignedPlaneCount; + } + public SortType finishRendering() { // combine the quads into one array int totalQuadCount = 0; @@ -497,8 +505,8 @@ private TranslucentData makeNewTranslucentData(BuiltSectionMeshParts translucent // TODO: investigate existing BSP build failures, then remove this logging LOGGER.warn( "BSP build failure at {}. Please report this to douira for evaluation alongside with some way of reproducing the geometry in this section. (coordinates and world file or seed)", - sectionPos); - var geometryPlanes = GeometryPlanes.fromQuadLists(sectionPos, this.quads); + this.sectionPos); + var geometryPlanes = GeometryPlanes.fromQuadLists(this.sectionPos, this.quads); return TopoSortDynamicData.fromMesh( translucentMesh, cameraPos, this.quads, this.sectionPos, geometryPlanes, buffer); @@ -517,6 +525,7 @@ private int getQuadHash(TQuad[] quads) { var quad = quads[i]; this.quadHash = this.quadHash * 31 + quad.getQuadHash() + i * 3; } + this.quadHashPresent = true; return this.quadHash; } @@ -524,7 +533,7 @@ public TranslucentData getTranslucentData( TranslucentData oldData, BuiltSectionMeshParts translucentMesh, CombinedCameraPos cameraPos) { // means there is no translucent geometry if (translucentMesh == null) { - return NoData.forNoTranslucent(sectionPos); + return NoData.forNoTranslucent(this.sectionPos); } // re-use the original translucent data if it's the same. This reduces the diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java index 3212abeb8c..6f3c5e16db 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java @@ -223,7 +223,7 @@ public void integrateTranslucentData(TranslucentData oldData, TranslucentData ne public void addDebugStrings(List list) { var sortBehavior = SodiumClientMod.options().performance.getSortBehavior(); - if (sortBehavior == SortBehavior.OFF) { + if (sortBehavior.getSortMode() == SortBehavior.SortMode.NONE) { list.add("TS OFF"); } else { list.add("TS (%s) NL=%02d TrN=%02d TrS=G%03d/D%03d".formatted( From 8a857dc80179bac2662bc5a6eee15088b53c285a Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Thu, 1 Feb 2024 21:19:23 -0500 Subject: [PATCH 247/256] Migrate to official mappings --- build.gradle.kts | 3 +- .../mods/sodium/api/math/MatrixHelper.java | 10 +- .../mods/sodium/api/util/NormI8.java | 4 +- .../attributes/CommonVertexAttribute.java | 18 +- .../api/vertex/buffer/VertexBufferWriter.java | 2 +- .../vertex/format/VertexFormatRegistry.java | 2 +- .../api/vertex/format/common/ColorVertex.java | 4 +- .../api/vertex/format/common/GlyphVertex.java | 4 +- .../api/vertex/format/common/LineVertex.java | 4 +- .../api/vertex/format/common/ModelVertex.java | 4 +- .../vertex/format/common/ParticleVertex.java | 4 +- .../mods/sodium/client/SodiumClientMod.java | 4 +- .../checks/EarlyDriverScanner.java | 5 +- .../checks/LateDriverScanner.java | 10 +- .../compatibility/checks/ModuleScanner.java | 21 +- .../checks/ResourcePackScanner.java | 46 ++-- .../checks/SodiumResourcePackMetadata.java | 7 +- .../probe/GraphicsAdapterProbe.java | 7 +- .../workarounds/Workarounds.java | 11 +- .../nvidia/NvidiaDriverVersion.java | 1 + .../workarounds/nvidia/NvidiaWorkarounds.java | 6 +- .../data/fingerprint/FingerprintMeasure.java | 7 +- .../client/gl/device/GLRenderDevice.java | 5 +- .../client/gl/device/MultiDrawBatch.java | 1 - .../sodium/client/gl/shader/GlProgram.java | 8 +- .../sodium/client/gl/shader/GlShader.java | 8 +- .../sodium/client/gl/shader/ShaderLoader.java | 6 +- .../sodium/client/gl/shader/ShaderParser.java | 5 +- .../client/gui/SodiumGameOptionPages.java | 225 +++++++++--------- .../sodium/client/gui/SodiumGameOptions.java | 15 +- .../sodium/client/gui/SodiumOptionsGUI.java | 102 ++++---- .../sodium/client/gui/console/Console.java | 4 +- .../client/gui/console/ConsoleHooks.java | 4 +- .../client/gui/console/ConsoleRenderer.java | 56 ++--- .../client/gui/console/ConsoleSink.java | 4 +- .../client/gui/console/message/Message.java | 4 +- .../sodium/client/gui/options/Option.java | 7 +- .../client/gui/options/OptionImpact.java | 20 +- .../sodium/client/gui/options/OptionImpl.java | 22 +- .../sodium/client/gui/options/OptionPage.java | 8 +- .../client/gui/options/TextProvider.java | 4 +- .../compat/VanillaBooleanOptionBinding.java | 18 +- .../gui/options/control/ControlElement.java | 28 +-- .../control/ControlValueFormatter.java | 26 +- .../gui/options/control/CyclingControl.java | 29 ++- .../gui/options/control/SliderControl.java | 34 +-- .../gui/options/control/TickBoxControl.java | 11 +- .../storage/MinecraftOptionsStorage.java | 14 +- .../client/gui/prompt/ScreenPrompt.java | 47 ++-- .../gui/screen/ConfigCorruptedScreen.java | 38 +-- .../client/gui/widgets/AbstractWidget.java | 78 +++--- .../client/gui/widgets/FlatButtonWidget.java | 39 ++- .../client/model/color/ColorProvider.java | 2 +- .../model/color/ColorProviderRegistry.java | 13 +- .../model/color/DefaultColorProviders.java | 15 +- .../color/interop/BlockColorsExtended.java | 8 +- .../color/interop/ItemColorsExtended.java | 6 +- .../client/model/light/LightPipeline.java | 4 +- .../model/light/data/ArrayLightDataCache.java | 15 +- .../model/light/data/HashLightDataCache.java | 6 +- .../model/light/data/LightDataAccess.java | 60 ++--- .../model/light/flat/FlatLightPipeline.java | 21 +- .../client/model/light/smooth/AoFaceData.java | 20 +- .../model/light/smooth/AoNeighborInfo.java | 4 +- .../light/smooth/SmoothLightPipeline.java | 14 +- .../client/model/quad/BakedQuadView.java | 1 - .../sodium/client/model/quad/ModelQuad.java | 12 +- .../client/model/quad/ModelQuadView.java | 6 +- .../model/quad/ModelQuadViewMutable.java | 6 +- .../quad/blender/BlendedColorProvider.java | 10 +- .../quad/properties/ModelQuadFacing.java | 2 +- .../model/quad/properties/ModelQuadFlags.java | 2 +- .../sodium/client/platform/MessageBox.java | 13 +- .../sodium/client/platform/unix/Libc.java | 1 + .../platform/windows/WindowsCommandLine.java | 1 - .../windows/WindowsDriverStoreVersion.java | 1 + .../client/platform/windows/api/Kernel32.java | 1 - .../client/render/SodiumWorldRenderer.java | 170 +++++++------ .../render/chunk/ChunkRenderMatrices.java | 8 +- .../render/chunk/DefaultChunkRenderer.java | 3 +- .../render/chunk/NonStoringBuilderPool.java | 14 +- .../client/render/chunk/RenderSection.java | 16 +- .../render/chunk/RenderSectionManager.java | 59 ++--- .../render/chunk/ShaderChunkRenderer.java | 9 +- .../render/chunk/SharedQuadIndexBuffer.java | 2 +- .../chunk/compile/ChunkBuildContext.java | 9 +- .../buffers/BakedChunkModelBuilder.java | 4 +- .../compile/buffers/ChunkModelBuilder.java | 4 +- .../chunk/compile/executor/ChunkBuilder.java | 9 +- .../chunk/compile/executor/ChunkJobQueue.java | 1 - .../compile/executor/ChunkJobResult.java | 4 +- .../compile/pipeline/BlockOcclusionCache.java | 34 +-- .../compile/pipeline/BlockRenderCache.java | 15 +- .../compile/pipeline/BlockRenderContext.java | 8 +- .../chunk/compile/pipeline/BlockRenderer.java | 47 ++-- .../chunk/compile/pipeline/FluidRenderer.java | 177 +++++++------- .../tasks/ChunkBuilderMeshingTask.java | 63 +++-- .../render/chunk/data/BuiltSectionInfo.java | 28 +-- .../chunk/data/SectionRenderDataStorage.java | 1 - .../client/render/chunk/map/ChunkTracker.java | 14 +- .../render/chunk/map/ChunkTrackerHolder.java | 4 +- .../chunk/occlusion/GraphDirection.java | 2 +- .../chunk/occlusion/OcclusionCuller.java | 24 +- .../chunk/occlusion/VisibilityEncoding.java | 6 +- .../render/chunk/region/RenderRegion.java | 4 +- .../chunk/region/RenderRegionManager.java | 4 + .../chunk/shader/ChunkShaderFogComponent.java | 2 +- .../terrain/DefaultTerrainRenderPasses.java | 8 +- .../chunk/terrain/TerrainRenderPass.java | 10 +- .../terrain/material/DefaultMaterials.java | 22 +- .../builder/ChunkMeshBufferBuilder.java | 1 - .../render/immediate/CloudRenderer.java | 169 ++++++------- .../immediate/model/BakedModelEncoder.java | 14 +- .../immediate/model/EntityRenderer.java | 52 ++-- .../render/immediate/model/ModelCuboid.java | 3 +- .../render/immediate/model/ModelPartData.java | 2 +- .../client/render/texture/SpriteUtil.java | 10 +- .../render/vertex/VertexConsumerTracker.java | 2 +- .../render/vertex/VertexConsumerUtils.java | 2 +- .../vertex/VertexFormatDescriptionImpl.java | 12 +- .../vertex/VertexFormatRegistryImpl.java | 3 +- .../vertex/buffer/SodiumBufferBuilder.java | 30 +-- .../generated/VertexSerializerFactory.java | 1 - .../client/render/viewport/Viewport.java | 18 +- .../sodium/client/util/DirectionUtil.java | 3 +- .../sodium/client/util/ModelQuadUtil.java | 8 +- .../sodium/client/util/NativeImageHelper.java | 9 +- .../sodium/client/util/color/BoxBlur.java | 4 +- .../sodium/client/util/color/ColorSRGB.java | 4 +- .../client/util/color/FastCubicSampler.java | 35 ++- .../client/util/sorting/AbstractSort.java | 1 + .../sodium/client/util/sorting/MergeSort.java | 1 + .../client/util/sorting/VertexSorters.java | 6 +- .../client/world/BiomeSeedProvider.java | 4 +- .../client/world/PaletteStorageExtended.java | 2 +- .../world/ReadableContainerExtended.java | 8 +- .../mods/sodium/client/world/WorldSlice.java | 130 +++++----- .../client/world/biome/BiomeColorCache.java | 32 +-- .../client/world/biome/BiomeColorMaps.java | 8 +- .../client/world/biome/BiomeColorSource.java | 10 +- .../sodium/client/world/biome/BiomeSlice.java | 85 +++---- .../world/cloned/ChunkRenderContext.java | 14 +- .../world/cloned/ClonedChunkSection.java | 103 ++++---- .../world/cloned/ClonedChunkSectionCache.java | 28 +-- .../mixin/core/MinecraftClientMixin.java | 21 +- .../mods/sodium/mixin/core/WindowMixin.java | 2 +- .../core/gui/WorldLoadingStateMixin.java | 14 +- .../core/model/colors/BlockColorsMixin.java | 16 +- .../core/model/colors/ItemColorsMixin.java | 14 +- .../mixin/core/model/quad/BakedQuadMixin.java | 34 +-- .../core/render/VertexFormatAccessor.java | 2 +- .../core/render/frustum/FrustumMixin.java | 12 +- .../consumer/BufferBuilderMixin.java | 51 ++-- .../consumer/OutlineVertexConsumerMixin.java | 10 +- .../consumer/OverlayVertexConsumerMixin.java | 18 +- .../SpriteTexturedVertexConsumerMixin.java | 18 +- .../VertexConsumerProviderImmediateMixin.java | 10 +- .../consumer/VertexConsumersMixin.java | 6 +- .../world/BufferBuilderStorageMixin.java | 10 +- .../core/render/world/WorldRendererMixin.java | 72 +++--- .../core/world/biome/ClientWorldMixin.java | 30 +-- .../world/chunk/EmptyPaletteStorageMixin.java | 8 +- .../world/chunk/PackedIntegerArrayMixin.java | 18 +- .../world/chunk/PalettedContainerMixin.java | 24 +- .../world/map/ClientChunkManagerMixin.java | 32 +-- .../map/ClientPlayNetworkHandlerMixin.java | 24 +- .../core/world/map/ClientWorldMixin.java | 4 +- .../debug/checks/AbstractTextureMixin.java | 6 +- .../mixin/debug/checks/AsyncTextureMixin.java | 6 +- .../debug/checks/BufferRendererMixin.java | 6 +- .../mixin/debug/checks/FramebufferMixin.java | 10 +- .../checks/NativeImageBackedTextureMixin.java | 6 +- .../mixin/debug/checks/NativeImageMixin.java | 2 +- .../debug/checks/PlayerSkinTextureMixin.java | 20 +- .../mixin/debug/checks/RenderSystemMixin.java | 4 +- .../debug/checks/SpriteAtlasTextureMixin.java | 4 +- .../SpriteContentsAnimatorImplMixin.java | 6 +- .../debug/checks/TextureManagerMixin.java | 8 +- .../mixin/debug/checks/VertexBufferMixin.java | 4 +- .../mixin/debug/checks/VertexFormatMixin.java | 6 +- .../debug/checks/WindowFramebufferMixin.java | 4 +- .../gui/hooks/console/GameRendererMixin.java | 24 +- .../gui/hooks/debug/DebugHudMixin.java | 18 +- .../hooks/settings/OptionsScreenMixin.java | 8 +- .../gui/screen/LevelLoadingScreenMixin.java | 41 ++-- .../model/MultipartBakedModelMixin.java | 22 +- .../model/WeightedBakedModelMixin.java | 24 +- .../options/overlays/InGameHudMixin.java | 6 +- .../render_layers/LeavesBlockMixin.java | 19 +- .../render_layers/RenderLayersMixin.java | 14 +- .../options/weather/WorldRendererMixin.java | 10 +- .../features/render/entity/CuboidMixin.java | 8 +- .../render/entity/ModelPartMixin.java | 43 ++-- .../entity/cull/EntityRendererMixin.java | 8 +- .../shadows/EntityRenderDispatcherMixin.java | 51 ++-- .../render/gui/font/GlyphRendererMixin.java | 40 ++-- .../gui/outlines/WorldRendererMixin.java | 17 +- .../render/immediate/DirectionMixin.java | 16 +- .../intrinsics/BufferBuilderMixin.java | 32 +-- .../sorting/BufferBuilderMixin.java | 37 ++- .../sorting/VertexSorterMixin.java | 6 +- .../matrix_stack/MatrixStackMixin.java | 32 +-- .../matrix_stack/VertexConsumerMixin.java | 3 +- .../render/model/RenderLayersMixin.java | 18 +- .../model/block/BlockModelRendererMixin.java | 41 ++-- .../render/model/item/ItemRendererMixin.java | 41 ++-- .../particle/BillboardParticleMixin.java | 58 ++--- .../world/clouds/WorldRendererMixin.java | 26 +- .../world/sky/BackgroundRendererMixin.java | 22 +- .../render/world/sky/ClientWorldMixin.java | 16 +- .../render/world/sky/WorldRendererMixin.java | 20 +- .../shader/uniform/ShaderProgramMixin.java | 18 +- .../textures/NativeImageAccessor.java | 4 +- .../textures/SpriteContentsInvoker.java | 4 +- .../tracking/BlockModelRendererMixin.java | 20 +- .../animations/tracking/DrawContextMixin.java | 14 +- .../tracking/SpriteAtlasTextureMixin.java | 10 +- .../SpriteBillboardParticleMixin.java | 28 +-- .../SpriteContentsAnimationAccessor.java | 6 +- .../SpriteContentsAnimationFrameAccessor.java | 4 +- .../SpriteContentsAnimatorImplMixin.java | 22 +- .../tracking/SpriteContentsMixin.java | 6 +- .../upload/SpriteContentsAccessor.java | 6 +- .../SpriteContentsAnimationAccessor.java | 8 +- .../SpriteContentsAnimationFrameAccessor.java | 4 +- .../SpriteContentsAnimatorImplAccessor.java | 8 +- .../SpriteContentsInterpolationMixin.java | 35 ++- .../textures/mipmaps/MipmapHelperMixin.java | 36 +-- .../textures/mipmaps/SpriteContentsMixin.java | 26 +- .../features/world/biome/BiomeMixin.java | 28 ++- .../world/storage/ClientChunkMapMixin.java | 26 +- .../context_creation/WindowMixin.java | 16 +- .../event_loop/RenderSystemMixin.java | 2 +- src/main/resources/sodium.accesswidener | 34 +-- 234 files changed, 2293 insertions(+), 2232 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index e484a25422..2307d8caf9 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,7 +1,6 @@ object Constants { // https://fabricmc.net/develop/ const val MINECRAFT_VERSION: String = "1.20.4" - const val YARN_VERSION: String = "1.20.4+build.3" const val FABRIC_LOADER_VERSION: String = "0.15.6" const val FABRIC_API_VERSION: String = "0.95.3+1.20.4" @@ -64,7 +63,7 @@ sourceSets { dependencies { minecraft(group = "com.mojang", name = "minecraft", version = Constants.MINECRAFT_VERSION) - mappings(group = "net.fabricmc", name = "yarn", version = Constants.YARN_VERSION, classifier = "v2") + mappings(loom.officialMojangMappings()) modImplementation(group = "net.fabricmc", name = "fabric-loader", version = Constants.FABRIC_LOADER_VERSION) fun addEmbeddedFabricModule(name: String) { diff --git a/src/api/java/net/caffeinemc/mods/sodium/api/math/MatrixHelper.java b/src/api/java/net/caffeinemc/mods/sodium/api/math/MatrixHelper.java index 9f3530f85c..ce49b5dbda 100644 --- a/src/api/java/net/caffeinemc/mods/sodium/api/math/MatrixHelper.java +++ b/src/api/java/net/caffeinemc/mods/sodium/api/math/MatrixHelper.java @@ -1,8 +1,8 @@ package net.caffeinemc.mods.sodium.api.math; +import com.mojang.blaze3d.vertex.PoseStack; import net.caffeinemc.mods.sodium.api.util.NormI8; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.util.math.Direction; +import net.minecraft.core.Direction; import org.joml.Matrix3f; import org.joml.Matrix4f; import org.joml.Vector3f; @@ -120,11 +120,11 @@ public static float transformPositionZ(Matrix4f mat, float x, float y, float z) * @param angleY The angle to rotate by on the Y-axis * @param angleX The angle to rotate by on the X-axis */ - public static void rotateZYX(MatrixStack.Entry matrices, float angleZ, float angleY, float angleX) { - matrices.getPositionMatrix() + public static void rotateZYX(PoseStack.Pose matrices, float angleZ, float angleY, float angleX) { + matrices.pose() .rotateZYX(angleZ, angleY, angleX); - matrices.getNormalMatrix() + matrices.normal() .rotateZYX(angleZ, angleY, angleX); } diff --git a/src/api/java/net/caffeinemc/mods/sodium/api/util/NormI8.java b/src/api/java/net/caffeinemc/mods/sodium/api/util/NormI8.java index 4ed46a98fe..e0f0ed7639 100644 --- a/src/api/java/net/caffeinemc/mods/sodium/api/util/NormI8.java +++ b/src/api/java/net/caffeinemc/mods/sodium/api/util/NormI8.java @@ -1,6 +1,6 @@ package net.caffeinemc.mods.sodium.api.util; -import net.minecraft.util.math.MathHelper; +import net.minecraft.util.Mth; import org.joml.Vector3f; /** @@ -52,7 +52,7 @@ public static int pack(float x, float y, float z) { */ private static int encode(float comp) { // TODO: is the clamp necessary here? our inputs should always be normalized vector components - return ((int) (MathHelper.clamp(comp, -1.0F, 1.0F) * COMPONENT_RANGE) & 255); + return ((int) (Mth.clamp(comp, -1.0F, 1.0F) * COMPONENT_RANGE) & 255); } /** diff --git a/src/api/java/net/caffeinemc/mods/sodium/api/vertex/attributes/CommonVertexAttribute.java b/src/api/java/net/caffeinemc/mods/sodium/api/vertex/attributes/CommonVertexAttribute.java index 6da5c62a38..cdd7c25f7f 100644 --- a/src/api/java/net/caffeinemc/mods/sodium/api/vertex/attributes/CommonVertexAttribute.java +++ b/src/api/java/net/caffeinemc/mods/sodium/api/vertex/attributes/CommonVertexAttribute.java @@ -1,15 +1,15 @@ package net.caffeinemc.mods.sodium.api.vertex.attributes; -import net.minecraft.client.render.VertexFormatElement; -import net.minecraft.client.render.VertexFormats; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.VertexFormatElement; public enum CommonVertexAttribute { - POSITION(VertexFormats.POSITION_ELEMENT), - COLOR(VertexFormats.COLOR_ELEMENT), - TEXTURE(VertexFormats.TEXTURE_ELEMENT), - OVERLAY(VertexFormats.OVERLAY_ELEMENT), - LIGHT(VertexFormats.LIGHT_ELEMENT), - NORMAL(VertexFormats.NORMAL_ELEMENT); + POSITION(DefaultVertexFormat.ELEMENT_POSITION), + COLOR(DefaultVertexFormat.ELEMENT_COLOR), + TEXTURE(DefaultVertexFormat.ELEMENT_UV0), + OVERLAY(DefaultVertexFormat.ELEMENT_UV1), + LIGHT(DefaultVertexFormat.ELEMENT_UV2), + NORMAL(DefaultVertexFormat.ELEMENT_NORMAL); private final VertexFormatElement element; @@ -30,6 +30,6 @@ public static CommonVertexAttribute getCommonType(VertexFormatElement element) { } public int getByteLength() { - return this.element.getByteLength(); + return this.element.getByteSize(); } } diff --git a/src/api/java/net/caffeinemc/mods/sodium/api/vertex/buffer/VertexBufferWriter.java b/src/api/java/net/caffeinemc/mods/sodium/api/vertex/buffer/VertexBufferWriter.java index 376cbeb41b..19ac176227 100644 --- a/src/api/java/net/caffeinemc/mods/sodium/api/vertex/buffer/VertexBufferWriter.java +++ b/src/api/java/net/caffeinemc/mods/sodium/api/vertex/buffer/VertexBufferWriter.java @@ -1,8 +1,8 @@ package net.caffeinemc.mods.sodium.api.vertex.buffer; +import com.mojang.blaze3d.vertex.VertexConsumer; import net.caffeinemc.mods.sodium.api.memory.MemoryIntrinsics; import net.caffeinemc.mods.sodium.api.vertex.format.VertexFormatDescription; -import net.minecraft.client.render.VertexConsumer; import org.jetbrains.annotations.Nullable; import org.lwjgl.system.MemoryStack; diff --git a/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/VertexFormatRegistry.java b/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/VertexFormatRegistry.java index 649ff7dddb..08389a510c 100644 --- a/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/VertexFormatRegistry.java +++ b/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/VertexFormatRegistry.java @@ -1,7 +1,7 @@ package net.caffeinemc.mods.sodium.api.vertex.format; +import com.mojang.blaze3d.vertex.VertexFormat; import net.caffeinemc.mods.sodium.api.internal.DependencyInjection; -import net.minecraft.client.render.VertexFormat; public interface VertexFormatRegistry { VertexFormatRegistry INSTANCE = DependencyInjection.load(VertexFormatRegistry.class, diff --git a/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/common/ColorVertex.java b/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/common/ColorVertex.java index 0138cab706..2c6d46b0d5 100644 --- a/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/common/ColorVertex.java +++ b/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/common/ColorVertex.java @@ -1,16 +1,16 @@ package net.caffeinemc.mods.sodium.api.vertex.format.common; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; import net.caffeinemc.mods.sodium.api.math.MatrixHelper; import net.caffeinemc.mods.sodium.api.vertex.attributes.common.ColorAttribute; import net.caffeinemc.mods.sodium.api.vertex.attributes.common.PositionAttribute; import net.caffeinemc.mods.sodium.api.vertex.format.VertexFormatDescription; import net.caffeinemc.mods.sodium.api.vertex.format.VertexFormatRegistry; -import net.minecraft.client.render.VertexFormats; import org.joml.Matrix4f; public final class ColorVertex { public static final VertexFormatDescription FORMAT = VertexFormatRegistry.instance() - .get(VertexFormats.POSITION_COLOR); + .get(DefaultVertexFormat.POSITION_COLOR); public static final int STRIDE = 16; diff --git a/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/common/GlyphVertex.java b/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/common/GlyphVertex.java index 1092333c48..77ebd99fa1 100644 --- a/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/common/GlyphVertex.java +++ b/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/common/GlyphVertex.java @@ -1,16 +1,16 @@ package net.caffeinemc.mods.sodium.api.vertex.format.common; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; import net.caffeinemc.mods.sodium.api.vertex.attributes.common.ColorAttribute; import net.caffeinemc.mods.sodium.api.vertex.attributes.common.LightAttribute; import net.caffeinemc.mods.sodium.api.vertex.attributes.common.PositionAttribute; import net.caffeinemc.mods.sodium.api.vertex.format.VertexFormatDescription; import net.caffeinemc.mods.sodium.api.vertex.format.VertexFormatRegistry; import net.caffeinemc.mods.sodium.api.vertex.attributes.common.TextureAttribute; -import net.minecraft.client.render.VertexFormats; public final class GlyphVertex { public static final VertexFormatDescription FORMAT = VertexFormatRegistry.instance() - .get(VertexFormats.POSITION_COLOR_TEXTURE_LIGHT); + .get(DefaultVertexFormat.POSITION_COLOR_TEX_LIGHTMAP); public static final int STRIDE = 28; diff --git a/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/common/LineVertex.java b/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/common/LineVertex.java index c3ffa168ac..7f1ec9f306 100644 --- a/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/common/LineVertex.java +++ b/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/common/LineVertex.java @@ -1,15 +1,15 @@ package net.caffeinemc.mods.sodium.api.vertex.format.common; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; import net.caffeinemc.mods.sodium.api.vertex.attributes.common.ColorAttribute; import net.caffeinemc.mods.sodium.api.vertex.attributes.common.NormalAttribute; import net.caffeinemc.mods.sodium.api.vertex.attributes.common.PositionAttribute; import net.caffeinemc.mods.sodium.api.vertex.format.VertexFormatDescription; import net.caffeinemc.mods.sodium.api.vertex.format.VertexFormatRegistry; -import net.minecraft.client.render.VertexFormats; public final class LineVertex { public static final VertexFormatDescription FORMAT = VertexFormatRegistry.instance() - .get(VertexFormats.LINES); + .get(DefaultVertexFormat.POSITION_COLOR_NORMAL); public static final int STRIDE = 20; diff --git a/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/common/ModelVertex.java b/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/common/ModelVertex.java index def1cc8ea1..3b19ed1e79 100644 --- a/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/common/ModelVertex.java +++ b/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/common/ModelVertex.java @@ -1,13 +1,13 @@ package net.caffeinemc.mods.sodium.api.vertex.format.common; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; import net.caffeinemc.mods.sodium.api.vertex.attributes.common.*; import net.caffeinemc.mods.sodium.api.vertex.format.VertexFormatDescription; import net.caffeinemc.mods.sodium.api.vertex.format.VertexFormatRegistry; -import net.minecraft.client.render.VertexFormats; public final class ModelVertex { public static final VertexFormatDescription FORMAT = VertexFormatRegistry.instance() - .get(VertexFormats.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL); + .get(DefaultVertexFormat.NEW_ENTITY); public static final int STRIDE = 36; diff --git a/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/common/ParticleVertex.java b/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/common/ParticleVertex.java index 3dec8b750d..fccca93b05 100644 --- a/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/common/ParticleVertex.java +++ b/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/common/ParticleVertex.java @@ -1,16 +1,16 @@ package net.caffeinemc.mods.sodium.api.vertex.format.common; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; import net.caffeinemc.mods.sodium.api.vertex.attributes.common.ColorAttribute; import net.caffeinemc.mods.sodium.api.vertex.attributes.common.LightAttribute; import net.caffeinemc.mods.sodium.api.vertex.attributes.common.PositionAttribute; import net.caffeinemc.mods.sodium.api.vertex.format.VertexFormatDescription; import net.caffeinemc.mods.sodium.api.vertex.format.VertexFormatRegistry; import net.caffeinemc.mods.sodium.api.vertex.attributes.common.TextureAttribute; -import net.minecraft.client.render.VertexFormats; public final class ParticleVertex { public static final VertexFormatDescription FORMAT = VertexFormatRegistry.instance() - .get(VertexFormats.POSITION_TEXTURE_COLOR_LIGHT); + .get(DefaultVertexFormat.PARTICLE); public static final int STRIDE = 28; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java b/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java index 3de3a87329..578e838310 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java @@ -9,7 +9,7 @@ import net.fabricmc.api.ClientModInitializer; import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.ModContainer; -import net.minecraft.text.Text; +import net.minecraft.network.chat.Component; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -66,7 +66,7 @@ private static SodiumGameOptions loadConfig() { LOGGER.error("Failed to load configuration file", e); LOGGER.error("Using default configuration file in read-only mode"); - Console.instance().logMessage(MessageLevel.SEVERE, Text.translatable("sodium.console.config_not_loaded"), 12.5); + Console.instance().logMessage(MessageLevel.SEVERE, Component.translatable("sodium.console.config_not_loaded"), 12.5); var config = SodiumGameOptions.defaults(); config.setReadOnly(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/checks/EarlyDriverScanner.java b/src/main/java/me/jellysquid/mods/sodium/client/compatibility/checks/EarlyDriverScanner.java index 12e8011d6b..638298190c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/checks/EarlyDriverScanner.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/compatibility/checks/EarlyDriverScanner.java @@ -2,9 +2,10 @@ import me.jellysquid.mods.sodium.client.platform.MessageBox; import me.jellysquid.mods.sodium.client.platform.windows.WindowsDriverStoreVersion; +import net.minecraft.Util; +import me.jellysquid.mods.sodium.client.compatibility.environment.probe.GraphicsAdapterInfo; import me.jellysquid.mods.sodium.client.compatibility.environment.probe.GraphicsAdapterProbe; import me.jellysquid.mods.sodium.client.compatibility.environment.probe.GraphicsAdapterVendor; -import net.minecraft.util.Util; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -58,7 +59,7 @@ private static void showUnsupportedDriverMessageBox(String message, String url) // https://github.com/CaffeineMC/sodium-fabric/issues/899 private static @Nullable WindowsDriverStoreVersion findBrokenIntelGen7GraphicsDriver() { - if (Util.getOperatingSystem() != Util.OperatingSystem.WINDOWS) { + if (Util.getPlatform() != Util.OS.WINDOWS) { return null; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/checks/LateDriverScanner.java b/src/main/java/me/jellysquid/mods/sodium/client/compatibility/checks/LateDriverScanner.java index d6c05c312c..23f11ee9b5 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/checks/LateDriverScanner.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/compatibility/checks/LateDriverScanner.java @@ -3,9 +3,9 @@ import me.jellysquid.mods.sodium.client.compatibility.workarounds.nvidia.NvidiaDriverVersion; import me.jellysquid.mods.sodium.client.gui.console.Console; import me.jellysquid.mods.sodium.client.gui.console.message.MessageLevel; +import net.minecraft.Util; +import net.minecraft.network.chat.Component; import me.jellysquid.mods.sodium.client.compatibility.environment.GLContextInfo; -import net.minecraft.text.Text; -import net.minecraft.util.Util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -20,7 +20,7 @@ public static void onContextInitialized() { checkContextImplementation(); if (isUsingPojavLauncher()) { - Console.instance().logMessage(MessageLevel.SEVERE, Text.translatable("sodium.console.pojav_launcher"), 30.0); + Console.instance().logMessage(MessageLevel.SEVERE, Component.translatable("sodium.console.pojav_launcher"), 30.0); LOGGER.error("It appears that PojavLauncher is being used with an OpenGL compatibility layer. This will " + "likely cause severe performance issues, graphical issues, and crashes when used with Sodium. This " + "configuration is not supported -- you are on your own!"); @@ -41,7 +41,7 @@ private static void checkContextImplementation() { if (!isSupportedNvidiaDriver(driver)) { Console.instance() - .logMessage(MessageLevel.SEVERE, Text.translatable("sodium.console.broken_nvidia_driver"), 30.0); + .logMessage(MessageLevel.SEVERE, Component.translatable("sodium.console.broken_nvidia_driver"), 30.0); LOGGER.error("The NVIDIA graphics driver appears to be out of date. This will likely cause severe " + "performance issues and crashes when used with Sodium. The graphics driver should be updated to " + @@ -56,7 +56,7 @@ private static void checkContextImplementation() { private static boolean isSupportedNvidiaDriver(GLContextInfo driver) { // The Linux driver has two separate branches which have overlapping version numbers, despite also having // different feature sets. As a result, we can't reliably determine which Linux drivers are broken... - if (Util.getOperatingSystem() != Util.OperatingSystem.WINDOWS) { + if (Util.getPlatform() != Util.OS.WINDOWS) { return true; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/checks/ModuleScanner.java b/src/main/java/me/jellysquid/mods/sodium/client/compatibility/checks/ModuleScanner.java index af141f56e0..d07d56bfc9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/checks/ModuleScanner.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/compatibility/checks/ModuleScanner.java @@ -2,16 +2,19 @@ import me.jellysquid.mods.sodium.client.platform.MessageBox; import me.jellysquid.mods.sodium.client.platform.windows.api.Kernel32; +import me.jellysquid.mods.sodium.client.platform.windows.api.version.LanguageCodePage; import me.jellysquid.mods.sodium.client.platform.windows.api.version.Version; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.util.Window; -import net.minecraft.util.WinNativeModuleUtil; +import me.jellysquid.mods.sodium.client.platform.windows.api.version.VersionInfo; +import net.minecraft.client.Minecraft; +import net.minecraft.util.NativeModuleLister; +import net.minecraft.util.NativeModuleLister.NativeModuleInfo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - +import com.mojang.blaze3d.platform.Window; import java.nio.file.Files; import java.nio.file.Path; import java.util.List; +import java.util.regex.Matcher; import java.util.regex.Pattern; /** @@ -25,10 +28,10 @@ public class ModuleScanner { private static final String[] RTSS_HOOKS_MODULE_NAMES = { "RTSSHooks64.dll", "RTSSHooks.dll" }; public static void checkModules() { - List modules; + List modules; try { - modules = WinNativeModuleUtil.collectNativeModules(); + modules = NativeModuleLister.listModules(); } catch (Throwable t) { LOGGER.warn("Failed to scan the currently loaded modules", t); return; @@ -63,7 +66,7 @@ private static void checkRTSSModules() { } if (version == null || !isRTSSCompatible(version)) { - Window window = MinecraftClient.getInstance().getWindow(); + Window window = Minecraft.getInstance().getWindow(); MessageBox.showMessageBox(window, MessageBox.IconType.ERROR, "Sodium Renderer", "You appear to be using an older version of RivaTuner Statistics Server (RTSS) which is not compatible with Sodium. " + "You must either update to a newer version (7.3.4 and later) or close the RivaTuner Statistics Server application.\n\n" + @@ -158,10 +161,10 @@ private static String findRTSSModuleVersion() { return fileVersion; } - private static boolean isModuleLoaded(List modules, String[] names) { + private static boolean isModuleLoaded(List modules, String[] names) { for (var name : names) { for (var module : modules) { - if (module.path.equalsIgnoreCase(name)) { + if (module.name.equalsIgnoreCase(name)) { return true; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/checks/ResourcePackScanner.java b/src/main/java/me/jellysquid/mods/sodium/client/compatibility/checks/ResourcePackScanner.java index e614c00c7e..ce48b6d78f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/checks/ResourcePackScanner.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/compatibility/checks/ResourcePackScanner.java @@ -2,10 +2,14 @@ import me.jellysquid.mods.sodium.client.gui.console.Console; import me.jellysquid.mods.sodium.client.gui.console.message.MessageLevel; -import net.minecraft.resource.*; -import net.minecraft.text.MutableText; -import net.minecraft.text.Text; -import net.minecraft.util.Identifier; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.FilePackResources; +import net.minecraft.server.packs.PackResources; +import net.minecraft.server.packs.PackType; +import net.minecraft.server.packs.PathPackResources; +import net.minecraft.server.packs.resources.ResourceManager; import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -50,7 +54,7 @@ public class ResourcePackScanner { * Detailed information on shader files replaced by resource packs is printed in the client log. */ public static void checkIfCoreShaderLoaded(ResourceManager manager) { - var outputs = manager.streamResourcePacks() + var outputs = manager.listPacks() .filter(ResourcePackScanner::isExternalResourcePack) .map(ResourcePackScanner::scanResources) .toList(); @@ -71,27 +75,27 @@ private static void printToasts(Collection resourcePacks) { boolean shown = false; if (!incompatibleResourcePacks.isEmpty()) { - showConsoleMessage(Text.translatable("sodium.console.core_shaders_error"), MessageLevel.SEVERE); + showConsoleMessage(Component.translatable("sodium.console.core_shaders_error"), MessageLevel.SEVERE); for (var entry : incompatibleResourcePacks) { - showConsoleMessage(Text.literal(getResourcePackName(entry.resourcePack)), MessageLevel.SEVERE); + showConsoleMessage(Component.literal(getResourcePackName(entry.resourcePack)), MessageLevel.SEVERE); } shown = true; } if (!likelyIncompatibleResourcePacks.isEmpty()) { - showConsoleMessage(Text.translatable("sodium.console.core_shaders_warn"), MessageLevel.WARN); + showConsoleMessage(Component.translatable("sodium.console.core_shaders_warn"), MessageLevel.WARN); for (var entry : likelyIncompatibleResourcePacks) { - showConsoleMessage(Text.literal(getResourcePackName(entry.resourcePack)), MessageLevel.WARN); + showConsoleMessage(Component.literal(getResourcePackName(entry.resourcePack)), MessageLevel.WARN); } shown = true; } if (shown) { - showConsoleMessage(Text.translatable("sodium.console.core_shaders_info"), MessageLevel.INFO); + showConsoleMessage(Component.translatable("sodium.console.core_shaders_info"), MessageLevel.INFO); } } @@ -139,7 +143,7 @@ private static void emitProblem(StringBuilder builder, String description, Strin } @NotNull - private static ScannedResourcePack scanResources(ResourcePack resourcePack) { + private static ScannedResourcePack scanResources(PackResources resourcePack) { final var ignoredShaders = determineIgnoredShaders(resourcePack); if (!ignoredShaders.isEmpty()) { @@ -150,7 +154,7 @@ private static ScannedResourcePack scanResources(ResourcePack resourcePack) { final var unsupportedShaderPrograms = new ArrayList(); final var unsupportedShaderIncludes = new ArrayList(); - resourcePack.findResources(ResourceType.CLIENT_RESOURCES, Identifier.DEFAULT_NAMESPACE, "shaders", (identifier, supplier) -> { + resourcePack.listResources(PackType.CLIENT_RESOURCES, ResourceLocation.DEFAULT_NAMESPACE, "shaders", (identifier, supplier) -> { // Trim full shader file path to only contain the filename final var path = identifier.getPath(); final var name = path.substring(path.lastIndexOf('/') + 1); @@ -172,12 +176,12 @@ private static ScannedResourcePack scanResources(ResourcePack resourcePack) { return new ScannedResourcePack(resourcePack, unsupportedShaderPrograms, unsupportedShaderIncludes); } - private static boolean isExternalResourcePack(ResourcePack pack) { - return pack instanceof DirectoryResourcePack || pack instanceof ZipResourcePack; + private static boolean isExternalResourcePack(PackResources pack) { + return pack instanceof PathPackResources || pack instanceof FilePackResources; } - private static String getResourcePackName(ResourcePack pack) { - var path = pack.getName(); + private static String getResourcePackName(PackResources pack) { + var path = pack.packId(); // Omit 'file/' prefix for the in-game message return path.startsWith("file/") ? path.substring(5) : path; @@ -191,24 +195,24 @@ private static String getResourcePackName(ResourcePack pack) { * @param resourcePack The resource pack to fetch the ignored shaders of * @return A list of shaders to ignore, this is the filename only without the path */ - private static List determineIgnoredShaders(ResourcePack resourcePack) { + private static List determineIgnoredShaders(PackResources resourcePack) { var ignoredShaders = new ArrayList(); try { - var meta = resourcePack.parseMetadata(SodiumResourcePackMetadata.SERIALIZER); + var meta = resourcePack.getMetadataSection(SodiumResourcePackMetadata.SERIALIZER); if (meta != null) { ignoredShaders.addAll(meta.ignoredShaders()); } } catch (IOException x) { - LOGGER.error("Failed to load pack.mcmeta file for resource pack '{}'", resourcePack.getName()); + LOGGER.error("Failed to load pack.mcmeta file for resource pack '{}'", resourcePack.packId()); } return ignoredShaders; } - private static void showConsoleMessage(MutableText message, MessageLevel messageLevel) { + private static void showConsoleMessage(MutableComponent message, MessageLevel messageLevel) { Console.instance().logMessage(messageLevel, message, 12.5); } - private record ScannedResourcePack(ResourcePack resourcePack, + private record ScannedResourcePack(PackResources resourcePack, ArrayList shaderPrograms, ArrayList shaderIncludes) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/checks/SodiumResourcePackMetadata.java b/src/main/java/me/jellysquid/mods/sodium/client/compatibility/checks/SodiumResourcePackMetadata.java index cbce1f5a24..c10d20520a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/checks/SodiumResourcePackMetadata.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/compatibility/checks/SodiumResourcePackMetadata.java @@ -2,9 +2,8 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; -import net.minecraft.resource.metadata.ResourceMetadataSerializer; - import java.util.List; +import net.minecraft.server.packs.metadata.MetadataSectionType; /** * Reads additional metadata for Sodium from a resource pack's `pack.mcmeta` file. This allows the @@ -17,6 +16,6 @@ public record SodiumResourcePackMetadata(List ignoredShaders) { .forGetter(SodiumResourcePackMetadata::ignoredShaders)) .apply(instance, SodiumResourcePackMetadata::new) ); - public static final ResourceMetadataSerializer SERIALIZER = - ResourceMetadataSerializer.fromCodec("sodium", CODEC); + public static final MetadataSectionType SERIALIZER = + MetadataSectionType.fromCodec("sodium", CODEC); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/environment/probe/GraphicsAdapterProbe.java b/src/main/java/me/jellysquid/mods/sodium/client/compatibility/environment/probe/GraphicsAdapterProbe.java index 2aa35e34ba..39d2f97db2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/environment/probe/GraphicsAdapterProbe.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/compatibility/environment/probe/GraphicsAdapterProbe.java @@ -1,9 +1,10 @@ package me.jellysquid.mods.sodium.client.compatibility.environment.probe; -import net.minecraft.util.Util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import oshi.SystemInfo; +import oshi.hardware.GraphicsCard; +import oshi.hardware.HardwareAbstractionLayer; import oshi.util.ExecutingCommand; import java.io.IOException; @@ -12,6 +13,8 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.stream.Stream; +import net.minecraft.Util; public class GraphicsAdapterProbe { private static final Logger LOGGER = LoggerFactory.getLogger("Sodium-GraphicsAdapterProbe"); @@ -23,7 +26,7 @@ public static void findAdapters() { // We rely on separate detection logic for Linux because Oshi fails to find GPUs without // display outputs, and we can also retrieve the driver version for NVIDIA GPUs this way. - var results = Util.getOperatingSystem() == Util.OperatingSystem.LINUX + var results = Util.getPlatform() == Util.OS.LINUX ? findAdaptersLinux() : findAdaptersCrossPlatform(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/workarounds/Workarounds.java b/src/main/java/me/jellysquid/mods/sodium/client/compatibility/workarounds/Workarounds.java index 9e14747383..643b337664 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/workarounds/Workarounds.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/compatibility/workarounds/Workarounds.java @@ -3,7 +3,8 @@ import me.jellysquid.mods.sodium.client.compatibility.environment.probe.GraphicsAdapterInfo; import me.jellysquid.mods.sodium.client.compatibility.environment.probe.GraphicsAdapterProbe; import me.jellysquid.mods.sodium.client.compatibility.environment.probe.GraphicsAdapterVendor; -import net.minecraft.util.Util; +import net.minecraft.Util; +import net.minecraft.Util.OS; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -33,7 +34,7 @@ public static void init() { private static Set findNecessaryWorkarounds() { var workarounds = EnumSet.noneOf(Reference.class); - var operatingSystem = Util.getOperatingSystem(); + var operatingSystem = Util.getPlatform(); var graphicsAdapters = GraphicsAdapterProbe.getAdapters(); @@ -41,7 +42,7 @@ private static Set findNecessaryWorkarounds() { workarounds.add(Reference.NVIDIA_THREADED_OPTIMIZATIONS); } - if (operatingSystem == Util.OperatingSystem.LINUX) { + if (operatingSystem == Util.OS.LINUX) { var session = System.getenv("XDG_SESSION_TYPE"); if (session == null) { @@ -58,8 +59,8 @@ private static Set findNecessaryWorkarounds() { return Collections.unmodifiableSet(workarounds); } - private static boolean isUsingNvidiaGraphicsCard(Util.OperatingSystem operatingSystem, Collection adapters) { - return (operatingSystem == Util.OperatingSystem.WINDOWS || operatingSystem == Util.OperatingSystem.LINUX) && + private static boolean isUsingNvidiaGraphicsCard(Util.OS operatingSystem, Collection adapters) { + return (operatingSystem == Util.OS.WINDOWS || operatingSystem == Util.OS.LINUX) && adapters.stream().anyMatch(adapter -> adapter.vendor() == GraphicsAdapterVendor.NVIDIA); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/workarounds/nvidia/NvidiaDriverVersion.java b/src/main/java/me/jellysquid/mods/sodium/client/compatibility/workarounds/nvidia/NvidiaDriverVersion.java index 1f9c52f56c..ff2c05e95b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/workarounds/nvidia/NvidiaDriverVersion.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/compatibility/workarounds/nvidia/NvidiaDriverVersion.java @@ -5,6 +5,7 @@ import org.jetbrains.annotations.Nullable; import java.util.Objects; +import java.util.regex.Matcher; import java.util.regex.Pattern; public record NvidiaDriverVersion(int major, int minor) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/workarounds/nvidia/NvidiaWorkarounds.java b/src/main/java/me/jellysquid/mods/sodium/client/compatibility/workarounds/nvidia/NvidiaWorkarounds.java index 7522124c52..1e25ae2eb7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/workarounds/nvidia/NvidiaWorkarounds.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/compatibility/workarounds/nvidia/NvidiaWorkarounds.java @@ -2,8 +2,8 @@ import me.jellysquid.mods.sodium.client.platform.unix.Libc; import me.jellysquid.mods.sodium.client.platform.windows.api.Kernel32; +import net.minecraft.Util; import me.jellysquid.mods.sodium.client.platform.windows.WindowsCommandLine; -import net.minecraft.util.Util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -14,7 +14,7 @@ public static void install() { LOGGER.warn("Applying workaround: Prevent the NVIDIA OpenGL driver from using broken optimizations (NVIDIA_THREADED_OPTIMIZATIONS)"); try { - switch (Util.getOperatingSystem()) { + switch (Util.getPlatform()) { case WINDOWS -> { // The NVIDIA drivers rely on parsing the command line arguments to detect Minecraft. If we destroy those, // then it shouldn't be able to detect us anymore. @@ -39,7 +39,7 @@ public static void install() { } public static void uninstall() { - switch (Util.getOperatingSystem()) { + switch (Util.getPlatform()) { case WINDOWS -> { WindowsCommandLine.resetCommandLine(); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/data/fingerprint/FingerprintMeasure.java b/src/main/java/me/jellysquid/mods/sodium/client/data/fingerprint/FingerprintMeasure.java index 4908c491c3..ff4705ad6f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/data/fingerprint/FingerprintMeasure.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/data/fingerprint/FingerprintMeasure.java @@ -1,22 +1,23 @@ package me.jellysquid.mods.sodium.client.data.fingerprint; import net.fabricmc.loader.api.FabricLoader; -import net.minecraft.client.MinecraftClient; +import net.minecraft.client.Minecraft; import org.apache.commons.codec.binary.Hex; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; - import java.nio.charset.StandardCharsets; +import java.nio.file.Path; import java.security.MessageDigest; import java.security.SecureRandom; import java.time.Instant; import java.util.Objects; +import java.util.UUID; public record FingerprintMeasure(@NotNull String uuid, @NotNull String path) { private static final int SALT_LENGTH = 64; public static @Nullable FingerprintMeasure create() { - var uuid = MinecraftClient.getInstance().getSession().getUuidOrNull(); + var uuid = Minecraft.getInstance().getUser().getProfileId(); var path = FabricLoader.getInstance().getGameDir(); if (uuid == null || path == null) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/device/GLRenderDevice.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/device/GLRenderDevice.java index 557dad274b..66a0433934 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/device/GLRenderDevice.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/device/GLRenderDevice.java @@ -7,9 +7,8 @@ import me.jellysquid.mods.sodium.client.gl.sync.GlFence; import me.jellysquid.mods.sodium.client.gl.tessellation.*; import me.jellysquid.mods.sodium.client.gl.util.EnumBitField; -import net.minecraft.client.render.BufferRenderer; import org.lwjgl.opengl.*; - +import com.mojang.blaze3d.vertex.BufferUploader; import java.nio.ByteBuffer; public class GLRenderDevice implements RenderDevice { @@ -35,7 +34,7 @@ public void makeActive() { return; } - BufferRenderer.reset(); + BufferUploader.reset(); this.stateTracker.clear(); this.isActive = true; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/device/MultiDrawBatch.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/device/MultiDrawBatch.java index ca09e06c10..258213beda 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/device/MultiDrawBatch.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/device/MultiDrawBatch.java @@ -3,7 +3,6 @@ import org.lwjgl.PointerBuffer; import org.lwjgl.system.MemoryUtil; import org.lwjgl.system.Pointer; - import java.nio.IntBuffer; /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlProgram.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlProgram.java index 05c582a0ed..a46f41152d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlProgram.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlProgram.java @@ -5,7 +5,7 @@ import me.jellysquid.mods.sodium.client.gl.shader.uniform.GlUniform; import me.jellysquid.mods.sodium.client.gl.shader.uniform.GlUniformBlock; import me.jellysquid.mods.sodium.client.render.chunk.shader.ShaderBindingContext; -import net.minecraft.util.Identifier; +import net.minecraft.resources.ResourceLocation; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.lwjgl.opengl.GL20C; @@ -32,7 +32,7 @@ public T getInterface() { return this.shaderInterface; } - public static Builder builder(Identifier identifier) { + public static Builder builder(ResourceLocation identifier) { return new Builder(identifier); } @@ -75,10 +75,10 @@ public GlUniformBlock bindUniformBlock(String name, int bindingPoint) { } public static class Builder { - private final Identifier name; + private final ResourceLocation name; private final int program; - public Builder(Identifier name) { + public Builder(ResourceLocation name) { this.name = name; this.program = GL20C.glCreateProgram(); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlShader.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlShader.java index 2749370580..2c73d10f2c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlShader.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlShader.java @@ -2,7 +2,7 @@ import com.mojang.blaze3d.platform.GlStateManager; import me.jellysquid.mods.sodium.client.gl.GlObject; -import net.minecraft.util.Identifier; +import net.minecraft.resources.ResourceLocation; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.lwjgl.opengl.GL20C; @@ -13,9 +13,9 @@ public class GlShader extends GlObject { private static final Logger LOGGER = LogManager.getLogger(GlShader.class); - private final Identifier name; + private final ResourceLocation name; - public GlShader(ShaderType type, Identifier name, String src) { + public GlShader(ShaderType type, ResourceLocation name, String src) { this.name = name; int handle = GL20C.glCreateShader(type.id); @@ -37,7 +37,7 @@ public GlShader(ShaderType type, Identifier name, String src) { this.setHandle(handle); } - public Identifier getName() { + public ResourceLocation getName() { return this.name; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderLoader.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderLoader.java index b29bca96d8..6dd27f8458 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderLoader.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderLoader.java @@ -1,11 +1,11 @@ package me.jellysquid.mods.sodium.client.gl.shader; -import net.minecraft.util.Identifier; import org.apache.commons.io.IOUtils; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; +import net.minecraft.resources.ResourceLocation; public class ShaderLoader { /** @@ -18,11 +18,11 @@ public class ShaderLoader { * @param constants A list of constants for shader specialization * @return An OpenGL shader object compiled with the given user defines */ - public static GlShader loadShader(ShaderType type, Identifier name, ShaderConstants constants) { + public static GlShader loadShader(ShaderType type, ResourceLocation name, ShaderConstants constants) { return new GlShader(type, name, ShaderParser.parseShader(getShaderSource(name), constants)); } - public static String getShaderSource(Identifier name) { + public static String getShaderSource(ResourceLocation name) { String path = String.format("/assets/%s/shaders/%s", name.getNamespace(), name.getPath()); try (InputStream in = ShaderLoader.class.getResourceAsStream(path)) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderParser.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderParser.java index 5bf0588672..9bdb7c8a93 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderParser.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderParser.java @@ -1,7 +1,5 @@ package me.jellysquid.mods.sodium.client.gl.shader; -import net.minecraft.util.Identifier; - import java.io.BufferedReader; import java.io.IOException; import java.io.StringReader; @@ -9,6 +7,7 @@ import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; +import net.minecraft.resources.ResourceLocation; public class ShaderParser { public static String parseShader(String src, ShaderConstants constants) { @@ -49,7 +48,7 @@ private static List resolveImport(String line) { String namespace = matcher.group("namespace"); String path = matcher.group("path"); - Identifier identifier = new Identifier(namespace, path); + ResourceLocation identifier = new ResourceLocation(namespace, path); String source = ShaderLoader.getShaderSource(identifier); return ShaderParser.parseShader(source); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java index 8791f32a62..839a6ee5f4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java @@ -1,6 +1,8 @@ package me.jellysquid.mods.sodium.client.gui; import com.google.common.collect.ImmutableList; +import com.mojang.blaze3d.pipeline.RenderTarget; +import com.mojang.blaze3d.platform.Window; import me.jellysquid.mods.sodium.client.gl.arena.staging.MappedStagingBuffer; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; import me.jellysquid.mods.sodium.client.gui.options.*; @@ -12,11 +14,12 @@ import me.jellysquid.mods.sodium.client.gui.options.storage.MinecraftOptionsStorage; import me.jellysquid.mods.sodium.client.gui.options.storage.SodiumOptionsStorage; import me.jellysquid.mods.sodium.client.compatibility.workarounds.Workarounds; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gl.Framebuffer; -import net.minecraft.client.option.*; -import net.minecraft.client.util.Window; -import net.minecraft.text.Text; +import net.minecraft.client.AttackIndicatorStatus; +import net.minecraft.client.CloudStatus; +import net.minecraft.client.GraphicsStatus; +import net.minecraft.client.Minecraft; +import net.minecraft.client.ParticleStatus; +import net.minecraft.network.chat.Component; import org.lwjgl.opengl.GL; import org.lwjgl.opengl.GLCapabilities; @@ -33,190 +36,190 @@ public static OptionPage general() { groups.add(OptionGroup.createBuilder() .add(OptionImpl.createBuilder(int.class, vanillaOpts) - .setName(Text.translatable("options.renderDistance")) - .setTooltip(Text.translatable("sodium.options.view_distance.tooltip")) + .setName(Component.translatable("options.renderDistance")) + .setTooltip(Component.translatable("sodium.options.view_distance.tooltip")) .setControl(option -> new SliderControl(option, 2, 32, 1, ControlValueFormatter.translateVariable("options.chunks"))) - .setBinding((options, value) -> options.getViewDistance().setValue(value), options -> options.getViewDistance().getValue()) + .setBinding((options, value) -> options.renderDistance().set(value), options -> options.renderDistance().get()) .setImpact(OptionImpact.HIGH) .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) .build()) .add(OptionImpl.createBuilder(int.class, vanillaOpts) - .setName(Text.translatable("options.simulationDistance")) - .setTooltip(Text.translatable("sodium.options.simulation_distance.tooltip")) + .setName(Component.translatable("options.simulationDistance")) + .setTooltip(Component.translatable("sodium.options.simulation_distance.tooltip")) .setControl(option -> new SliderControl(option, 5, 32, 1, ControlValueFormatter.translateVariable("options.chunks"))) - .setBinding((options, value) -> options.getSimulationDistance().setValue(value), options -> options.getSimulationDistance().getValue()) + .setBinding((options, value) -> options.simulationDistance().set(value), options -> options.simulationDistance().get()) .setImpact(OptionImpact.HIGH) .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) .build()) .add(OptionImpl.createBuilder(int.class, vanillaOpts) - .setName(Text.translatable("options.gamma")) - .setTooltip(Text.translatable("sodium.options.brightness.tooltip")) + .setName(Component.translatable("options.gamma")) + .setTooltip(Component.translatable("sodium.options.brightness.tooltip")) .setControl(opt -> new SliderControl(opt, 0, 100, 1, ControlValueFormatter.brightness())) - .setBinding((opts, value) -> opts.getGamma().setValue(value * 0.01D), (opts) -> (int) (opts.getGamma().getValue() / 0.01D)) + .setBinding((opts, value) -> opts.gamma().set(value * 0.01D), (opts) -> (int) (opts.gamma().get() / 0.01D)) .build()) .build()); groups.add(OptionGroup.createBuilder() .add(OptionImpl.createBuilder(int.class, vanillaOpts) - .setName(Text.translatable("options.guiScale")) - .setTooltip(Text.translatable("sodium.options.gui_scale.tooltip")) - .setControl(option -> new SliderControl(option, 0, MinecraftClient.getInstance().getWindow().calculateScaleFactor(0, MinecraftClient.getInstance().forcesUnicodeFont()), 1, ControlValueFormatter.guiScale())) + .setName(Component.translatable("options.guiScale")) + .setTooltip(Component.translatable("sodium.options.gui_scale.tooltip")) + .setControl(option -> new SliderControl(option, 0, Minecraft.getInstance().getWindow().calculateScale(0, Minecraft.getInstance().isEnforceUnicode()), 1, ControlValueFormatter.guiScale())) .setBinding((opts, value) -> { - opts.getGuiScale().setValue(value); + opts.guiScale().set(value); - MinecraftClient client = MinecraftClient.getInstance(); - client.onResolutionChanged(); - }, opts -> opts.getGuiScale().getValue()) + Minecraft client = Minecraft.getInstance(); + client.resizeDisplay(); + }, opts -> opts.guiScale().get()) .build()) .add(OptionImpl.createBuilder(boolean.class, vanillaOpts) - .setName(Text.translatable("options.fullscreen")) - .setTooltip(Text.translatable("sodium.options.fullscreen.tooltip")) + .setName(Component.translatable("options.fullscreen")) + .setTooltip(Component.translatable("sodium.options.fullscreen.tooltip")) .setControl(TickBoxControl::new) .setBinding((opts, value) -> { - opts.getFullscreen().setValue(value); + opts.fullscreen().set(value); - MinecraftClient client = MinecraftClient.getInstance(); + Minecraft client = Minecraft.getInstance(); Window window = client.getWindow(); - if (window != null && window.isFullscreen() != opts.getFullscreen().getValue()) { - window.toggleFullscreen(); + if (window != null && window.isFullscreen() != opts.fullscreen().get()) { + window.toggleFullScreen(); // The client might not be able to enter full-screen mode - opts.getFullscreen().setValue(window.isFullscreen()); + opts.fullscreen().set(window.isFullscreen()); } - }, (opts) -> opts.getFullscreen().getValue()) + }, (opts) -> opts.fullscreen().get()) .build()) .add(OptionImpl.createBuilder(boolean.class, vanillaOpts) - .setName(Text.translatable("options.vsync")) - .setTooltip(Text.translatable("sodium.options.v_sync.tooltip")) + .setName(Component.translatable("options.vsync")) + .setTooltip(Component.translatable("sodium.options.v_sync.tooltip")) .setControl(TickBoxControl::new) - .setBinding(new VanillaBooleanOptionBinding(MinecraftClient.getInstance().options.getEnableVsync())) + .setBinding(new VanillaBooleanOptionBinding(Minecraft.getInstance().options.enableVsync())) .setImpact(OptionImpact.VARIES) .build()) .add(OptionImpl.createBuilder(int.class, vanillaOpts) - .setName(Text.translatable("options.framerateLimit")) - .setTooltip(Text.translatable("sodium.options.fps_limit.tooltip")) + .setName(Component.translatable("options.framerateLimit")) + .setTooltip(Component.translatable("sodium.options.fps_limit.tooltip")) .setControl(option -> new SliderControl(option, 10, 260, 10, ControlValueFormatter.fpsLimit())) .setBinding((opts, value) -> { - opts.getMaxFps().setValue(value); - MinecraftClient.getInstance().getWindow().setFramerateLimit(value); - }, opts -> opts.getMaxFps().getValue()) + opts.framerateLimit().set(value); + Minecraft.getInstance().getWindow().setFramerateLimit(value); + }, opts -> opts.framerateLimit().get()) .build()) .build()); groups.add(OptionGroup.createBuilder() .add(OptionImpl.createBuilder(boolean.class, vanillaOpts) - .setName(Text.translatable("options.viewBobbing")) - .setTooltip(Text.translatable("sodium.options.view_bobbing.tooltip")) + .setName(Component.translatable("options.viewBobbing")) + .setTooltip(Component.translatable("sodium.options.view_bobbing.tooltip")) .setControl(TickBoxControl::new) - .setBinding(new VanillaBooleanOptionBinding(MinecraftClient.getInstance().options.getBobView())) + .setBinding(new VanillaBooleanOptionBinding(Minecraft.getInstance().options.bobView())) .build()) - .add(OptionImpl.createBuilder(AttackIndicator.class, vanillaOpts) - .setName(Text.translatable("options.attackIndicator")) - .setTooltip(Text.translatable("sodium.options.attack_indicator.tooltip")) - .setControl(opts -> new CyclingControl<>(opts, AttackIndicator.class, new Text[] { Text.translatable("options.off"), Text.translatable("options.attack.crosshair"), Text.translatable("options.attack.hotbar") })) - .setBinding((opts, value) -> opts.getAttackIndicator().setValue(value), (opts) -> opts.getAttackIndicator().getValue()) + .add(OptionImpl.createBuilder(AttackIndicatorStatus.class, vanillaOpts) + .setName(Component.translatable("options.attackIndicator")) + .setTooltip(Component.translatable("sodium.options.attack_indicator.tooltip")) + .setControl(opts -> new CyclingControl<>(opts, AttackIndicatorStatus.class, new Component[] { Component.translatable("options.off"), Component.translatable("options.attack.crosshair"), Component.translatable("options.attack.hotbar") })) + .setBinding((opts, value) -> opts.attackIndicator().set(value), (opts) -> opts.attackIndicator().get()) .build()) .add(OptionImpl.createBuilder(boolean.class, vanillaOpts) - .setName(Text.translatable("options.autosaveIndicator")) - .setTooltip(Text.translatable("sodium.options.autosave_indicator.tooltip")) + .setName(Component.translatable("options.autosaveIndicator")) + .setTooltip(Component.translatable("sodium.options.autosave_indicator.tooltip")) .setControl(TickBoxControl::new) - .setBinding((opts, value) -> opts.getShowAutosaveIndicator().setValue(value), opts -> opts.getShowAutosaveIndicator().getValue()) + .setBinding((opts, value) -> opts.showAutosaveIndicator().set(value), opts -> opts.showAutosaveIndicator().get()) .build()) .build()); - return new OptionPage(Text.translatable("stat.generalButton"), ImmutableList.copyOf(groups)); + return new OptionPage(Component.translatable("stat.generalButton"), ImmutableList.copyOf(groups)); } public static OptionPage quality() { List groups = new ArrayList<>(); groups.add(OptionGroup.createBuilder() - .add(OptionImpl.createBuilder(GraphicsMode.class, vanillaOpts) - .setName(Text.translatable("options.graphics")) - .setTooltip(Text.translatable("sodium.options.graphics_quality.tooltip")) - .setControl(option -> new CyclingControl<>(option, GraphicsMode.class, new Text[] { Text.translatable("options.graphics.fast"), Text.translatable("options.graphics.fancy"), Text.translatable("options.graphics.fabulous") })) + .add(OptionImpl.createBuilder(GraphicsStatus.class, vanillaOpts) + .setName(Component.translatable("options.graphics")) + .setTooltip(Component.translatable("sodium.options.graphics_quality.tooltip")) + .setControl(option -> new CyclingControl<>(option, GraphicsStatus.class, new Component[] { Component.translatable("options.graphics.fast"), Component.translatable("options.graphics.fancy"), Component.translatable("options.graphics.fabulous") })) .setBinding( - (opts, value) -> opts.getGraphicsMode().setValue(value), - opts -> opts.getGraphicsMode().getValue()) + (opts, value) -> opts.graphicsMode().set(value), + opts -> opts.graphicsMode().get()) .setImpact(OptionImpact.HIGH) .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) .build()) .build()); groups.add(OptionGroup.createBuilder() - .add(OptionImpl.createBuilder(CloudRenderMode.class, vanillaOpts) - .setName(Text.translatable("options.renderClouds")) - .setTooltip(Text.translatable("sodium.options.clouds_quality.tooltip")) - .setControl(option -> new CyclingControl<>(option, CloudRenderMode.class, new Text[] { Text.translatable("options.off"), Text.translatable("options.graphics.fast"), Text.translatable("options.graphics.fancy") })) + .add(OptionImpl.createBuilder(CloudStatus.class, vanillaOpts) + .setName(Component.translatable("options.renderClouds")) + .setTooltip(Component.translatable("sodium.options.clouds_quality.tooltip")) + .setControl(option -> new CyclingControl<>(option, CloudStatus.class, new Component[] { Component.translatable("options.off"), Component.translatable("options.graphics.fast"), Component.translatable("options.graphics.fancy") })) .setBinding((opts, value) -> { - opts.getCloudRenderMode().setValue(value); + opts.cloudStatus().set(value); - if (MinecraftClient.isFabulousGraphicsOrBetter()) { - Framebuffer framebuffer = MinecraftClient.getInstance().worldRenderer.getCloudsFramebuffer(); + if (Minecraft.useShaderTransparency()) { + RenderTarget framebuffer = Minecraft.getInstance().levelRenderer.getCloudsTarget(); if (framebuffer != null) { - framebuffer.clear(MinecraftClient.IS_SYSTEM_MAC); + framebuffer.clear(Minecraft.ON_OSX); } } - }, opts -> opts.getCloudRenderMode().getValue()) + }, opts -> opts.cloudStatus().get()) .setImpact(OptionImpact.LOW) .build()) .add(OptionImpl.createBuilder(SodiumGameOptions.GraphicsQuality.class, sodiumOpts) - .setName(Text.translatable("soundCategory.weather")) - .setTooltip(Text.translatable("sodium.options.weather_quality.tooltip")) + .setName(Component.translatable("soundCategory.weather")) + .setTooltip(Component.translatable("sodium.options.weather_quality.tooltip")) .setControl(option -> new CyclingControl<>(option, SodiumGameOptions.GraphicsQuality.class)) .setBinding((opts, value) -> opts.quality.weatherQuality = value, opts -> opts.quality.weatherQuality) .setImpact(OptionImpact.MEDIUM) .build()) .add(OptionImpl.createBuilder(SodiumGameOptions.GraphicsQuality.class, sodiumOpts) - .setName(Text.translatable("sodium.options.leaves_quality.name")) - .setTooltip(Text.translatable("sodium.options.leaves_quality.tooltip")) + .setName(Component.translatable("sodium.options.leaves_quality.name")) + .setTooltip(Component.translatable("sodium.options.leaves_quality.tooltip")) .setControl(option -> new CyclingControl<>(option, SodiumGameOptions.GraphicsQuality.class)) .setBinding((opts, value) -> opts.quality.leavesQuality = value, opts -> opts.quality.leavesQuality) .setImpact(OptionImpact.MEDIUM) .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) .build()) - .add(OptionImpl.createBuilder(ParticlesMode.class, vanillaOpts) - .setName(Text.translatable("options.particles")) - .setTooltip(Text.translatable("sodium.options.particle_quality.tooltip")) - .setControl(option -> new CyclingControl<>(option, ParticlesMode.class, new Text[] { Text.translatable("options.particles.all"), Text.translatable("options.particles.decreased"), Text.translatable("options.particles.minimal") })) - .setBinding((opts, value) -> opts.getParticles().setValue(value), (opts) -> opts.getParticles().getValue()) + .add(OptionImpl.createBuilder(ParticleStatus.class, vanillaOpts) + .setName(Component.translatable("options.particles")) + .setTooltip(Component.translatable("sodium.options.particle_quality.tooltip")) + .setControl(option -> new CyclingControl<>(option, ParticleStatus.class, new Component[] { Component.translatable("options.particles.all"), Component.translatable("options.particles.decreased"), Component.translatable("options.particles.minimal") })) + .setBinding((opts, value) -> opts.particles().set(value), (opts) -> opts.particles().get()) .setImpact(OptionImpact.MEDIUM) .build()) .add(OptionImpl.createBuilder(boolean.class, vanillaOpts) - .setName(Text.translatable("options.ao")) - .setTooltip(Text.translatable("sodium.options.smooth_lighting.tooltip")) + .setName(Component.translatable("options.ao")) + .setTooltip(Component.translatable("sodium.options.smooth_lighting.tooltip")) .setControl(TickBoxControl::new) - .setBinding((opts, value) -> opts.getAo().setValue(value), opts -> opts.getAo().getValue()) + .setBinding((opts, value) -> opts.ambientOcclusion().set(value), opts -> opts.ambientOcclusion().get()) .setImpact(OptionImpact.LOW) .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) .build()) .add(OptionImpl.createBuilder(int.class, vanillaOpts) - .setName(Text.translatable("options.biomeBlendRadius")) - .setTooltip(Text.translatable("sodium.options.biome_blend.tooltip")) + .setName(Component.translatable("options.biomeBlendRadius")) + .setTooltip(Component.translatable("sodium.options.biome_blend.tooltip")) .setControl(option -> new SliderControl(option, 1, 7, 1, ControlValueFormatter.biomeBlend())) - .setBinding((opts, value) -> opts.getBiomeBlendRadius().setValue(value), opts -> opts.getBiomeBlendRadius().getValue()) + .setBinding((opts, value) -> opts.biomeBlendRadius().set(value), opts -> opts.biomeBlendRadius().get()) .setImpact(OptionImpact.LOW) .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) .build()) .add(OptionImpl.createBuilder(int.class, vanillaOpts) - .setName(Text.translatable("options.entityDistanceScaling")) - .setTooltip(Text.translatable("sodium.options.entity_distance.tooltip")) + .setName(Component.translatable("options.entityDistanceScaling")) + .setTooltip(Component.translatable("sodium.options.entity_distance.tooltip")) .setControl(option -> new SliderControl(option, 50, 500, 25, ControlValueFormatter.percentage())) - .setBinding((opts, value) -> opts.getEntityDistanceScaling().setValue(value / 100.0), opts -> Math.round(opts.getEntityDistanceScaling().getValue().floatValue() * 100.0F)) + .setBinding((opts, value) -> opts.entityDistanceScaling().set(value / 100.0), opts -> Math.round(opts.entityDistanceScaling().get().floatValue() * 100.0F)) .setImpact(OptionImpact.HIGH) .build() ) .add(OptionImpl.createBuilder(boolean.class, vanillaOpts) - .setName(Text.translatable("options.entityShadows")) - .setTooltip(Text.translatable("sodium.options.entity_shadows.tooltip")) + .setName(Component.translatable("options.entityShadows")) + .setTooltip(Component.translatable("sodium.options.entity_shadows.tooltip")) .setControl(TickBoxControl::new) - .setBinding((opts, value) -> opts.getEntityShadows().setValue(value), opts -> opts.getEntityShadows().getValue()) + .setBinding((opts, value) -> opts.entityShadows().set(value), opts -> opts.entityShadows().get()) .setImpact(OptionImpact.MEDIUM) .build()) .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) - .setName(Text.translatable("sodium.options.vignette.name")) - .setTooltip(Text.translatable("sodium.options.vignette.tooltip")) + .setName(Component.translatable("sodium.options.vignette.name")) + .setTooltip(Component.translatable("sodium.options.vignette.tooltip")) .setControl(TickBoxControl::new) .setBinding((opts, value) -> opts.quality.enableVignette = value, opts -> opts.quality.enableVignette) .build()) @@ -225,17 +228,17 @@ public static OptionPage quality() { groups.add(OptionGroup.createBuilder() .add(OptionImpl.createBuilder(int.class, vanillaOpts) - .setName(Text.translatable("options.mipmapLevels")) - .setTooltip(Text.translatable("sodium.options.mipmap_levels.tooltip")) + .setName(Component.translatable("options.mipmapLevels")) + .setTooltip(Component.translatable("sodium.options.mipmap_levels.tooltip")) .setControl(option -> new SliderControl(option, 0, 4, 1, ControlValueFormatter.multiplier())) - .setBinding((opts, value) -> opts.getMipmapLevels().setValue(value), opts -> opts.getMipmapLevels().getValue()) + .setBinding((opts, value) -> opts.mipmapLevels().set(value), opts -> opts.mipmapLevels().get()) .setImpact(OptionImpact.MEDIUM) .setFlags(OptionFlag.REQUIRES_ASSET_RELOAD) .build()) .build()); - return new OptionPage(Text.translatable("sodium.options.pages.quality"), ImmutableList.copyOf(groups)); + return new OptionPage(Component.translatable("sodium.options.pages.quality"), ImmutableList.copyOf(groups)); } public static OptionPage performance() { @@ -243,8 +246,8 @@ public static OptionPage performance() { groups.add(OptionGroup.createBuilder() .add(OptionImpl.createBuilder(int.class, sodiumOpts) - .setName(Text.translatable("sodium.options.chunk_update_threads.name")) - .setTooltip(Text.translatable("sodium.options.chunk_update_threads.tooltip")) + .setName(Component.translatable("sodium.options.chunk_update_threads.name")) + .setTooltip(Component.translatable("sodium.options.chunk_update_threads.tooltip")) .setControl(o -> new SliderControl(o, 0, Runtime.getRuntime().availableProcessors(), 1, ControlValueFormatter.quantityOrDisabled("threads", "Default"))) .setImpact(OptionImpact.HIGH) .setBinding((opts, value) -> opts.performance.chunkBuilderThreads = value, opts -> opts.performance.chunkBuilderThreads) @@ -252,8 +255,8 @@ public static OptionPage performance() { .build() ) .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) - .setName(Text.translatable("sodium.options.always_defer_chunk_updates.name")) - .setTooltip(Text.translatable("sodium.options.always_defer_chunk_updates.tooltip")) + .setName(Component.translatable("sodium.options.always_defer_chunk_updates.name")) + .setTooltip(Component.translatable("sodium.options.always_defer_chunk_updates.tooltip")) .setControl(TickBoxControl::new) .setImpact(OptionImpact.HIGH) .setBinding((opts, value) -> opts.performance.alwaysDeferChunkUpdates = value, opts -> opts.performance.alwaysDeferChunkUpdates) @@ -264,8 +267,8 @@ public static OptionPage performance() { groups.add(OptionGroup.createBuilder() .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) - .setName(Text.translatable("sodium.options.use_block_face_culling.name")) - .setTooltip(Text.translatable("sodium.options.use_block_face_culling.tooltip")) + .setName(Component.translatable("sodium.options.use_block_face_culling.name")) + .setTooltip(Component.translatable("sodium.options.use_block_face_culling.tooltip")) .setControl(TickBoxControl::new) .setImpact(OptionImpact.MEDIUM) .setBinding((opts, value) -> opts.performance.useBlockFaceCulling = value, opts -> opts.performance.useBlockFaceCulling) @@ -273,8 +276,8 @@ public static OptionPage performance() { .build() ) .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) - .setName(Text.translatable("sodium.options.use_fog_occlusion.name")) - .setTooltip(Text.translatable("sodium.options.use_fog_occlusion.tooltip")) + .setName(Component.translatable("sodium.options.use_fog_occlusion.name")) + .setTooltip(Component.translatable("sodium.options.use_fog_occlusion.tooltip")) .setControl(TickBoxControl::new) .setBinding((opts, value) -> opts.performance.useFogOcclusion = value, opts -> opts.performance.useFogOcclusion) .setImpact(OptionImpact.MEDIUM) @@ -282,16 +285,16 @@ public static OptionPage performance() { .build() ) .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) - .setName(Text.translatable("sodium.options.use_entity_culling.name")) - .setTooltip(Text.translatable("sodium.options.use_entity_culling.tooltip")) + .setName(Component.translatable("sodium.options.use_entity_culling.name")) + .setTooltip(Component.translatable("sodium.options.use_entity_culling.tooltip")) .setControl(TickBoxControl::new) .setImpact(OptionImpact.MEDIUM) .setBinding((opts, value) -> opts.performance.useEntityCulling = value, opts -> opts.performance.useEntityCulling) .build() ) .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) - .setName(Text.translatable("sodium.options.animate_only_visible_textures.name")) - .setTooltip(Text.translatable("sodium.options.animate_only_visible_textures.tooltip")) + .setName(Component.translatable("sodium.options.animate_only_visible_textures.name")) + .setTooltip(Component.translatable("sodium.options.animate_only_visible_textures.tooltip")) .setControl(TickBoxControl::new) .setImpact(OptionImpact.HIGH) .setBinding((opts, value) -> opts.performance.animateOnlyVisibleTextures = value, opts -> opts.performance.animateOnlyVisibleTextures) @@ -299,8 +302,8 @@ public static OptionPage performance() { .build() ) .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) - .setName(Text.translatable("sodium.options.use_no_error_context.name")) - .setTooltip(Text.translatable("sodium.options.use_no_error_context.tooltip")) + .setName(Component.translatable("sodium.options.use_no_error_context.name")) + .setTooltip(Component.translatable("sodium.options.use_no_error_context.tooltip")) .setControl(TickBoxControl::new) .setImpact(OptionImpact.LOW) .setBinding((opts, value) -> opts.performance.useNoErrorGLContext = value, opts -> opts.performance.useNoErrorGLContext) @@ -309,7 +312,7 @@ public static OptionPage performance() { .build()) .build()); - return new OptionPage(Text.translatable("sodium.options.pages.performance"), ImmutableList.copyOf(groups)); + return new OptionPage(Component.translatable("sodium.options.pages.performance"), ImmutableList.copyOf(groups)); } private static boolean supportsNoErrorContext() { @@ -323,8 +326,8 @@ public static OptionPage advanced() { groups.add(OptionGroup.createBuilder() .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) - .setName(Text.translatable("sodium.options.use_persistent_mapping.name")) - .setTooltip(Text.translatable("sodium.options.use_persistent_mapping.tooltip")) + .setName(Component.translatable("sodium.options.use_persistent_mapping.name")) + .setTooltip(Component.translatable("sodium.options.use_persistent_mapping.tooltip")) .setControl(TickBoxControl::new) .setImpact(OptionImpact.MEDIUM) .setEnabled(MappedStagingBuffer.isSupported(RenderDevice.INSTANCE)) @@ -336,14 +339,14 @@ public static OptionPage advanced() { groups.add(OptionGroup.createBuilder() .add(OptionImpl.createBuilder(int.class, sodiumOpts) - .setName(Text.translatable("sodium.options.cpu_render_ahead_limit.name")) - .setTooltip(Text.translatable("sodium.options.cpu_render_ahead_limit.tooltip")) + .setName(Component.translatable("sodium.options.cpu_render_ahead_limit.name")) + .setTooltip(Component.translatable("sodium.options.cpu_render_ahead_limit.tooltip")) .setControl(opt -> new SliderControl(opt, 0, 9, 1, ControlValueFormatter.translateVariable("sodium.options.cpu_render_ahead_limit.value"))) .setBinding((opts, value) -> opts.advanced.cpuRenderAheadLimit = value, opts -> opts.advanced.cpuRenderAheadLimit) .build() ) .build()); - return new OptionPage(Text.translatable("sodium.options.pages.advanced"), ImmutableList.copyOf(groups)); + return new OptionPage(Component.translatable("sodium.options.pages.advanced"), ImmutableList.copyOf(groups)); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java index 36f099cff0..1ac5294744 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java @@ -7,9 +7,8 @@ import me.jellysquid.mods.sodium.client.gui.options.TextProvider; import me.jellysquid.mods.sodium.client.util.FileUtil; import net.fabricmc.loader.api.FabricLoader; -import net.minecraft.client.option.GraphicsMode; -import net.minecraft.text.Text; - +import net.minecraft.client.GraphicsStatus; +import net.minecraft.network.chat.Component; import java.io.FileReader; import java.io.IOException; import java.lang.reflect.Modifier; @@ -71,19 +70,19 @@ public enum GraphicsQuality implements TextProvider { FANCY("options.clouds.fancy"), FAST("options.clouds.fast"); - private final Text name; + private final Component name; GraphicsQuality(String name) { - this.name = Text.translatable(name); + this.name = Component.translatable(name); } @Override - public Text getLocalizedName() { + public Component getLocalizedName() { return this.name; } - public boolean isFancy(GraphicsMode graphicsMode) { - return (this == FANCY) || (this == DEFAULT && (graphicsMode == GraphicsMode.FANCY || graphicsMode == GraphicsMode.FABULOUS)); + public boolean isFancy(GraphicsStatus graphicsMode) { + return (this == FANCY) || (this == DEFAULT && (graphicsMode == GraphicsStatus.FANCY || graphicsMode == GraphicsStatus.FABULOUS)); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java index 2f441b160d..b8ea794f82 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java @@ -14,17 +14,17 @@ import me.jellysquid.mods.sodium.client.gui.widgets.FlatButtonWidget; import me.jellysquid.mods.sodium.client.util.Dim2i; import net.fabricmc.loader.api.FabricLoader; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.Element; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.gui.screen.option.VideoOptionsScreen; -import net.minecraft.text.OrderedText; -import net.minecraft.text.StringVisitable; -import net.minecraft.text.Text; -import net.minecraft.util.Formatting; -import net.minecraft.util.Language; -import net.minecraft.util.Util; +import net.minecraft.ChatFormatting; +import net.minecraft.Util; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.VideoSettingsScreen; +import net.minecraft.locale.Language; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.FormattedText; +import net.minecraft.util.FormattedCharSequence; import org.jetbrains.annotations.Nullable; import org.lwjgl.glfw.GLFW; @@ -56,7 +56,7 @@ public class SodiumOptionsGUI extends Screen implements ScreenPromptable { private @Nullable ScreenPrompt prompt; private SodiumOptionsGUI(Screen prevScreen) { - super(Text.literal("Sodium Renderer Settings")); + super(Component.literal("Sodium Renderer Settings")); this.prevScreen = prevScreen; @@ -108,7 +108,7 @@ private void checkPromptTimers() { private void openDonationPrompt(SodiumGameOptions options) { var prompt = new ScreenPrompt(this, DONATION_PROMPT_MESSAGE, 320, 190, - new ScreenPrompt.Action(Text.literal("Buy us a coffee"), this::openDonationPage)); + new ScreenPrompt.Action(Component.literal("Buy us a coffee"), this::openDonationPage)); prompt.setFocused(true); options.notifications.hasSeenDonationPrompt = true; @@ -149,7 +149,7 @@ protected void init() { private void rebuildGUI() { this.controls.clear(); - this.clearChildren(); + this.clearWidgets(); if (this.currentPage == null) { if (this.pages.isEmpty()) { @@ -163,21 +163,21 @@ private void rebuildGUI() { this.rebuildGUIPages(); this.rebuildGUIOptions(); - this.undoButton = new FlatButtonWidget(new Dim2i(this.width - 211, this.height - 30, 65, 20), Text.translatable("sodium.options.buttons.undo"), this::undoChanges); - this.applyButton = new FlatButtonWidget(new Dim2i(this.width - 142, this.height - 30, 65, 20), Text.translatable("sodium.options.buttons.apply"), this::applyChanges); - this.closeButton = new FlatButtonWidget(new Dim2i(this.width - 73, this.height - 30, 65, 20), Text.translatable("gui.done"), this::close); - this.donateButton = new FlatButtonWidget(new Dim2i(this.width - 128, 6, 100, 20), Text.translatable("sodium.options.buttons.donate"), this::openDonationPage); - this.hideDonateButton = new FlatButtonWidget(new Dim2i(this.width - 26, 6, 20, 20), Text.literal("x"), this::hideDonationButton); + this.undoButton = new FlatButtonWidget(new Dim2i(this.width - 211, this.height - 30, 65, 20), Component.translatable("sodium.options.buttons.undo"), this::undoChanges); + this.applyButton = new FlatButtonWidget(new Dim2i(this.width - 142, this.height - 30, 65, 20), Component.translatable("sodium.options.buttons.apply"), this::applyChanges); + this.closeButton = new FlatButtonWidget(new Dim2i(this.width - 73, this.height - 30, 65, 20), Component.translatable("gui.done"), this::onClose); + this.donateButton = new FlatButtonWidget(new Dim2i(this.width - 128, 6, 100, 20), Component.translatable("sodium.options.buttons.donate"), this::openDonationPage); + this.hideDonateButton = new FlatButtonWidget(new Dim2i(this.width - 26, 6, 20, 20), Component.literal("x"), this::hideDonationButton); if (SodiumClientMod.options().notifications.hasClearedDonationButton) { this.setDonationButtonVisibility(false); } - this.addDrawableChild(this.undoButton); - this.addDrawableChild(this.applyButton); - this.addDrawableChild(this.closeButton); - this.addDrawableChild(this.donateButton); - this.addDrawableChild(this.hideDonateButton); + this.addRenderableWidget(this.undoButton); + this.addRenderableWidget(this.applyButton); + this.addRenderableWidget(this.closeButton); + this.addRenderableWidget(this.donateButton); + this.addRenderableWidget(this.hideDonateButton); } private void setDonationButtonVisibility(boolean value) { @@ -203,14 +203,14 @@ private void rebuildGUIPages() { int y = 6; for (OptionPage page : this.pages) { - int width = 12 + this.textRenderer.getWidth(page.getName()); + int width = 12 + this.font.width(page.getName()); FlatButtonWidget button = new FlatButtonWidget(new Dim2i(x, y, width, 18), page.getName(), () -> this.setPage(page)); button.setSelected(this.currentPage == page); x += width + 6; - this.addDrawableChild(button); + this.addRenderableWidget(button); } } @@ -224,7 +224,7 @@ private void rebuildGUIOptions() { Control control = option.getControl(); ControlElement element = control.createElement(new Dim2i(x, y, 200, 18)); - this.addDrawableChild(element); + this.addRenderableWidget(element); this.controls.add(element); @@ -238,7 +238,7 @@ private void rebuildGUIOptions() { } @Override - public void render(DrawContext drawContext, int mouseX, int mouseY, float delta) { + public void render(GuiGraphics drawContext, int mouseX, int mouseY, float delta) { this.updateControls(); super.render(drawContext, this.prompt != null ? -1 : mouseX, this.prompt != null ? -1 : mouseY, delta); @@ -289,7 +289,7 @@ private Stream> getActiveControls() { return this.controls.stream(); } - private void renderOptionTooltip(DrawContext drawContext, ControlElement element) { + private void renderOptionTooltip(GuiGraphics drawContext, ControlElement element) { Dim2i dim = element.getDimensions(); int textPadding = 3; @@ -301,12 +301,12 @@ private void renderOptionTooltip(DrawContext drawContext, ControlElement elem int boxX = dim.getLimitX() + boxPadding; Option option = element.getOption(); - List tooltip = new ArrayList<>(this.textRenderer.wrapLines(option.getTooltip(), boxWidth - (textPadding * 2))); + List tooltip = new ArrayList<>(this.font.split(option.getTooltip(), boxWidth - (textPadding * 2))); OptionImpact impact = option.getImpact(); if (impact != null) { - tooltip.add(Language.getInstance().reorder(Text.translatable("sodium.options.performance_impact_string", impact.getLocalizedName()).formatted(Formatting.GRAY))); + tooltip.add(Language.getInstance().getVisualOrder(Component.translatable("sodium.options.performance_impact_string", impact.getLocalizedName()).withStyle(ChatFormatting.GRAY))); } int boxHeight = (tooltip.size() * 12) + boxPadding; @@ -321,7 +321,7 @@ private void renderOptionTooltip(DrawContext drawContext, ControlElement elem drawContext.fillGradient(boxX, boxY, boxX + boxWidth, boxY + boxHeight, 0xE0000000, 0xE0000000); for (int i = 0; i < tooltip.size(); i++) { - drawContext.drawTextWithShadow(this.textRenderer, tooltip.get(i), boxX + textPadding, boxY + textPadding + (i * 12), 0xFFFFFFFF); + drawContext.drawString(this.font, tooltip.get(i), boxX + textPadding, boxY + textPadding + (i * 12), 0xFFFFFFFF); } } @@ -340,24 +340,24 @@ private void applyChanges() { dirtyStorages.add(option.getStorage()); })); - MinecraftClient client = MinecraftClient.getInstance(); + Minecraft client = Minecraft.getInstance(); - if (client.world != null) { + if (client.level != null) { if (flags.contains(OptionFlag.REQUIRES_RENDERER_RELOAD)) { - client.worldRenderer.reload(); + client.levelRenderer.allChanged(); } else if (flags.contains(OptionFlag.REQUIRES_RENDERER_UPDATE)) { - client.worldRenderer.scheduleTerrainUpdate(); + client.levelRenderer.needsUpdate(); } } if (flags.contains(OptionFlag.REQUIRES_ASSET_RELOAD)) { - client.setMipmapLevels(client.options.getMipmapLevels().getValue()); - client.reloadResourcesConcurrently(); + client.updateMaxMipLevel(client.options.mipmapLevels().get()); + client.delayTextureReload(); } if (flags.contains(OptionFlag.REQUIRES_GAME_RESTART)) { Console.instance().logMessage(MessageLevel.WARN, - Text.translatable("sodium.console.game_restart"), 10.0); + Component.translatable("sodium.console.game_restart"), 10.0); } for (OptionStorage storage : dirtyStorages) { @@ -371,8 +371,8 @@ private void undoChanges() { } private void openDonationPage() { - Util.getOperatingSystem() - .open("https://caffeinemc.net/donate"); + Util.getPlatform() + .openUri("https://caffeinemc.net/donate"); } @Override @@ -382,7 +382,7 @@ public boolean keyPressed(int keyCode, int scanCode, int modifiers) { } if (this.prompt == null && keyCode == GLFW.GLFW_KEY_P && (modifiers & GLFW.GLFW_MOD_SHIFT) != 0) { - MinecraftClient.getInstance().setScreen(new VideoOptionsScreen(this.prevScreen, MinecraftClient.getInstance().options)); + Minecraft.getInstance().setScreen(new VideoSettingsScreen(this.prevScreen, Minecraft.getInstance().options)); return true; } @@ -412,12 +412,12 @@ public boolean shouldCloseOnEsc() { } @Override - public void close() { - this.client.setScreen(this.prevScreen); + public void onClose() { + this.minecraft.setScreen(this.prevScreen); } @Override - public List children() { + public List children() { return this.prompt == null ? super.children() : this.prompt.getWidgets(); } @@ -437,15 +437,15 @@ public Dim2i getDimensions() { return new Dim2i(0, 0, this.width, this.height); } - private static final List DONATION_PROMPT_MESSAGE; + private static final List DONATION_PROMPT_MESSAGE; static { DONATION_PROMPT_MESSAGE = List.of( - StringVisitable.concat(Text.literal("Hello!")), - StringVisitable.concat(Text.literal("It seems that you've been enjoying "), Text.literal("Sodium").withColor(0x27eb92), Text.literal(", the free and open-source optimization mod for Minecraft.")), - StringVisitable.concat(Text.literal("Mods like these are complex. They require "), Text.literal("thousands of hours").withColor(0xff6e00), Text.literal(" of development, debugging, and tuning to create the experience that players have come to expect.")), - StringVisitable.concat(Text.literal("If you'd like to show your token of appreciation, and support the development of our mod in the process, then consider "), Text.literal("buying us a coffee").withColor(0xed49ce), Text.literal(".")), - StringVisitable.concat(Text.literal("And thanks again for using our mod! We hope it helps you (and your computer.)")) + FormattedText.composite(Component.literal("Hello!")), + FormattedText.composite(Component.literal("It seems that you've been enjoying "), Component.literal("Sodium").withColor(0x27eb92), Component.literal(", the free and open-source optimization mod for Minecraft.")), + FormattedText.composite(Component.literal("Mods like these are complex. They require "), Component.literal("thousands of hours").withColor(0xff6e00), Component.literal(" of development, debugging, and tuning to create the experience that players have come to expect.")), + FormattedText.composite(Component.literal("If you'd like to show your token of appreciation, and support the development of our mod in the process, then consider "), Component.literal("buying us a coffee").withColor(0xed49ce), Component.literal(".")), + FormattedText.composite(Component.literal("And thanks again for using our mod! We hope it helps you (and your computer.)")) ); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/console/Console.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/console/Console.java index 2cca2ff333..72cdaf6543 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/console/Console.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/console/Console.java @@ -2,7 +2,7 @@ import me.jellysquid.mods.sodium.client.gui.console.message.Message; import me.jellysquid.mods.sodium.client.gui.console.message.MessageLevel; -import net.minecraft.text.Text; +import net.minecraft.network.chat.Component; import org.apache.commons.lang3.Validate; import org.jetbrains.annotations.NotNull; @@ -15,7 +15,7 @@ public class Console implements ConsoleSink { private final ArrayDeque messages = new ArrayDeque<>(); @Override - public void logMessage(@NotNull MessageLevel level, @NotNull Text text, double duration) { + public void logMessage(@NotNull MessageLevel level, @NotNull Component text, double duration) { Validate.notNull(level); Validate.notNull(text); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/console/ConsoleHooks.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/console/ConsoleHooks.java index d415e9d6d6..587e1dd3bd 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/console/ConsoleHooks.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/console/ConsoleHooks.java @@ -1,9 +1,9 @@ package me.jellysquid.mods.sodium.client.gui.console; -import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.GuiGraphics; public class ConsoleHooks { - public static void render(DrawContext drawContext, double currentTime) { + public static void render(GuiGraphics drawContext, double currentTime) { ConsoleRenderer.INSTANCE.update(Console.INSTANCE, currentTime); ConsoleRenderer.INSTANCE.draw(drawContext); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/console/ConsoleRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/console/ConsoleRenderer.java index ca220078e6..fedd7c1df0 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/console/ConsoleRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/console/ConsoleRenderer.java @@ -4,17 +4,19 @@ import me.jellysquid.mods.sodium.client.gui.console.message.MessageLevel; import net.caffeinemc.mods.sodium.api.util.ColorARGB; import net.caffeinemc.mods.sodium.api.util.ColorU8; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.font.TextHandler; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.text.OrderedText; -import net.minecraft.text.Style; -import net.minecraft.text.Text; -import net.minecraft.util.Language; -import net.minecraft.util.math.MathHelper; +import net.minecraft.client.Minecraft; +import net.minecraft.client.StringSplitter; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.locale.Language; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.network.chat.Style; +import net.minecraft.util.FormattedCharSequence; +import net.minecraft.util.Mth; import org.lwjgl.glfw.GLFW; - +import com.mojang.blaze3d.vertex.PoseStack; import java.util.ArrayList; +import java.util.Deque; import java.util.EnumMap; import java.util.LinkedList; import java.util.List; @@ -43,13 +45,13 @@ private void pollMessages(Console console, double currentTime) { } } - public void draw(DrawContext context) { + public void draw(GuiGraphics context) { var currentTime = GLFW.glfwGetTime(); - MinecraftClient client = MinecraftClient.getInstance(); + Minecraft client = Minecraft.getInstance(); - var matrices = context.getMatrices(); - matrices.push(); + var matrices = context.pose(); + matrices.pushPose(); matrices.translate(0.0f, 0.0f, 1000.0f); @@ -69,16 +71,16 @@ public void draw(DrawContext context) { continue; } - List lines = new ArrayList<>(); + List lines = new ArrayList<>(); var messageWidth = 270; - TextHandler textHandler = client.textRenderer.getTextHandler(); - textHandler.wrapLines(message.text(), messageWidth - 20, Style.EMPTY, (text, lastLineWrapped) -> { - lines.add(Language.getInstance().reorder(text)); + StringSplitter textHandler = client.font.getSplitter(); + textHandler.splitLines(message.text(), messageWidth - 20, Style.EMPTY, (text, lastLineWrapped) -> { + lines.add(Language.getInstance().getVisualOrder(text)); }); - var messageHeight = (client.textRenderer.fontHeight * lines.size()) + (paddingHeight * 2); + var messageHeight = (client.font.lineHeight * lines.size()) + (paddingHeight * 2); renders.add(new MessageRender(x, y, messageWidth, messageHeight, message.level(), lines, opacity)); @@ -86,8 +88,8 @@ public void draw(DrawContext context) { } } - var mouseX = client.mouse.getX() / client.getWindow().getScaleFactor(); - var mouseY = client.mouse.getY() / client.getWindow().getScaleFactor(); + var mouseX = client.mouseHandler.xpos() / client.getWindow().getGuiScale(); + var mouseY = client.mouseHandler.ypos() / client.getWindow().getGuiScale(); boolean hovered = false; @@ -122,14 +124,14 @@ public void draw(DrawContext context) { for (var line : render.lines()) { // message text - context.drawText(client.textRenderer, line, x + paddingWidth + 3, y + paddingHeight, + context.drawString(client.font, line, x + paddingWidth + 3, y + paddingHeight, ColorARGB.withAlpha(colors.text(), weightAlpha(opacity)), false); - y += client.textRenderer.fontHeight; + y += client.font.lineHeight; } } - matrices.pop(); + matrices.popPose(); } private static double getMessageOpacity(ActiveMessage message, double time) { @@ -164,19 +166,19 @@ private static double getFadeOutOpacity(ActiveMessage message, double time) { } private static double getAnimationProgress(double currentTime, double startTime, double endTime) { - return MathHelper.clamp(MathHelper.getLerpProgress(currentTime, startTime, endTime), 0.0D, 1.0D); + return Mth.clamp(Mth.inverseLerp(currentTime, startTime, endTime), 0.0D, 1.0D); } private static int weightAlpha(double scale) { return ColorU8.normalizedFloatToByte((float) scale); } - private record ActiveMessage(MessageLevel level, Text text, double duration, double timestamp) { + private record ActiveMessage(MessageLevel level, Component text, double duration, double timestamp) { public static ActiveMessage create(Message message, double timestamp) { var text = message.text() .copy() - .styled((style) -> style.withFont(MinecraftClient.UNICODE_FONT_ID)); + .withStyle((style) -> style.withFont(Minecraft.UNIFORM_FONT)); return new ActiveMessage(message.level(), text, message.duration(), timestamp); } @@ -208,7 +210,7 @@ private record ColorPalette(int text, int background, int foreground) { } - private record MessageRender(int x, int y, int width, int height, MessageLevel level, List lines, double opacity) { + private record MessageRender(int x, int y, int width, int height, MessageLevel level, List lines, double opacity) { } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/console/ConsoleSink.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/console/ConsoleSink.java index 923e50360c..758b4e7b08 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/console/ConsoleSink.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/console/ConsoleSink.java @@ -1,9 +1,9 @@ package me.jellysquid.mods.sodium.client.gui.console; import me.jellysquid.mods.sodium.client.gui.console.message.MessageLevel; -import net.minecraft.text.Text; +import net.minecraft.network.chat.Component; import org.jetbrains.annotations.NotNull; public interface ConsoleSink { - void logMessage(@NotNull MessageLevel level, @NotNull Text text, double duration); + void logMessage(@NotNull MessageLevel level, @NotNull Component text, double duration); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/console/message/Message.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/console/message/Message.java index 7e00cbca0a..f1f45f5494 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/console/message/Message.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/console/message/Message.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.gui.console.message; -import net.minecraft.text.Text; +import net.minecraft.network.chat.Component; -public record Message(MessageLevel level, Text text, double duration) { +public record Message(MessageLevel level, Component text, double duration) { } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/Option.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/Option.java index 1a0118f8e6..4eb9ac86ea 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/Option.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/Option.java @@ -2,14 +2,13 @@ import me.jellysquid.mods.sodium.client.gui.options.control.Control; import me.jellysquid.mods.sodium.client.gui.options.storage.OptionStorage; -import net.minecraft.text.Text; - +import net.minecraft.network.chat.Component; import java.util.Collection; public interface Option { - Text getName(); + Component getName(); - Text getTooltip(); + Component getTooltip(); OptionImpact getImpact(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpact.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpact.java index 7d0f93b6e8..693e6e6fca 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpact.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpact.java @@ -1,22 +1,22 @@ package me.jellysquid.mods.sodium.client.gui.options; -import net.minecraft.text.Text; -import net.minecraft.util.Formatting; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; public enum OptionImpact implements TextProvider { - LOW(Formatting.GREEN, "sodium.option_impact.low"), - MEDIUM(Formatting.YELLOW, "sodium.option_impact.medium"), - HIGH(Formatting.GOLD, "sodium.option_impact.high"), - VARIES(Formatting.WHITE, "sodium.option_impact.varies"); + LOW(ChatFormatting.GREEN, "sodium.option_impact.low"), + MEDIUM(ChatFormatting.YELLOW, "sodium.option_impact.medium"), + HIGH(ChatFormatting.GOLD, "sodium.option_impact.high"), + VARIES(ChatFormatting.WHITE, "sodium.option_impact.varies"); - private final Text text; + private final Component text; - OptionImpact(Formatting color, String text) { - this.text = Text.translatable(text).formatted(color); + OptionImpact(ChatFormatting color, String text) { + this.text = Component.translatable(text).withStyle(color); } @Override - public Text getLocalizedName() { + public Component getLocalizedName() { return this.text; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpl.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpl.java index 95ad50b433..7fd6a654de 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpl.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpl.java @@ -4,7 +4,7 @@ import me.jellysquid.mods.sodium.client.gui.options.binding.OptionBinding; import me.jellysquid.mods.sodium.client.gui.options.control.Control; import me.jellysquid.mods.sodium.client.gui.options.storage.OptionStorage; -import net.minecraft.text.Text; +import net.minecraft.network.chat.Component; import org.apache.commons.lang3.Validate; import java.util.Collection; @@ -21,8 +21,8 @@ public class OptionImpl implements Option { private final EnumSet flags; - private final Text name; - private final Text tooltip; + private final Component name; + private final Component tooltip; private final OptionImpact impact; @@ -32,8 +32,8 @@ public class OptionImpl implements Option { private final boolean enabled; private OptionImpl(OptionStorage storage, - Text name, - Text tooltip, + Component name, + Component tooltip, OptionBinding binding, Function, Control> control, EnumSet flags, @@ -52,12 +52,12 @@ private OptionImpl(OptionStorage storage, } @Override - public Text getName() { + public Component getName() { return this.name; } @Override - public Text getTooltip() { + public Component getTooltip() { return this.tooltip; } @@ -119,8 +119,8 @@ public static OptionImpl.Builder createBuilder(@SuppressWarnings("u public static class Builder { private final OptionStorage storage; - private Text name; - private Text tooltip; + private Component name; + private Component tooltip; private OptionBinding binding; private Function, Control> control; private OptionImpact impact; @@ -131,7 +131,7 @@ private Builder(OptionStorage storage) { this.storage = storage; } - public Builder setName(Text name) { + public Builder setName(Component name) { Validate.notNull(name, "Argument must not be null"); this.name = name; @@ -139,7 +139,7 @@ public Builder setName(Text name) { return this; } - public Builder setTooltip(Text tooltip) { + public Builder setTooltip(Component tooltip) { Validate.notNull(tooltip, "Argument must not be null"); this.tooltip = tooltip; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionPage.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionPage.java index 2aa185e35c..0baaceee6b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionPage.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionPage.java @@ -1,14 +1,14 @@ package me.jellysquid.mods.sodium.client.gui.options; import com.google.common.collect.ImmutableList; -import net.minecraft.text.Text; +import net.minecraft.network.chat.Component; public class OptionPage { - private final Text name; + private final Component name; private final ImmutableList groups; private final ImmutableList> options; - public OptionPage(Text name, ImmutableList groups) { + public OptionPage(Component name, ImmutableList groups) { this.name = name; this.groups = groups; @@ -29,7 +29,7 @@ public ImmutableList> getOptions() { return this.options; } - public Text getName() { + public Component getName() { return this.name; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/TextProvider.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/TextProvider.java index adb85defce..9f438c2709 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/TextProvider.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/TextProvider.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.gui.options; -import net.minecraft.text.Text; +import net.minecraft.network.chat.Component; public interface TextProvider { - Text getLocalizedName(); + Component getLocalizedName(); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/compat/VanillaBooleanOptionBinding.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/compat/VanillaBooleanOptionBinding.java index 5ebea886d1..c78dec6c02 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/compat/VanillaBooleanOptionBinding.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/compat/VanillaBooleanOptionBinding.java @@ -1,23 +1,23 @@ package me.jellysquid.mods.sodium.client.gui.options.binding.compat; import me.jellysquid.mods.sodium.client.gui.options.binding.OptionBinding; -import net.minecraft.client.option.GameOptions; -import net.minecraft.client.option.SimpleOption; +import net.minecraft.client.OptionInstance; +import net.minecraft.client.Options; -public class VanillaBooleanOptionBinding implements OptionBinding { - private final SimpleOption option; +public class VanillaBooleanOptionBinding implements OptionBinding { + private final OptionInstance option; - public VanillaBooleanOptionBinding(SimpleOption option) { + public VanillaBooleanOptionBinding(OptionInstance option) { this.option = option; } @Override - public void setValue(GameOptions storage, Boolean value) { - this.option.setValue(value); + public void setValue(Options storage, Boolean value) { + this.option.set(value); } @Override - public Boolean getValue(GameOptions storage) { - return this.option.getValue(); + public Boolean getValue(Options storage) { + return this.option.get(); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlElement.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlElement.java index cd0ed26ea5..c6336be1b6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlElement.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlElement.java @@ -3,11 +3,11 @@ import me.jellysquid.mods.sodium.client.gui.options.Option; import me.jellysquid.mods.sodium.client.gui.widgets.AbstractWidget; import me.jellysquid.mods.sodium.client.util.Dim2i; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.ScreenRect; -import net.minecraft.client.gui.navigation.GuiNavigation; -import net.minecraft.client.gui.navigation.GuiNavigationPath; -import net.minecraft.util.Formatting; +import net.minecraft.ChatFormatting; +import net.minecraft.client.gui.ComponentPath; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.navigation.FocusNavigationEvent; +import net.minecraft.client.gui.navigation.ScreenRectangle; import org.jetbrains.annotations.Nullable; public class ControlElement extends AbstractWidget { @@ -21,22 +21,22 @@ public ControlElement(Option option, Dim2i dim) { } @Override - public void render(DrawContext drawContext, int mouseX, int mouseY, float delta) { + public void render(GuiGraphics drawContext, int mouseX, int mouseY, float delta) { String name = this.option.getName().getString(); String label; - if ((this.hovered || this.isFocused()) && this.font.getWidth(name) > (this.dim.width() - this.option.getControl().getMaxWidth())) { + if ((this.hovered || this.isFocused()) && this.font.width(name) > (this.dim.width() - this.option.getControl().getMaxWidth())) { name = name.substring(0, Math.min(name.length(), 10)) + "..."; } if (this.option.isAvailable()) { if (this.option.hasChanged()) { - label = Formatting.ITALIC + name + " *"; + label = ChatFormatting.ITALIC + name + " *"; } else { - label = Formatting.WHITE + name; + label = ChatFormatting.WHITE + name; } } else { - label = String.valueOf(Formatting.GRAY) + Formatting.STRIKETHROUGH + name; + label = String.valueOf(ChatFormatting.GRAY) + ChatFormatting.STRIKETHROUGH + name; } this.hovered = this.dim.containsCursor(mouseX, mouseY); @@ -58,14 +58,14 @@ public Dim2i getDimensions() { } @Override - public @Nullable GuiNavigationPath getNavigationPath(GuiNavigation navigation) { + public @Nullable ComponentPath nextFocusPath(FocusNavigationEvent navigation) { if (!this.option.isAvailable()) return null; - return super.getNavigationPath(navigation); + return super.nextFocusPath(navigation); } @Override - public ScreenRect getNavigationFocus() { - return new ScreenRect(this.dim.x(), this.dim.y(), this.dim.width(), this.dim.height()); + public ScreenRectangle getRectangle() { + return new ScreenRectangle(this.dim.x(), this.dim.y(), this.dim.width(), this.dim.height()); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlValueFormatter.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlValueFormatter.java index 1811ca105e..4ee1d8f683 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlValueFormatter.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlValueFormatter.java @@ -1,51 +1,51 @@ package me.jellysquid.mods.sodium.client.gui.options.control; -import net.minecraft.text.Text; +import net.minecraft.network.chat.Component; public interface ControlValueFormatter { static ControlValueFormatter guiScale() { - return (v) -> (v == 0) ? Text.translatable("options.guiScale.auto") : Text.literal(v + "x"); + return (v) -> (v == 0) ? Component.translatable("options.guiScale.auto") : Component.literal(v + "x"); } static ControlValueFormatter fpsLimit() { - return (v) -> (v == 260) ? Text.translatable("options.framerateLimit.max") : Text.translatable("options.framerate", v); + return (v) -> (v == 260) ? Component.translatable("options.framerateLimit.max") : Component.translatable("options.framerate", v); } static ControlValueFormatter brightness() { return (v) -> { if (v == 0) { - return Text.translatable("options.gamma.min"); + return Component.translatable("options.gamma.min"); } else if (v == 100) { - return Text.translatable("options.gamma.max"); + return Component.translatable("options.gamma.max"); } else { - return Text.literal(v + "%"); + return Component.literal(v + "%"); } }; } static ControlValueFormatter biomeBlend() { - return (v) -> (v == 0) ? Text.translatable("gui.none") : Text.translatable("sodium.options.biome_blend.value", v); + return (v) -> (v == 0) ? Component.translatable("gui.none") : Component.translatable("sodium.options.biome_blend.value", v); } - Text format(int value); + Component format(int value); static ControlValueFormatter translateVariable(String key) { - return (v) -> Text.translatable(key, v); + return (v) -> Component.translatable(key, v); } static ControlValueFormatter percentage() { - return (v) -> Text.literal(v + "%"); + return (v) -> Component.literal(v + "%"); } static ControlValueFormatter multiplier() { - return (v) -> Text.literal(v + "x"); + return (v) -> Component.literal(v + "x"); } static ControlValueFormatter quantityOrDisabled(String name, String disableText) { - return (v) -> Text.literal(v == 0 ? disableText : v + " " + name); + return (v) -> Component.literal(v == 0 ? disableText : v + " " + name); } static ControlValueFormatter number() { - return (v) -> Text.literal(String.valueOf(v)); + return (v) -> Component.literal(String.valueOf(v)); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/CyclingControl.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/CyclingControl.java index 06825cde9b..db9bcc37ed 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/CyclingControl.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/CyclingControl.java @@ -3,23 +3,22 @@ import me.jellysquid.mods.sodium.client.gui.options.Option; import me.jellysquid.mods.sodium.client.gui.options.TextProvider; import me.jellysquid.mods.sodium.client.util.Dim2i; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.input.KeyCodes; -import net.minecraft.client.util.InputUtil; -import net.minecraft.text.Text; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.navigation.CommonInputs; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; import org.apache.commons.lang3.Validate; public class CyclingControl> implements Control { private final Option option; private final T[] allowedValues; - private final Text[] names; + private final Component[] names; public CyclingControl(Option option, Class enumType) { this(option, enumType, enumType.getEnumConstants()); } - public CyclingControl(Option option, Class enumType, Text[] names) { + public CyclingControl(Option option, Class enumType, Component[] names) { T[] universe = enumType.getEnumConstants(); Validate.isTrue(universe.length == names.length, "Mismatch between universe length and names array length"); @@ -35,16 +34,16 @@ public CyclingControl(Option option, Class enumType, T[] allowedValues) { this.option = option; this.allowedValues = allowedValues; - this.names = new Text[universe.length]; + this.names = new Component[universe.length]; for (int i = 0; i < this.names.length; i++) { - Text name; + Component name; T value = universe[i]; if (value instanceof TextProvider) { name = ((TextProvider) value).getLocalizedName(); } else { - name = Text.literal(value.name()); + name = Component.literal(value.name()); } this.names[i] = name; @@ -68,10 +67,10 @@ public int getMaxWidth() { private static class CyclingControlElement> extends ControlElement { private final T[] allowedValues; - private final Text[] names; + private final Component[] names; private int currentIndex; - public CyclingControlElement(Option option, Dim2i dim, T[] allowedValues, Text[] names) { + public CyclingControlElement(Option option, Dim2i dim, T[] allowedValues, Component[] names) { super(option, dim); this.allowedValues = allowedValues; @@ -87,11 +86,11 @@ public CyclingControlElement(Option option, Dim2i dim, T[] allowedValues, Tex } @Override - public void render(DrawContext drawContext, int mouseX, int mouseY, float delta) { + public void render(GuiGraphics drawContext, int mouseX, int mouseY, float delta) { super.render(drawContext, mouseX, mouseY, delta); Enum value = this.option.getValue(); - Text name = this.names[value.ordinal()]; + Component name = this.names[value.ordinal()]; int strWidth = this.getStringWidth(name); this.drawString(drawContext, name, this.dim.getLimitX() - strWidth - 6, this.dim.getCenterY() - 4, 0xFFFFFFFF); @@ -113,7 +112,7 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { public boolean keyPressed(int keyCode, int scanCode, int modifiers) { if (!isFocused()) return false; - if (KeyCodes.isToggle(keyCode)) { + if (CommonInputs.selected(keyCode)) { cycleControl(Screen.hasShiftDown()); return true; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/SliderControl.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/SliderControl.java index 99e496ab47..f8ded9a65f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/SliderControl.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/SliderControl.java @@ -1,12 +1,12 @@ package me.jellysquid.mods.sodium.client.gui.options.control; +import com.mojang.blaze3d.platform.InputConstants; import me.jellysquid.mods.sodium.client.gui.options.Option; import me.jellysquid.mods.sodium.client.util.Dim2i; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.util.InputUtil; -import net.minecraft.client.util.math.Rect2i; -import net.minecraft.text.Text; -import net.minecraft.util.math.MathHelper; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.renderer.Rect2i; +import net.minecraft.network.chat.Component; +import net.minecraft.util.Mth; import org.apache.commons.lang3.Validate; public class SliderControl implements Control { @@ -74,7 +74,7 @@ public Button(Option option, Dim2i dim, int min, int max, int interval, } @Override - public void render(DrawContext drawContext, int mouseX, int mouseY, float delta) { + public void render(GuiGraphics drawContext, int mouseX, int mouseY, float delta) { super.render(drawContext, mouseX, mouseY, delta); if (this.option.isAvailable() && (this.hovered || this.isFocused())) { @@ -84,19 +84,19 @@ public void render(DrawContext drawContext, int mouseX, int mouseY, float delta) } } - private void renderStandaloneValue(DrawContext drawContext) { + private void renderStandaloneValue(GuiGraphics drawContext) { int sliderX = this.sliderBounds.getX(); int sliderY = this.sliderBounds.getY(); int sliderWidth = this.sliderBounds.getWidth(); int sliderHeight = this.sliderBounds.getHeight(); - Text label = this.formatter.format(this.option.getValue()); - int labelWidth = this.font.getWidth(label); + Component label = this.formatter.format(this.option.getValue()); + int labelWidth = this.font.width(label); this.drawString(drawContext, label, sliderX + sliderWidth - labelWidth, sliderY + (sliderHeight / 2) - 4, 0xFFFFFFFF); } - private void renderSlider(DrawContext drawContext) { + private void renderSlider(GuiGraphics drawContext) { int sliderX = this.sliderBounds.getX(); int sliderY = this.sliderBounds.getY(); int sliderWidth = this.sliderBounds.getWidth(); @@ -104,7 +104,7 @@ private void renderSlider(DrawContext drawContext) { this.thumbPosition = this.getThumbPositionForValue(this.option.getValue()); - double thumbOffset = MathHelper.clamp((double) (this.getIntValue() - this.min) / this.range * sliderWidth, 0, sliderWidth); + double thumbOffset = Mth.clamp((double) (this.getIntValue() - this.min) / this.range * sliderWidth, 0, sliderWidth); int thumbX = (int) (sliderX + thumbOffset - THUMB_WIDTH); int trackY = (int) (sliderY + (sliderHeight / 2f) - ((double) TRACK_HEIGHT / 2)); @@ -114,7 +114,7 @@ private void renderSlider(DrawContext drawContext) { String label = String.valueOf(this.getIntValue()); - int labelWidth = this.font.getWidth(label); + int labelWidth = this.font.width(label); this.drawString(drawContext, label, sliderX - labelWidth - 6, sliderY + (sliderHeight / 2) - 4, 0xFFFFFFFF); } @@ -152,7 +152,7 @@ private void setValueFromMouse(double d) { } public void setValue(double d) { - this.thumbPosition = MathHelper.clamp(d, 0.0D, 1.0D); + this.thumbPosition = Mth.clamp(d, 0.0D, 1.0D); int value = this.getIntValue(); @@ -165,11 +165,11 @@ public void setValue(double d) { public boolean keyPressed(int keyCode, int scanCode, int modifiers) { if (!isFocused()) return false; - if (keyCode == InputUtil.GLFW_KEY_LEFT) { - this.option.setValue(MathHelper.clamp(this.option.getValue() - this.interval, this.min, this.max)); + if (keyCode == InputConstants.KEY_LEFT) { + this.option.setValue(Mth.clamp(this.option.getValue() - this.interval, this.min, this.max)); return true; - } else if (keyCode == InputUtil.GLFW_KEY_RIGHT) { - this.option.setValue(MathHelper.clamp(this.option.getValue() + this.interval, this.min, this.max)); + } else if (keyCode == InputConstants.KEY_RIGHT) { + this.option.setValue(Mth.clamp(this.option.getValue() + this.interval, this.min, this.max)); return true; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/TickBoxControl.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/TickBoxControl.java index 9dc1a1dbcb..abdc1e1dce 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/TickBoxControl.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/TickBoxControl.java @@ -2,10 +2,9 @@ import me.jellysquid.mods.sodium.client.gui.options.Option; import me.jellysquid.mods.sodium.client.util.Dim2i; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.input.KeyCodes; -import net.minecraft.client.util.InputUtil; -import net.minecraft.client.util.math.Rect2i; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.navigation.CommonInputs; +import net.minecraft.client.renderer.Rect2i; public class TickBoxControl implements Control { private final Option option; @@ -39,7 +38,7 @@ public TickBoxControlElement(Option option, Dim2i dim) { } @Override - public void render(DrawContext drawContext, int mouseX, int mouseY, float delta) { + public void render(GuiGraphics drawContext, int mouseX, int mouseY, float delta) { super.render(drawContext, mouseX, mouseY, delta); final int x = this.button.getX(); @@ -81,7 +80,7 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { public boolean keyPressed(int keyCode, int scanCode, int modifiers) { if (!isFocused()) return false; - if (KeyCodes.isToggle(keyCode)) { + if (CommonInputs.selected(keyCode)) { toggleControl(); this.playClickSound(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/MinecraftOptionsStorage.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/MinecraftOptionsStorage.java index 30663f78db..92748aae01 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/MinecraftOptionsStorage.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/MinecraftOptionsStorage.java @@ -1,24 +1,24 @@ package me.jellysquid.mods.sodium.client.gui.options.storage; import me.jellysquid.mods.sodium.client.SodiumClientMod; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.option.GameOptions; +import net.minecraft.client.Minecraft; +import net.minecraft.client.Options; -public class MinecraftOptionsStorage implements OptionStorage { - private final MinecraftClient client; +public class MinecraftOptionsStorage implements OptionStorage { + private final Minecraft client; public MinecraftOptionsStorage() { - this.client = MinecraftClient.getInstance(); + this.client = Minecraft.getInstance(); } @Override - public GameOptions getData() { + public Options getData() { return this.client.options; } @Override public void save() { - this.getData().write(); + this.getData().save(); SodiumClientMod.logger().info("Flushed changes to Minecraft configuration"); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/prompt/ScreenPrompt.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/prompt/ScreenPrompt.java index c60a1aae7f..b28acdf918 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/prompt/ScreenPrompt.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/prompt/ScreenPrompt.java @@ -2,21 +2,24 @@ import me.jellysquid.mods.sodium.client.gui.widgets.AbstractWidget; import me.jellysquid.mods.sodium.client.gui.widgets.FlatButtonWidget; +import me.jellysquid.mods.sodium.client.gui.widgets.FlatButtonWidget.Style; import me.jellysquid.mods.sodium.client.util.Dim2i; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.Drawable; -import net.minecraft.client.gui.Element; -import net.minecraft.text.StringVisitable; -import net.minecraft.text.Text; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.Renderable; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.FormattedText; +import net.minecraft.util.FormattedCharSequence; import org.jetbrains.annotations.NotNull; import org.lwjgl.glfw.GLFW; - +import com.mojang.blaze3d.vertex.PoseStack; import java.util.List; -public class ScreenPrompt implements Element, Drawable { +public class ScreenPrompt implements GuiEventListener, Renderable { private final ScreenPromptable parent; - private final List text; + private final List text; private final Action action; @@ -24,7 +27,7 @@ public class ScreenPrompt implements Element, Drawable { private final int width, height; - public ScreenPrompt(ScreenPromptable parent, List text, int width, int height, Action action) { + public ScreenPrompt(ScreenPromptable parent, List text, int width, int height, Action action) { this.parent = parent; this.text = text; @@ -40,16 +43,16 @@ public void init() { int boxX = (parentDimensions.width() / 2) - (width / 2); int boxY = (parentDimensions.height() / 2) - (height / 2); - this.closeButton = new FlatButtonWidget(new Dim2i((boxX + width) - 84, (boxY + height) - 24, 80, 20), Text.literal("Close"), this::close); + this.closeButton = new FlatButtonWidget(new Dim2i((boxX + width) - 84, (boxY + height) - 24, 80, 20), Component.literal("Close"), this::close); this.closeButton.setStyle(createButtonStyle()); this.actionButton = new FlatButtonWidget(new Dim2i((boxX + width) - 198, (boxY + height) - 24, 110, 20), this.action.label, this::runAction); this.actionButton.setStyle(createButtonStyle()); } - public void render(DrawContext drawContext, int mouseX, int mouseY, float delta) { - var matrices = drawContext.getMatrices(); - matrices.push(); + public void render(GuiGraphics drawContext, int mouseX, int mouseY, float delta) { + var matrices = drawContext.pose(); + matrices.pushPose(); matrices.translate(0.0f, 0.0f, 1000.0f); var parentDimensions = this.parent.getDimensions(); @@ -62,7 +65,7 @@ public void render(DrawContext drawContext, int mouseX, int mouseY, float delta) int boxY = (parentDimensions.height() / 2) - (height / 2); drawContext.fill(boxX, boxY, boxX + width, boxY + height, 0xFF171717); - drawContext.drawBorder(boxX, boxY, width, height, 0xFF121212); + drawContext.renderOutline(boxX, boxY, width, height, 0xFF121212); matrices.translate(0.0f, 0.0f, 50.0f); @@ -74,14 +77,14 @@ public void render(DrawContext drawContext, int mouseX, int mouseY, float delta) int textMaxWidth = width - (padding * 2); int textMaxHeight = height - (padding * 2); - var textRenderer = MinecraftClient.getInstance().textRenderer; + var textRenderer = Minecraft.getInstance().font; for (var paragraph : this.text) { - var formatted = textRenderer.wrapLines(paragraph, textMaxWidth); + var formatted = textRenderer.split(paragraph, textMaxWidth); for (var line : formatted) { - drawContext.drawText(textRenderer, line, textX, textY, 0xFFFFFFFF, true); - textY += textRenderer.fontHeight + 2; + drawContext.drawString(textRenderer, line, textX, textY, 0xFFFFFFFF, true); + textY += textRenderer.lineHeight + 2; } textY += 8; @@ -91,7 +94,7 @@ public void render(DrawContext drawContext, int mouseX, int mouseY, float delta) button.render(drawContext, mouseX, mouseY, delta); } - matrices.pop(); + matrices.popPose(); } private static FlatButtonWidget.Style createButtonStyle() { @@ -138,7 +141,7 @@ public boolean keyPressed(int keyCode, int scanCode, int modifiers) { return true; } - return Element.super.keyPressed(keyCode, scanCode, modifiers); + return GuiEventListener.super.keyPressed(keyCode, scanCode, modifiers); } @Override @@ -155,7 +158,7 @@ private void runAction() { this.close(); } - public record Action(Text label, Runnable runnable) { + public record Action(Component label, Runnable runnable) { } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/screen/ConfigCorruptedScreen.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/screen/ConfigCorruptedScreen.java index b5c6afa916..9340b62c2d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/screen/ConfigCorruptedScreen.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/screen/ConfigCorruptedScreen.java @@ -3,11 +3,11 @@ import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.gui.console.Console; import me.jellysquid.mods.sodium.client.gui.console.message.MessageLevel; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.gui.widget.ButtonWidget; -import net.minecraft.text.Text; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; import org.jetbrains.annotations.Nullable; import java.util.Arrays; @@ -29,8 +29,8 @@ public class ConfigCorruptedScreen extends Screen { More information about the error can be found in the log file. """; - private static final List TEXT_BODY = Arrays.stream(TEXT_BODY_RAW.split("\n")) - .map(Text::literal) + private static final List TEXT_BODY = Arrays.stream(TEXT_BODY_RAW.split("\n")) + .map(Component::literal) .collect(Collectors.toList()); private static final int BUTTON_WIDTH = 140; @@ -42,7 +42,7 @@ public class ConfigCorruptedScreen extends Screen { private final Function nextScreen; public ConfigCorruptedScreen(@Nullable Screen prevScreen, @Nullable Function nextScreen) { - super(Text.literal("Sodium failed to load the configuration file")); + super(Component.literal("Sodium failed to load the configuration file")); this.prevScreen = prevScreen; this.nextScreen = nextScreen; @@ -54,31 +54,31 @@ protected void init() { int buttonY = this.height - SCREEN_PADDING - BUTTON_HEIGHT; - this.addDrawableChild(ButtonWidget.builder(Text.literal("Continue"), (btn) -> { - Console.instance().logMessage(MessageLevel.INFO, Text.translatable("sodium.console.config_file_was_reset"), 3.0); + this.addRenderableWidget(Button.builder(Component.literal("Continue"), (btn) -> { + Console.instance().logMessage(MessageLevel.INFO, Component.translatable("sodium.console.config_file_was_reset"), 3.0); SodiumClientMod.restoreDefaultOptions(); - MinecraftClient.getInstance().setScreen(this.nextScreen.apply(this.prevScreen)); - }).dimensions(this.width - SCREEN_PADDING - BUTTON_WIDTH, buttonY, BUTTON_WIDTH, BUTTON_HEIGHT).build()); + Minecraft.getInstance().setScreen(this.nextScreen.apply(this.prevScreen)); + }).bounds(this.width - SCREEN_PADDING - BUTTON_WIDTH, buttonY, BUTTON_WIDTH, BUTTON_HEIGHT).build()); - this.addDrawableChild(ButtonWidget.builder(Text.literal("Go back"), (btn) -> { - MinecraftClient.getInstance().setScreen(this.prevScreen); - }).dimensions(SCREEN_PADDING, buttonY, BUTTON_WIDTH, BUTTON_HEIGHT).build()); + this.addRenderableWidget(Button.builder(Component.literal("Go back"), (btn) -> { + Minecraft.getInstance().setScreen(this.prevScreen); + }).bounds(SCREEN_PADDING, buttonY, BUTTON_WIDTH, BUTTON_HEIGHT).build()); } @Override - public void render(DrawContext drawContext, int mouseX, int mouseY, float delta) { + public void render(GuiGraphics drawContext, int mouseX, int mouseY, float delta) { super.render(drawContext, mouseX, mouseY, delta); - drawContext.drawTextWithShadow(this.textRenderer, Text.literal("Sodium Renderer"), 32, 32, 0xffffff); - drawContext.drawTextWithShadow(this.textRenderer, Text.literal("Could not load the configuration file"), 32, 48, 0xff0000); + drawContext.drawString(this.font, Component.literal("Sodium Renderer"), 32, 32, 0xffffff); + drawContext.drawString(this.font, Component.literal("Could not load the configuration file"), 32, 48, 0xff0000); for (int i = 0; i < TEXT_BODY.size(); i++) { if (TEXT_BODY.get(i).getString().isEmpty()) { continue; } - drawContext.drawTextWithShadow(this.textRenderer, TEXT_BODY.get(i), 32, 68 + (i * 12), 0xffffff); + drawContext.drawString(this.font, TEXT_BODY.get(i), 32, 68 + (i * 12), 0xffffff); } } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/AbstractWidget.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/AbstractWidget.java index 46d7cf92e3..e18349d0d9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/AbstractWidget.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/AbstractWidget.java @@ -1,78 +1,78 @@ package me.jellysquid.mods.sodium.client.gui.widgets; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.font.TextRenderer; -import net.minecraft.client.gui.Drawable; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.Element; -import net.minecraft.client.gui.Selectable; -import net.minecraft.client.gui.navigation.GuiNavigation; -import net.minecraft.client.gui.navigation.GuiNavigationPath; -import net.minecraft.client.gui.navigation.GuiNavigationType; -import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder; -import net.minecraft.client.gui.screen.narration.NarrationPart; -import net.minecraft.client.sound.PositionedSoundInstance; -import net.minecraft.sound.SoundEvents; -import net.minecraft.text.StringVisitable; -import net.minecraft.text.Text; +import net.minecraft.client.InputType; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.ComponentPath; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.Renderable; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.client.gui.narration.NarratableEntry; +import net.minecraft.client.gui.narration.NarratedElementType; +import net.minecraft.client.gui.narration.NarrationElementOutput; +import net.minecraft.client.gui.navigation.FocusNavigationEvent; +import net.minecraft.client.resources.sounds.SimpleSoundInstance; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.FormattedText; +import net.minecraft.sounds.SoundEvents; import org.jetbrains.annotations.Nullable; -public abstract class AbstractWidget implements Drawable, Element, Selectable { - protected final TextRenderer font; +public abstract class AbstractWidget implements Renderable, GuiEventListener, NarratableEntry { + protected final Font font; protected boolean focused; protected boolean hovered; protected AbstractWidget() { - this.font = MinecraftClient.getInstance().textRenderer; + this.font = Minecraft.getInstance().font; } - protected void drawString(DrawContext drawContext, String str, int x, int y, int color) { - drawContext.drawTextWithShadow(this.font, str, x, y, color); + protected void drawString(GuiGraphics drawContext, String str, int x, int y, int color) { + drawContext.drawString(this.font, str, x, y, color); } - protected void drawString(DrawContext drawContext, Text text, int x, int y, int color) { - drawContext.drawTextWithShadow(this.font, text, x, y, color); + protected void drawString(GuiGraphics drawContext, Component text, int x, int y, int color) { + drawContext.drawString(this.font, text, x, y, color); } public boolean isHovered() { return this.hovered; } - protected void drawRect(DrawContext drawContext, int x1, int y1, int x2, int y2, int color) { + protected void drawRect(GuiGraphics drawContext, int x1, int y1, int x2, int y2, int color) { drawContext.fill(x1, y1, x2, y2, color); } protected void playClickSound() { - MinecraftClient.getInstance().getSoundManager() - .play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK.value(), 1.0F)); + Minecraft.getInstance().getSoundManager() + .play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK.value(), 1.0F)); } - protected int getStringWidth(StringVisitable text) { - return this.font.getWidth(text); + protected int getStringWidth(FormattedText text) { + return this.font.width(text); } - public Selectable.SelectionType getType() { + public NarratableEntry.NarrationPriority narrationPriority() { if (this.focused) { - return Selectable.SelectionType.FOCUSED; + return NarratableEntry.NarrationPriority.FOCUSED; } if (this.hovered) { - return Selectable.SelectionType.HOVERED; + return NarratableEntry.NarrationPriority.HOVERED; } - return Selectable.SelectionType.NONE; + return NarratableEntry.NarrationPriority.NONE; } @Override - public void appendNarrations(NarrationMessageBuilder builder) { + public void updateNarration(NarrationElementOutput builder) { if (this.focused) { - builder.put(NarrationPart.USAGE, Text.translatable("narration.button.usage.focused")); + builder.add(NarratedElementType.USAGE, Component.translatable("narration.button.usage.focused")); } else if (this.hovered) { - builder.put(NarrationPart.USAGE, Text.translatable("narration.button.usage.hovered")); + builder.add(NarratedElementType.USAGE, Component.translatable("narration.button.usage.hovered")); } } @Nullable - public GuiNavigationPath getNavigationPath(GuiNavigation navigation) { - return !this.isFocused() ? GuiNavigationPath.of(this) : null; + public ComponentPath nextFocusPath(FocusNavigationEvent navigation) { + return !this.isFocused() ? ComponentPath.leaf(this) : null; } @Override @@ -85,14 +85,14 @@ public void setFocused(boolean focused) { if (!focused) { this.focused = false; } else { - GuiNavigationType guiNavigationType = MinecraftClient.getInstance().getNavigationType(); - if (guiNavigationType == GuiNavigationType.KEYBOARD_TAB || guiNavigationType == GuiNavigationType.KEYBOARD_ARROW) { + InputType guiNavigationType = Minecraft.getInstance().getLastInputType(); + if (guiNavigationType == InputType.KEYBOARD_TAB || guiNavigationType == InputType.KEYBOARD_ARROW) { this.focused = true; } } } - protected void drawBorder(DrawContext drawContext, int x1, int y1, int x2, int y2, int color) { + protected void drawBorder(GuiGraphics drawContext, int x1, int y1, int x2, int y2, int color) { drawContext.fill(x1, y1, x2, y1 + 1, color); drawContext.fill(x1, y2 - 1, x2, y2, color); drawContext.fill(x1, y1, x1 + 1, y2, color); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/FlatButtonWidget.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/FlatButtonWidget.java index a09b330935..ae3df5d623 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/FlatButtonWidget.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/FlatButtonWidget.java @@ -1,20 +1,19 @@ package me.jellysquid.mods.sodium.client.gui.widgets; import me.jellysquid.mods.sodium.client.util.Dim2i; -import net.minecraft.client.gui.Drawable; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.ScreenRect; -import net.minecraft.client.gui.navigation.GuiNavigation; -import net.minecraft.client.gui.navigation.GuiNavigationPath; -import net.minecraft.client.input.KeyCodes; -import net.minecraft.client.util.InputUtil; -import net.minecraft.text.Text; +import net.minecraft.client.gui.ComponentPath; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.Renderable; +import net.minecraft.client.gui.navigation.CommonInputs; +import net.minecraft.client.gui.navigation.FocusNavigationEvent; +import net.minecraft.client.gui.navigation.ScreenRectangle; +import net.minecraft.network.chat.Component; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Objects; -public class FlatButtonWidget extends AbstractWidget implements Drawable { +public class FlatButtonWidget extends AbstractWidget implements Renderable { private final Dim2i dim; private final Runnable action; @@ -24,16 +23,16 @@ public class FlatButtonWidget extends AbstractWidget implements Drawable { private boolean enabled = true; private boolean visible = true; - private Text label; + private Component label; - public FlatButtonWidget(Dim2i dim, Text label, Runnable action) { + public FlatButtonWidget(Dim2i dim, Component label, Runnable action) { this.dim = dim; this.label = label; this.action = action; } @Override - public void render(DrawContext drawContext, int mouseX, int mouseY, float delta) { + public void render(GuiGraphics drawContext, int mouseX, int mouseY, float delta) { if (!this.visible) { return; } @@ -43,7 +42,7 @@ public void render(DrawContext drawContext, int mouseX, int mouseY, float delta) int backgroundColor = this.enabled ? (this.hovered ? this.style.bgHovered : this.style.bgDefault) : this.style.bgDisabled; int textColor = this.enabled ? this.style.textDefault : this.style.textDisabled; - int strWidth = this.font.getWidth(this.label); + int strWidth = this.font.width(this.label); this.drawRect(drawContext, this.dim.x(), this.dim.y(), this.dim.getLimitX(), this.dim.getLimitY(), backgroundColor); this.drawString(drawContext, this.label, this.dim.getCenterX() - (strWidth / 2), this.dim.getCenterY() - 4, textColor); @@ -86,7 +85,7 @@ public boolean keyPressed(int keyCode, int scanCode, int modifiers) { if (!this.isFocused()) return false; - if (KeyCodes.isToggle(keyCode)) { + if (CommonInputs.selected(keyCode)) { doAction(); return true; } @@ -107,24 +106,24 @@ public void setVisible(boolean visible) { this.visible = visible; } - public void setLabel(Text text) { + public void setLabel(Component text) { this.label = text; } - public Text getLabel() { + public Component getLabel() { return this.label; } @Override - public @Nullable GuiNavigationPath getNavigationPath(GuiNavigation navigation) { + public @Nullable ComponentPath nextFocusPath(FocusNavigationEvent navigation) { if (!this.enabled || !this.visible) return null; - return super.getNavigationPath(navigation); + return super.nextFocusPath(navigation); } @Override - public ScreenRect getNavigationFocus() { - return new ScreenRect(this.dim.x(), this.dim.y(), this.dim.width(), this.dim.height()); + public ScreenRectangle getRectangle() { + return new ScreenRectangle(this.dim.x(), this.dim.y(), this.dim.width(), this.dim.height()); } public static class Style { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/color/ColorProvider.java b/src/main/java/me/jellysquid/mods/sodium/client/model/color/ColorProvider.java index 267a314775..a0f7262d94 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/color/ColorProvider.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/color/ColorProvider.java @@ -2,7 +2,7 @@ import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; import me.jellysquid.mods.sodium.client.world.WorldSlice; -import net.minecraft.util.math.BlockPos; +import net.minecraft.core.BlockPos; public interface ColorProvider { /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/color/ColorProviderRegistry.java b/src/main/java/me/jellysquid/mods/sodium/client/model/color/ColorProviderRegistry.java index 7e31d144c1..138d9cd0d7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/color/ColorProviderRegistry.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/color/ColorProviderRegistry.java @@ -1,16 +1,17 @@ package me.jellysquid.mods.sodium.client.model.color; import it.unimi.dsi.fastutil.objects.Reference2ReferenceMap; +import it.unimi.dsi.fastutil.objects.Reference2ReferenceMap.Entry; import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; import it.unimi.dsi.fastutil.objects.ReferenceSet; import me.jellysquid.mods.sodium.client.model.color.interop.BlockColorsExtended; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.block.Blocks; import net.minecraft.client.color.block.BlockColors; -import net.minecraft.fluid.Fluid; -import net.minecraft.fluid.FluidState; -import net.minecraft.fluid.Fluids; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.Fluid; +import net.minecraft.world.level.material.FluidState; +import net.minecraft.world.level.material.Fluids; // TODO: Make the registry a global somewhere that is only initialized once after content load diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/color/DefaultColorProviders.java b/src/main/java/me/jellysquid/mods/sodium/client/model/color/DefaultColorProviders.java index bd7f2375ae..19cba63f76 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/color/DefaultColorProviders.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/color/DefaultColorProviders.java @@ -6,15 +6,14 @@ import me.jellysquid.mods.sodium.client.world.WorldSlice; import net.caffeinemc.mods.sodium.api.util.ColorARGB; import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandler; -import net.minecraft.block.BlockState; -import net.minecraft.client.color.block.BlockColorProvider; -import net.minecraft.fluid.FluidState; -import net.minecraft.util.math.BlockPos; - +import net.minecraft.client.color.block.BlockColor; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.FluidState; import java.util.Arrays; public class DefaultColorProviders { - public static ColorProvider adapt(BlockColorProvider provider) { + public static ColorProvider adapt(BlockColor provider) { return new VanillaAdapter(provider); } @@ -63,9 +62,9 @@ protected int getColor(WorldSlice world, int x, int y, int z) { } private static class VanillaAdapter implements ColorProvider { - private final BlockColorProvider provider; + private final BlockColor provider; - private VanillaAdapter(BlockColorProvider provider) { + private VanillaAdapter(BlockColor provider) { this.provider = provider; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/color/interop/BlockColorsExtended.java b/src/main/java/me/jellysquid/mods/sodium/client/model/color/interop/BlockColorsExtended.java index e560eccfc3..922d8676ac 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/color/interop/BlockColorsExtended.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/color/interop/BlockColorsExtended.java @@ -2,12 +2,12 @@ import it.unimi.dsi.fastutil.objects.Reference2ReferenceMap; import it.unimi.dsi.fastutil.objects.ReferenceSet; -import net.minecraft.block.Block; -import net.minecraft.client.color.block.BlockColorProvider; +import net.minecraft.client.color.block.BlockColor; import net.minecraft.client.color.block.BlockColors; +import net.minecraft.world.level.block.Block; public interface BlockColorsExtended { - static Reference2ReferenceMap getProviders(BlockColors blockColors) { + static Reference2ReferenceMap getProviders(BlockColors blockColors) { return ((BlockColorsExtended) blockColors).sodium$getProviders(); } @@ -15,7 +15,7 @@ static ReferenceSet getOverridenVanillaBlocks(BlockColors blockColors) { return ((BlockColorsExtended) blockColors).sodium$getOverridenVanillaBlocks(); } - Reference2ReferenceMap sodium$getProviders(); + Reference2ReferenceMap sodium$getProviders(); ReferenceSet sodium$getOverridenVanillaBlocks(); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/color/interop/ItemColorsExtended.java b/src/main/java/me/jellysquid/mods/sodium/client/model/color/interop/ItemColorsExtended.java index e40060cf22..b7d9e0d6a1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/color/interop/ItemColorsExtended.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/color/interop/ItemColorsExtended.java @@ -1,8 +1,8 @@ package me.jellysquid.mods.sodium.client.model.color.interop; -import net.minecraft.client.color.item.ItemColorProvider; -import net.minecraft.item.ItemStack; +import net.minecraft.client.color.item.ItemColor; +import net.minecraft.world.item.ItemStack; public interface ItemColorsExtended { - ItemColorProvider sodium$getColorProvider(ItemStack stack); + ItemColor sodium$getColorProvider(ItemStack stack); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/LightPipeline.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/LightPipeline.java index 44f4729bd3..fb091e1f72 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/LightPipeline.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/LightPipeline.java @@ -2,8 +2,8 @@ import me.jellysquid.mods.sodium.client.model.light.data.QuadLightData; import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; /** * Light pipelines allow model quads for any location in the world to be lit using various backends, including fluids diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/ArrayLightDataCache.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/ArrayLightDataCache.java index 7f40883a8a..a9f3ae4ba6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/ArrayLightDataCache.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/ArrayLightDataCache.java @@ -1,9 +1,8 @@ package me.jellysquid.mods.sodium.client.model.light.data; import me.jellysquid.mods.sodium.client.world.WorldSlice; -import net.minecraft.util.math.ChunkSectionPos; -import net.minecraft.world.BlockRenderView; - +import net.minecraft.core.SectionPos; +import net.minecraft.world.level.BlockAndTintGetter; import java.util.Arrays; /** @@ -19,15 +18,15 @@ public class ArrayLightDataCache extends LightDataAccess { private int xOffset, yOffset, zOffset; - public ArrayLightDataCache(BlockRenderView world) { + public ArrayLightDataCache(BlockAndTintGetter world) { this.world = world; this.light = new int[BLOCK_LENGTH * BLOCK_LENGTH * BLOCK_LENGTH]; } - public void reset(ChunkSectionPos origin) { - this.xOffset = origin.getMinX() - NEIGHBOR_BLOCK_RADIUS; - this.yOffset = origin.getMinY() - NEIGHBOR_BLOCK_RADIUS; - this.zOffset = origin.getMinZ() - NEIGHBOR_BLOCK_RADIUS; + public void reset(SectionPos origin) { + this.xOffset = origin.minBlockX() - NEIGHBOR_BLOCK_RADIUS; + this.yOffset = origin.minBlockY() - NEIGHBOR_BLOCK_RADIUS; + this.zOffset = origin.minBlockZ() - NEIGHBOR_BLOCK_RADIUS; Arrays.fill(this.light, 0); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/HashLightDataCache.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/HashLightDataCache.java index 57c5f43037..47b03df67c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/HashLightDataCache.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/HashLightDataCache.java @@ -1,8 +1,8 @@ package me.jellysquid.mods.sodium.client.model.light.data; import it.unimi.dsi.fastutil.longs.Long2IntLinkedOpenHashMap; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.BlockRenderView; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.BlockAndTintGetter; /** * A light data cache which uses a hash table to store previously accessed values. @@ -10,7 +10,7 @@ public class HashLightDataCache extends LightDataAccess { private final Long2IntLinkedOpenHashMap map = new Long2IntLinkedOpenHashMap(1024, 0.50f); - public HashLightDataCache(BlockRenderView world) { + public HashLightDataCache(BlockAndTintGetter world) { this.world = world; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/LightDataAccess.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/LightDataAccess.java index 525b802980..9c1ba0e512 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/LightDataAccess.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/LightDataAccess.java @@ -1,12 +1,12 @@ package me.jellysquid.mods.sodium.client.model.light.data; -import net.minecraft.block.BlockState; -import net.minecraft.client.render.LightmapTextureManager; -import net.minecraft.client.render.WorldRenderer; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.world.BlockRenderView; -import net.minecraft.world.LightType; +import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.LightLayer; +import net.minecraft.world.level.block.state.BlockState; /** * The light data cache is used to make accessing the light data and occlusion properties of blocks cheaper. The data @@ -28,19 +28,19 @@ * You can use the various static pack/unpack methods to extract these values in a usable format. */ public abstract class LightDataAccess { - private final BlockPos.Mutable pos = new BlockPos.Mutable(); - protected BlockRenderView world; + private final BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(); + protected BlockAndTintGetter world; public int get(int x, int y, int z, Direction d1, Direction d2) { - return this.get(x + d1.getOffsetX() + d2.getOffsetX(), - y + d1.getOffsetY() + d2.getOffsetY(), - z + d1.getOffsetZ() + d2.getOffsetZ()); + return this.get(x + d1.getStepX() + d2.getStepX(), + y + d1.getStepY() + d2.getStepY(), + z + d1.getStepZ() + d2.getStepZ()); } public int get(int x, int y, int z, Direction dir) { - return this.get(x + dir.getOffsetX(), - y + dir.getOffsetY(), - z + dir.getOffsetZ()); + return this.get(x + dir.getStepX(), + y + dir.getStepY(), + z + dir.getStepZ()); } public int get(BlockPos pos, Direction dir) { @@ -59,16 +59,16 @@ public int get(BlockPos pos) { protected int compute(int x, int y, int z) { BlockPos pos = this.pos.set(x, y, z); - BlockRenderView world = this.world; + BlockAndTintGetter world = this.world; BlockState state = world.getBlockState(pos); - boolean em = state.hasEmissiveLighting(world, pos); - boolean op = state.shouldBlockVision(world, pos) && state.getOpacity(world, pos) != 0; - boolean fo = state.isOpaqueFullCube(world, pos); - boolean fc = state.isFullCube(world, pos); + boolean em = state.emissiveRendering(world, pos); + boolean op = state.isViewBlocking(world, pos) && state.getLightBlock(world, pos) != 0; + boolean fo = state.isSolidRender(world, pos); + boolean fc = state.isCollisionShapeFullBlock(world, pos); - int lu = state.getLuminance(); + int lu = state.getLightEmission(); // OPTIMIZE: Do not calculate light data if the block is full and opaque and does not emit light. int bl; @@ -77,14 +77,14 @@ protected int compute(int x, int y, int z) { bl = 0; sl = 0; } else { - bl = world.getLightLevel(LightType.BLOCK, pos); - sl = world.getLightLevel(LightType.SKY, pos); + bl = world.getBrightness(LightLayer.BLOCK, pos); + sl = world.getBrightness(LightLayer.SKY, pos); } // FIX: Do not apply AO from blocks that emit light float ao; if (lu == 0) { - ao = state.getAmbientOcclusionLightLevel(world, pos); + ao = state.getShadeBrightness(world, pos); } else { ao = 1.0f; } @@ -162,29 +162,29 @@ public static boolean unpackFC(int word) { * Computes the combined lightmap using block light, sky light, and luminance values. * *

This method's logic is equivalent to - * {@link WorldRenderer#getLightmapCoordinates(BlockRenderView, BlockPos)}, but without the + * {@link LevelRenderer#getLightColor(BlockAndTintGetter, BlockPos)}, but without the * emissive check. */ public static int getLightmap(int word) { - return LightmapTextureManager.pack(Math.max(unpackBL(word), unpackLU(word)), unpackSL(word)); + return LightTexture.pack(Math.max(unpackBL(word), unpackLU(word)), unpackSL(word)); } /** * Like {@link #getLightmap(int)}, but checks {@link #unpackEM(int)} first and returns - * the {@link LightmapTextureManager#MAX_LIGHT_COORDINATE fullbright lightmap} if emissive. + * the {@link LightTexture#FULL_BRIGHT fullbright lightmap} if emissive. * *

This method's logic is equivalent to - * {@link WorldRenderer#getLightmapCoordinates(BlockRenderView, BlockPos)}. + * {@link LevelRenderer#getLightColor(BlockAndTintGetter, BlockPos)}. */ public static int getEmissiveLightmap(int word) { if (unpackEM(word)) { - return LightmapTextureManager.MAX_LIGHT_COORDINATE; + return LightTexture.FULL_BRIGHT; } else { return getLightmap(word); } } - public BlockRenderView getWorld() { + public BlockAndTintGetter getWorld() { return this.world; } } \ No newline at end of file diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/flat/FlatLightPipeline.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/flat/FlatLightPipeline.java index acc4e5cb5a..134ee5799e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/flat/FlatLightPipeline.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/flat/FlatLightPipeline.java @@ -5,13 +5,12 @@ import me.jellysquid.mods.sodium.client.model.light.data.QuadLightData; import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFlags; -import net.minecraft.block.BlockState; -import net.minecraft.client.render.LightmapTextureManager; -import net.minecraft.client.render.WorldRenderer; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.world.BlockRenderView; - +import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.state.BlockState; import java.util.Arrays; import static me.jellysquid.mods.sodium.client.model.light.data.LightDataAccess.*; @@ -49,12 +48,12 @@ public void calculate(ModelQuadView quad, BlockPos pos, QuadLightData out, Direc } Arrays.fill(out.lm, lightmap); - Arrays.fill(out.br, this.lightCache.getWorld().getBrightness(lightFace, shade)); + Arrays.fill(out.br, this.lightCache.getWorld().getShade(lightFace, shade)); } /** * When vanilla computes an offset lightmap with flat lighting, it passes the original BlockState but the - * offset BlockPos to {@link WorldRenderer#getLightmapCoordinates(BlockRenderView, BlockState, BlockPos)}. + * offset BlockPos to {@link LevelRenderer#getLightColor(BlockAndTintGetter, BlockState, BlockPos)}. * This does not make much sense but fixes certain issues, primarily dark quads on light-emitting blocks * behind tinted glass. {@link LightDataAccess} cannot efficiently store lightmaps computed with * inconsistent values so this method exists to mirror vanilla behavior as closely as possible. @@ -64,11 +63,11 @@ private int getOffsetLightmap(BlockPos pos, Direction face) { // Check emissivity of the origin state if (unpackEM(word)) { - return LightmapTextureManager.MAX_LIGHT_COORDINATE; + return LightTexture.FULL_BRIGHT; } // Use world light values from the offset pos, but luminance from the origin pos int adjWord = this.lightCache.get(pos, face); - return LightmapTextureManager.pack(Math.max(unpackBL(adjWord), unpackLU(word)), unpackSL(adjWord)); + return LightTexture.pack(Math.max(unpackBL(adjWord), unpackLU(word)), unpackSL(adjWord)); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoFaceData.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoFaceData.java index c1be162c94..5ec8df8a00 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoFaceData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoFaceData.java @@ -1,9 +1,9 @@ package me.jellysquid.mods.sodium.client.model.light.smooth; import me.jellysquid.mods.sodium.client.model.light.data.LightDataAccess; -import net.minecraft.client.render.LightmapTextureManager; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; import static me.jellysquid.mods.sodium.client.model.light.data.ArrayLightDataCache.*; @@ -26,9 +26,9 @@ public void initLightData(LightDataAccess cache, BlockPos pos, Direction directi final int adjZ; if (offset) { - adjX = x + direction.getOffsetX(); - adjY = y + direction.getOffsetY(); - adjZ = z + direction.getOffsetZ(); + adjX = x + direction.getStepX(); + adjY = y + direction.getStepY(); + adjZ = z + direction.getStepZ(); } else { adjX = x; adjY = y; @@ -220,16 +220,16 @@ private static int calculateCornerBrightness(int a, int b, int c, int d, boolean // FIX: Apply the fullbright lightmap from emissive blocks at the very end so it cannot influence // the minimum lightmap and produce incorrect results (for example, sculk sensors in a dark room) if (aem) { - a = LightmapTextureManager.MAX_LIGHT_COORDINATE; + a = LightTexture.FULL_BRIGHT; } if (bem) { - b = LightmapTextureManager.MAX_LIGHT_COORDINATE; + b = LightTexture.FULL_BRIGHT; } if (cem) { - c = LightmapTextureManager.MAX_LIGHT_COORDINATE; + c = LightTexture.FULL_BRIGHT; } if (dem) { - d = LightmapTextureManager.MAX_LIGHT_COORDINATE; + d = LightTexture.FULL_BRIGHT; } return ((a + b + c + d) >> 2) & 0xFF00FF; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoNeighborInfo.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoNeighborInfo.java index c8d7627477..372f6a1920 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoNeighborInfo.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoNeighborInfo.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.model.light.smooth; -import net.minecraft.util.math.Direction; +import net.minecraft.core.Direction; /** * The neighbor information for each face of a block, used when performing smooth lighting in order to calculate @@ -245,6 +245,6 @@ public float getDepth(float x, float y, float z) { * @return Returns the {@link AoNeighborInfo} which corresponds with the specified direction */ public static AoNeighborInfo get(Direction direction) { - return VALUES[direction.getId()]; + return VALUES[direction.get3DDataValue()]; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/SmoothLightPipeline.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/SmoothLightPipeline.java index 04c665499c..abedf92c57 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/SmoothLightPipeline.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/SmoothLightPipeline.java @@ -5,9 +5,9 @@ import me.jellysquid.mods.sodium.client.model.light.data.QuadLightData; import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFlags; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.MathHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.util.Mth; /** * A light pipeline which produces smooth interpolated lighting and ambient occlusion for model quads. This @@ -139,7 +139,7 @@ private void applyParallelFace(AoNeighborInfo neighborInfo, ModelQuadView quad, // If the quad is approximately grid-aligned (not inset) to the other side of the block, avoid unnecessary // computation by treating it is as aligned - if (MathHelper.approximatelyEquals(depth, 1.0F)) { + if (Mth.equal(depth, 1.0F)) { this.applyAlignedPartialFaceVertex(pos, dir, weights, i, out, false); } else { // Blend the occlusion factor between the blocks directly beside this face and the blocks above it @@ -165,9 +165,9 @@ private void applyNonParallelFace(AoNeighborInfo neighborInfo, ModelQuadView qua float depth = neighborInfo.getDepth(cx, cy, cz); // If the quad is approximately grid-aligned (not inset), avoid unnecessary computation by treating it is as aligned - if (MathHelper.approximatelyEquals(depth, 0.0F)) { + if (Mth.equal(depth, 0.0F)) { this.applyAlignedPartialFaceVertex(pos, dir, weights, i, out, true); - } else if (MathHelper.approximatelyEquals(depth, 1.0F)) { + } else if (Mth.equal(depth, 1.0F)) { this.applyAlignedPartialFaceVertex(pos, dir, weights, i, out, false); } else { // Blend the occlusion factor between the blocks directly beside this face and the blocks above it @@ -215,7 +215,7 @@ private void applyInsetPartialFaceVertex(BlockPos pos, Direction dir, float n1d, } private void applySidedBrightness(QuadLightData out, Direction face, boolean shade) { - float brightness = this.lightCache.getWorld().getBrightness(face, shade); + float brightness = this.lightCache.getWorld().getShade(face, shade); float[] br = out.br; for (int i = 0; i < br.length; i++) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/BakedQuadView.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/BakedQuadView.java index 247e7a23fc..b835cba253 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/BakedQuadView.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/BakedQuadView.java @@ -1,7 +1,6 @@ package me.jellysquid.mods.sodium.client.model.quad; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; -import net.minecraft.util.math.Direction; public interface BakedQuadView extends ModelQuadView { ModelQuadFacing getNormalFace(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuad.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuad.java index 50028467f1..8318e45425 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuad.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuad.java @@ -1,10 +1,10 @@ package me.jellysquid.mods.sodium.client.model.quad; -import net.minecraft.client.texture.Sprite; -import net.minecraft.util.math.Direction; - import static me.jellysquid.mods.sodium.client.util.ModelQuadUtil.*; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.core.Direction; + /** * A simple implementation of the {@link ModelQuadViewMutable} interface which can provide an on-heap scratch area * for storing quad vertex data. @@ -13,7 +13,7 @@ public class ModelQuad implements ModelQuadViewMutable { private final int[] data = new int[VERTEX_SIZE * 4]; private int flags; - private Sprite sprite; + private TextureAtlasSprite sprite; private Direction direction; private int colorIdx; @@ -59,7 +59,7 @@ public void setFlags(int flags) { } @Override - public void setSprite(Sprite sprite) { + public void setSprite(TextureAtlasSprite sprite) { this.sprite = sprite; } @@ -114,7 +114,7 @@ public int getFlags() { } @Override - public Sprite getSprite() { + public TextureAtlasSprite getSprite() { return this.sprite; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java index 7c19d16220..afe24591a6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java @@ -1,8 +1,8 @@ package me.jellysquid.mods.sodium.client.model.quad; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFlags; -import net.minecraft.client.texture.Sprite; -import net.minecraft.util.math.Direction; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.core.Direction; /** * Provides a read-only view of a model quad. For mutable access to a model quad, see {@link ModelQuadViewMutable}. @@ -51,7 +51,7 @@ public interface ModelQuadView { /** * @return The sprite texture used by this quad, or null if none is attached */ - Sprite getSprite(); + TextureAtlasSprite getSprite(); /** * @return The face used by this quad for lighting effects diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadViewMutable.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadViewMutable.java index f978f1d293..dab620471a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadViewMutable.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadViewMutable.java @@ -1,8 +1,8 @@ package me.jellysquid.mods.sodium.client.model.quad; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFlags; -import net.minecraft.client.texture.Sprite; -import net.minecraft.util.math.Direction; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.core.Direction; /** * Provides a mutable view to a model quad. @@ -51,7 +51,7 @@ public interface ModelQuadViewMutable extends ModelQuadView { /** * Sets the sprite used by this quad */ - void setSprite(Sprite sprite); + void setSprite(TextureAtlasSprite sprite); /** * Sets the face used by this quad for lighting effects diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/BlendedColorProvider.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/BlendedColorProvider.java index ad7a6f51e3..805eddc3da 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/BlendedColorProvider.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/BlendedColorProvider.java @@ -5,8 +5,8 @@ import me.jellysquid.mods.sodium.client.world.WorldSlice; import net.caffeinemc.mods.sodium.api.util.ColorARGB; import net.caffeinemc.mods.sodium.api.util.ColorMixer; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.MathHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.util.Mth; public abstract class BlendedColorProvider implements ColorProvider { @Override @@ -25,9 +25,9 @@ private int getVertexColor(WorldSlice world, BlockPos blockPos, ModelQuadView qu // Floor the positions here to always get the largest integer below the input // as negative values by default round toward zero when casting to an integer. // Which would cause negative ratios to be calculated in the interpolation later on. - final int intX = MathHelper.floor(posX); - final int intY = MathHelper.floor(posY); - final int intZ = MathHelper.floor(posZ); + final int intX = Mth.floor(posX); + final int intY = Mth.floor(posY); + final int intZ = Mth.floor(posZ); // Integer component of position vector final int worldIntX = blockPos.getX() + intX; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java index f8b53c46f9..4a407494cc 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.model.quad.properties; -import net.minecraft.util.math.Direction; +import net.minecraft.core.Direction; public enum ModelQuadFacing { POS_X, diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFlags.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFlags.java index 52b602038b..08f3ad02b8 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFlags.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFlags.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.model.quad.properties; import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; -import net.minecraft.util.math.Direction; +import net.minecraft.core.Direction; public class ModelQuadFlags { /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/platform/MessageBox.java b/src/main/java/me/jellysquid/mods/sodium/client/platform/MessageBox.java index 1ae15626ff..a29f7b9cae 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/platform/MessageBox.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/platform/MessageBox.java @@ -1,15 +1,14 @@ package me.jellysquid.mods.sodium.client.platform; import me.jellysquid.mods.sodium.client.platform.windows.api.msgbox.MsgBoxParamSw; +import net.minecraft.Util; import me.jellysquid.mods.sodium.client.platform.windows.api.msgbox.MsgBoxCallback; import me.jellysquid.mods.sodium.client.platform.windows.api.User32; -import net.minecraft.client.util.Window; -import net.minecraft.util.Util; import org.jetbrains.annotations.Nullable; import org.lwjgl.glfw.GLFWNativeWin32; import org.lwjgl.system.MemoryStack; import org.lwjgl.system.MemoryUtil; - +import com.mojang.blaze3d.platform.Window; import java.nio.ByteBuffer; import java.util.Objects; @@ -28,7 +27,7 @@ public static void showMessageBox(@Nullable Window window, private interface MessageBoxImpl { static @Nullable MessageBoxImpl chooseImpl() { - if (Util.getOperatingSystem() == Util.OperatingSystem.WINDOWS) { + if (Util.getPlatform() == Util.OS.WINDOWS) { return new WindowsMessageBoxImpl(); } @@ -56,8 +55,8 @@ public void showMessageBox(@Nullable Window window, if (helpUrl != null) { msgBoxCallback = MsgBoxCallback.create(lpHelpInfo -> { - Util.getOperatingSystem() - .open(helpUrl); + Util.getPlatform() + .openUri(helpUrl); }); } else { msgBoxCallback = null; @@ -66,7 +65,7 @@ public void showMessageBox(@Nullable Window window, final long hWndOwner; if (window != null) { - hWndOwner = GLFWNativeWin32.glfwGetWin32Window(window.getHandle()); + hWndOwner = GLFWNativeWin32.glfwGetWin32Window(window.getWindow()); } else { hWndOwner = MemoryUtil.NULL; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/platform/unix/Libc.java b/src/main/java/me/jellysquid/mods/sodium/client/platform/unix/Libc.java index 43eb5930da..db64bb69e0 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/platform/unix/Libc.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/platform/unix/Libc.java @@ -1,5 +1,6 @@ package me.jellysquid.mods.sodium.client.platform.unix; +import java.nio.ByteBuffer; import org.jetbrains.annotations.Nullable; import org.lwjgl.system.*; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/platform/windows/WindowsCommandLine.java b/src/main/java/me/jellysquid/mods/sodium/client/platform/windows/WindowsCommandLine.java index 1a855ab1e8..9d223b2e17 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/platform/windows/WindowsCommandLine.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/platform/windows/WindowsCommandLine.java @@ -2,7 +2,6 @@ import me.jellysquid.mods.sodium.client.platform.windows.api.Kernel32; import org.lwjgl.system.MemoryUtil; - import java.nio.BufferOverflowException; import java.nio.ByteBuffer; import java.util.Objects; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/platform/windows/WindowsDriverStoreVersion.java b/src/main/java/me/jellysquid/mods/sodium/client/platform/windows/WindowsDriverStoreVersion.java index 328888cd37..eecda4add6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/platform/windows/WindowsDriverStoreVersion.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/platform/windows/WindowsDriverStoreVersion.java @@ -1,5 +1,6 @@ package me.jellysquid.mods.sodium.client.platform.windows; +import java.util.regex.Matcher; import java.util.regex.Pattern; public record WindowsDriverStoreVersion(int driverModel, int featureLevel, int major, int minor) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/platform/windows/api/Kernel32.java b/src/main/java/me/jellysquid/mods/sodium/client/platform/windows/api/Kernel32.java index d85c4852b8..072d8f7994 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/platform/windows/api/Kernel32.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/platform/windows/api/Kernel32.java @@ -3,7 +3,6 @@ import org.jetbrains.annotations.Nullable; import org.lwjgl.PointerBuffer; import org.lwjgl.system.*; - import java.nio.ByteBuffer; import java.nio.IntBuffer; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index eed7dbddb3..2bb011c6b1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -1,43 +1,57 @@ package me.jellysquid.mods.sodium.client.render; import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.SheetedDecalTextureGenerator; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.blaze3d.vertex.VertexMultiConsumer; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.gl.device.CommandList; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; import me.jellysquid.mods.sodium.client.render.chunk.ChunkRenderMatrices; +import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; import me.jellysquid.mods.sodium.client.render.chunk.RenderSectionManager; import me.jellysquid.mods.sodium.client.render.chunk.lists.ChunkRenderList; import me.jellysquid.mods.sodium.client.render.chunk.lists.SortedRenderLists; import me.jellysquid.mods.sodium.client.render.chunk.map.ChunkTracker; import me.jellysquid.mods.sodium.client.render.chunk.map.ChunkTrackerHolder; +import me.jellysquid.mods.sodium.client.render.chunk.region.RenderRegion; import me.jellysquid.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses; import me.jellysquid.mods.sodium.client.render.viewport.Viewport; import me.jellysquid.mods.sodium.client.util.NativeBuffer; +import me.jellysquid.mods.sodium.client.util.iterator.ByteIterator; import me.jellysquid.mods.sodium.client.world.WorldRendererExtended; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.network.ClientPlayerEntity; -import net.minecraft.client.render.*; -import net.minecraft.client.render.block.entity.BlockEntityRenderDispatcher; -import net.minecraft.client.render.model.ModelLoader; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.client.world.ClientWorld; -import net.minecraft.entity.Entity; -import net.minecraft.util.math.*; -import net.minecraft.util.profiler.Profiler; - +import net.minecraft.client.Camera; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderBuffers; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRenderDispatcher; +import net.minecraft.client.resources.model.ModelBakery; +import net.minecraft.core.BlockPos; +import net.minecraft.core.SectionPos; +import net.minecraft.server.level.BlockDestructionProgress; +import net.minecraft.util.Mth; +import net.minecraft.util.profiling.ProfilerFiller; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; import java.util.Collection; import java.util.Iterator; import java.util.SortedSet; /** - * Provides an extension to vanilla's {@link WorldRenderer}. + * Provides an extension to vanilla's {@link LevelRenderer}. */ public class SodiumWorldRenderer { - private final MinecraftClient client; + private final Minecraft client; - private ClientWorld world; + private ClientLevel world; private int renderDistance; private double lastCameraX, lastCameraY, lastCameraZ; @@ -65,7 +79,7 @@ public static SodiumWorldRenderer instance() { * @return The SodiumWorldRenderer based on the current dimension, or null if none is attached */ public static SodiumWorldRenderer instanceNullable() { - var world = MinecraftClient.getInstance().worldRenderer; + var world = Minecraft.getInstance().levelRenderer; if (world instanceof WorldRendererExtended) { return ((WorldRendererExtended) world).sodium$getWorldRenderer(); @@ -74,11 +88,11 @@ public static SodiumWorldRenderer instanceNullable() { return null; } - public SodiumWorldRenderer(MinecraftClient client) { + public SodiumWorldRenderer(Minecraft client) { this.client = client; } - public void setWorld(ClientWorld world) { + public void setWorld(ClientLevel world) { // Check that the world is actually changing if (this.world == world) { return; @@ -95,7 +109,7 @@ public void setWorld(ClientWorld world) { } } - private void loadWorld(ClientWorld world) { + private void loadWorld(ClientLevel world) { this.world = world; try (CommandList commandList = RenderDevice.INSTANCE.createCommandList()) { @@ -150,22 +164,22 @@ public void setupTerrain(Camera camera, this.useEntityCulling = SodiumClientMod.options().performance.useEntityCulling; - if (this.client.options.getClampedViewDistance() != this.renderDistance) { + if (this.client.options.getEffectiveRenderDistance() != this.renderDistance) { this.reload(); } - Profiler profiler = this.client.getProfiler(); + ProfilerFiller profiler = this.client.getProfiler(); profiler.push("camera_setup"); - ClientPlayerEntity player = this.client.player; + LocalPlayer player = this.client.player; if (player == null) { throw new IllegalStateException("Client instance has no active player entity"); } - Vec3d pos = camera.getPos(); - float pitch = camera.getPitch(); - float yaw = camera.getYaw(); + Vec3 pos = camera.getPosition(); + float pitch = camera.getXRot(); + float yaw = camera.getYRot(); float fogDistance = RenderSystem.getShaderFogEnd(); boolean dirty = pos.x != this.lastCameraX || pos.y != this.lastCameraY || pos.z != this.lastCameraZ || @@ -182,33 +196,33 @@ public void setupTerrain(Camera camera, this.lastCameraYaw = yaw; this.lastFogDistance = fogDistance; - profiler.swap("chunk_update"); + profiler.popPush("chunk_update"); this.renderSectionManager.updateChunks(updateChunksImmediately); - profiler.swap("chunk_upload"); + profiler.popPush("chunk_upload"); this.renderSectionManager.uploadChunks(); if (this.renderSectionManager.needsUpdate()) { - profiler.swap("chunk_render_lists"); + profiler.popPush("chunk_render_lists"); this.renderSectionManager.update(camera, viewport, frame, spectator); } if (updateChunksImmediately) { - profiler.swap("chunk_upload_immediately"); + profiler.popPush("chunk_upload_immediately"); this.renderSectionManager.uploadChunks(); } - profiler.swap("chunk_render_tick"); + profiler.popPush("chunk_render_tick"); this.renderSectionManager.tickVisibleRenders(); profiler.pop(); - Entity.setRenderDistanceMultiplier(MathHelper.clamp((double) this.client.options.getClampedViewDistance() / 8.0D, 1.0D, 2.5D) * this.client.options.getEntityDistanceScaling().getValue()); + Entity.setViewScale(Mth.clamp((double) this.client.options.getEffectiveRenderDistance() / 8.0D, 1.0D, 2.5D) * this.client.options.entityDistanceScaling().get()); } private void processChunkEvents() { @@ -217,15 +231,15 @@ private void processChunkEvents() { } /** - * Performs a render pass for the given {@link RenderLayer} and draws all visible chunks for it. + * Performs a render pass for the given {@link RenderType} and draws all visible chunks for it. */ - public void drawChunkLayer(RenderLayer renderLayer, MatrixStack matrixStack, double x, double y, double z) { + public void drawChunkLayer(RenderType renderLayer, PoseStack matrixStack, double x, double y, double z) { ChunkRenderMatrices matrices = ChunkRenderMatrices.from(matrixStack); - if (renderLayer == RenderLayer.getSolid()) { + if (renderLayer == RenderType.solid()) { this.renderSectionManager.renderLayer(matrices, DefaultTerrainRenderPasses.SOLID, x, y, z); this.renderSectionManager.renderLayer(matrices, DefaultTerrainRenderPasses.CUTOUT, x, y, z); - } else if (renderLayer == RenderLayer.getTranslucent()) { + } else if (renderLayer == RenderType.translucent()) { this.renderSectionManager.renderLayer(matrices, DefaultTerrainRenderPasses.TRANSLUCENT, x, y, z); } } @@ -246,7 +260,7 @@ private void initRenderer(CommandList commandList) { this.renderSectionManager = null; } - this.renderDistance = this.client.options.getClampedViewDistance(); + this.renderDistance = this.client.options.getEffectiveRenderDistance(); this.renderSectionManager = new RenderSectionManager(this.world, this.renderDistance, commandList); @@ -254,29 +268,29 @@ private void initRenderer(CommandList commandList) { ChunkTracker.forEachChunk(tracker.getReadyChunks(), this.renderSectionManager::onChunkAdded); } - public void renderBlockEntities(MatrixStack matrices, - BufferBuilderStorage bufferBuilders, - Long2ObjectMap> blockBreakingProgressions, + public void renderBlockEntities(PoseStack matrices, + RenderBuffers bufferBuilders, + Long2ObjectMap> blockBreakingProgressions, Camera camera, float tickDelta) { - VertexConsumerProvider.Immediate immediate = bufferBuilders.getEntityVertexConsumers(); + MultiBufferSource.BufferSource immediate = bufferBuilders.bufferSource(); - Vec3d cameraPos = camera.getPos(); - double x = cameraPos.getX(); - double y = cameraPos.getY(); - double z = cameraPos.getZ(); + Vec3 cameraPos = camera.getPosition(); + double x = cameraPos.x(); + double y = cameraPos.y(); + double z = cameraPos.z(); - BlockEntityRenderDispatcher blockEntityRenderer = MinecraftClient.getInstance().getBlockEntityRenderDispatcher(); + BlockEntityRenderDispatcher blockEntityRenderer = Minecraft.getInstance().getBlockEntityRenderDispatcher(); this.renderBlockEntities(matrices, bufferBuilders, blockBreakingProgressions, tickDelta, immediate, x, y, z, blockEntityRenderer); this.renderGlobalBlockEntities(matrices, bufferBuilders, blockBreakingProgressions, tickDelta, immediate, x, y, z, blockEntityRenderer); } - private void renderBlockEntities(MatrixStack matrices, - BufferBuilderStorage bufferBuilders, - Long2ObjectMap> blockBreakingProgressions, + private void renderBlockEntities(PoseStack matrices, + RenderBuffers bufferBuilders, + Long2ObjectMap> blockBreakingProgressions, float tickDelta, - VertexConsumerProvider.Immediate immediate, + MultiBufferSource.BufferSource immediate, double x, double y, double z, @@ -311,11 +325,11 @@ private void renderBlockEntities(MatrixStack matrices, } } - private void renderGlobalBlockEntities(MatrixStack matrices, - BufferBuilderStorage bufferBuilders, - Long2ObjectMap> blockBreakingProgressions, + private void renderGlobalBlockEntities(PoseStack matrices, + RenderBuffers bufferBuilders, + Long2ObjectMap> blockBreakingProgressions, float tickDelta, - VertexConsumerProvider.Immediate immediate, + MultiBufferSource.BufferSource immediate, double x, double y, double z, @@ -333,42 +347,42 @@ private void renderGlobalBlockEntities(MatrixStack matrices, } } - private static void renderBlockEntity(MatrixStack matrices, - BufferBuilderStorage bufferBuilders, - Long2ObjectMap> blockBreakingProgressions, + private static void renderBlockEntity(PoseStack matrices, + RenderBuffers bufferBuilders, + Long2ObjectMap> blockBreakingProgressions, float tickDelta, - VertexConsumerProvider.Immediate immediate, + MultiBufferSource.BufferSource immediate, double x, double y, double z, BlockEntityRenderDispatcher dispatcher, BlockEntity entity) { - BlockPos pos = entity.getPos(); + BlockPos pos = entity.getBlockPos(); - matrices.push(); + matrices.pushPose(); matrices.translate((double) pos.getX() - x, (double) pos.getY() - y, (double) pos.getZ() - z); - VertexConsumerProvider consumer = immediate; - SortedSet breakingInfo = blockBreakingProgressions.get(pos.asLong()); + MultiBufferSource consumer = immediate; + SortedSet breakingInfo = blockBreakingProgressions.get(pos.asLong()); if (breakingInfo != null && !breakingInfo.isEmpty()) { - int stage = breakingInfo.last().getStage(); + int stage = breakingInfo.last().getProgress(); if (stage >= 0) { - var bufferBuilder = bufferBuilders.getEffectVertexConsumers() - .getBuffer(ModelLoader.BLOCK_DESTRUCTION_RENDER_LAYERS.get(stage)); + var bufferBuilder = bufferBuilders.crumblingBufferSource() + .getBuffer(ModelBakery.DESTROY_TYPES.get(stage)); - MatrixStack.Entry entry = matrices.peek(); - VertexConsumer transformer = new OverlayVertexConsumer(bufferBuilder, - entry.getPositionMatrix(), entry.getNormalMatrix(), 1.0f); + PoseStack.Pose entry = matrices.last(); + VertexConsumer transformer = new SheetedDecalTextureGenerator(bufferBuilder, + entry.pose(), entry.normal(), 1.0f); - consumer = (layer) -> layer.hasCrumbling() ? VertexConsumers.union(transformer, immediate.getBuffer(layer)) : immediate.getBuffer(layer); + consumer = (layer) -> layer.affectsCrumbling() ? VertexMultiConsumer.create(transformer, immediate.getBuffer(layer)) : immediate.getBuffer(layer); } } dispatcher.render(entity, tickDelta, matrices, consumer); - matrices.pop(); + matrices.popPose(); } // the volume of a section multiplied by the number of sections to be checked at most @@ -384,11 +398,11 @@ public boolean isEntityVisible(Entity entity) { } // Ensure entities with outlines or nametags are always visible - if (this.client.hasOutline(entity) || entity.shouldRenderName()) { + if (this.client.shouldEntityAppearGlowing(entity) || entity.shouldShowName()) { return true; } - Box box = entity.getVisibilityBoundingBox(); + AABB box = entity.getBoundingBoxForCulling(); // bail on very large entities to avoid checking many sections double entityVolume = (box.maxX - box.minX) * (box.maxY - box.minY) * (box.maxZ - box.minZ); @@ -403,17 +417,17 @@ public boolean isEntityVisible(Entity entity) { public boolean isBoxVisible(double x1, double y1, double z1, double x2, double y2, double z2) { // Boxes outside the valid world height will never map to a rendered chunk // Always render these boxes or they'll be culled incorrectly! - if (y2 < this.world.getBottomY() + 0.5D || y1 > this.world.getTopY() - 0.5D) { + if (y2 < this.world.getMinBuildHeight() + 0.5D || y1 > this.world.getMaxBuildHeight() - 0.5D) { return true; } - int minX = ChunkSectionPos.getSectionCoord(x1 - 0.5D); - int minY = ChunkSectionPos.getSectionCoord(y1 - 0.5D); - int minZ = ChunkSectionPos.getSectionCoord(z1 - 0.5D); + int minX = SectionPos.posToSectionCoord(x1 - 0.5D); + int minY = SectionPos.posToSectionCoord(y1 - 0.5D); + int minZ = SectionPos.posToSectionCoord(z1 - 0.5D); - int maxX = ChunkSectionPos.getSectionCoord(x2 + 0.5D); - int maxY = ChunkSectionPos.getSectionCoord(y2 + 0.5D); - int maxZ = ChunkSectionPos.getSectionCoord(z2 + 0.5D); + int maxX = SectionPos.posToSectionCoord(x2 + 0.5D); + int maxY = SectionPos.posToSectionCoord(y2 + 0.5D); + int maxZ = SectionPos.posToSectionCoord(z2 + 0.5D); for (int x = minX; x <= maxX; x++) { for (int z = minZ; z <= maxZ; z++) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderMatrices.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderMatrices.java index 95bfb9042a..8fcb9d4f7c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderMatrices.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderMatrices.java @@ -1,13 +1,13 @@ package me.jellysquid.mods.sodium.client.render.chunk; import com.mojang.blaze3d.systems.RenderSystem; -import net.minecraft.client.util.math.MatrixStack; +import com.mojang.blaze3d.vertex.PoseStack; import org.joml.Matrix4f; import org.joml.Matrix4fc; public record ChunkRenderMatrices(Matrix4fc projection, Matrix4fc modelView) { - public static ChunkRenderMatrices from(MatrixStack stack) { - MatrixStack.Entry entry = stack.peek(); - return new ChunkRenderMatrices(new Matrix4f(RenderSystem.getProjectionMatrix()), new Matrix4f(entry.getPositionMatrix())); + public static ChunkRenderMatrices from(PoseStack stack) { + PoseStack.Pose entry = stack.last(); + return new ChunkRenderMatrices(new Matrix4f(RenderSystem.getProjectionMatrix()), new Matrix4f(entry.pose())); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java index 7037841c2a..76ac297946 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java @@ -16,6 +16,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.lists.ChunkRenderListIterable; import me.jellysquid.mods.sodium.client.render.chunk.lists.ChunkRenderList; import me.jellysquid.mods.sodium.client.render.chunk.region.RenderRegion; +import me.jellysquid.mods.sodium.client.render.chunk.region.RenderRegion.DeviceResources; import me.jellysquid.mods.sodium.client.render.chunk.shader.ChunkShaderBindingPoints; import me.jellysquid.mods.sodium.client.render.chunk.shader.ChunkShaderInterface; import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; @@ -23,8 +24,8 @@ import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexType; import me.jellysquid.mods.sodium.client.render.viewport.CameraTransform; import me.jellysquid.mods.sodium.client.util.BitwiseMath; +import me.jellysquid.mods.sodium.client.util.iterator.ByteIterator; import org.lwjgl.system.MemoryUtil; - import java.util.Iterator; public class DefaultChunkRenderer extends ShaderChunkRenderer { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/NonStoringBuilderPool.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/NonStoringBuilderPool.java index bea289c0c3..360789b6fd 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/NonStoringBuilderPool.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/NonStoringBuilderPool.java @@ -1,33 +1,33 @@ package me.jellysquid.mods.sodium.client.render.chunk; -import net.minecraft.client.render.chunk.BlockBufferBuilderPool; -import net.minecraft.client.render.chunk.BlockBufferBuilderStorage; import org.jetbrains.annotations.Nullable; import java.util.Collections; +import net.minecraft.client.renderer.SectionBufferBuilderPack; +import net.minecraft.client.renderer.SectionBufferBuilderPool; -public class NonStoringBuilderPool extends BlockBufferBuilderPool { +public class NonStoringBuilderPool extends SectionBufferBuilderPool { public NonStoringBuilderPool() { super(Collections.emptyList()); } @Nullable @Override - public BlockBufferBuilderStorage acquire() { + public SectionBufferBuilderPack acquire() { return null; } @Override - public void release(BlockBufferBuilderStorage blockBufferBuilderStorage) { + public void release(SectionBufferBuilderPack blockBufferBuilderStorage) { } @Override - public boolean hasNoAvailableBuilder() { + public boolean isEmpty() { return true; } @Override - public int getAvailableBuilderCount() { + public int getFreeBufferCount() { return 0; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java index a9432ea294..8be293d346 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java @@ -6,10 +6,10 @@ import me.jellysquid.mods.sodium.client.render.chunk.occlusion.VisibilityEncoding; import me.jellysquid.mods.sodium.client.render.chunk.region.RenderRegion; import me.jellysquid.mods.sodium.client.util.task.CancellationToken; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.client.texture.Sprite; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.ChunkSectionPos; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.core.BlockPos; +import net.minecraft.core.SectionPos; +import net.minecraft.world.level.block.entity.BlockEntity; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -46,7 +46,7 @@ public class RenderSection { private int flags = RenderSectionFlags.NONE; private BlockEntity @Nullable[] globalBlockEntities; private BlockEntity @Nullable[] culledBlockEntities; - private Sprite @Nullable[] animatedSprites; + private TextureAtlasSprite @Nullable[] animatedSprites; // Pending Update State @@ -154,8 +154,8 @@ private void clearRenderState() { /** * Returns the chunk section position which this render refers to in the world. */ - public ChunkSectionPos getPosition() { - return ChunkSectionPos.from(this.chunkX, this.chunkY, this.chunkZ); + public SectionPos getPosition() { + return SectionPos.of(this.chunkX, this.chunkY, this.chunkZ); } /** @@ -292,7 +292,7 @@ public long getVisibilityData() { /** * Returns the collection of animated sprites contained by this rendered chunk section. */ - public Sprite @Nullable[] getAnimatedSprites() { + public TextureAtlasSprite @Nullable[] getAnimatedSprites() { return this.animatedSprites; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index 0376e27b95..ed60539db0 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -9,11 +9,13 @@ import it.unimi.dsi.fastutil.objects.ReferenceSet; import it.unimi.dsi.fastutil.objects.ReferenceSets; import me.jellysquid.mods.sodium.client.SodiumClientMod; +import me.jellysquid.mods.sodium.client.gl.arena.GlBufferArena; import me.jellysquid.mods.sodium.client.gl.device.CommandList; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildOutput; import me.jellysquid.mods.sodium.client.render.chunk.compile.executor.ChunkBuilder; import me.jellysquid.mods.sodium.client.render.chunk.compile.executor.ChunkJobResult; +import me.jellysquid.mods.sodium.client.render.chunk.compile.executor.ChunkJobTyped; import me.jellysquid.mods.sodium.client.render.chunk.compile.executor.ChunkJobCollector; import me.jellysquid.mods.sodium.client.render.chunk.compile.tasks.ChunkBuilderMeshingTask; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionInfo; @@ -23,6 +25,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.occlusion.GraphDirection; import me.jellysquid.mods.sodium.client.render.chunk.occlusion.OcclusionCuller; import me.jellysquid.mods.sodium.client.render.chunk.region.RenderRegion; +import me.jellysquid.mods.sodium.client.render.chunk.region.RenderRegion.DeviceResources; import me.jellysquid.mods.sodium.client.render.chunk.region.RenderRegionManager; import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkMeshFormats; @@ -31,18 +34,20 @@ import me.jellysquid.mods.sodium.client.render.viewport.CameraTransform; import me.jellysquid.mods.sodium.client.render.viewport.Viewport; import me.jellysquid.mods.sodium.client.util.MathUtil; +import me.jellysquid.mods.sodium.client.util.iterator.ByteIterator; +import me.jellysquid.mods.sodium.client.util.task.CancellationToken; import me.jellysquid.mods.sodium.client.world.WorldSlice; import me.jellysquid.mods.sodium.client.world.cloned.ChunkRenderContext; import me.jellysquid.mods.sodium.client.world.cloned.ClonedChunkSectionCache; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.render.Camera; -import net.minecraft.client.texture.Sprite; -import net.minecraft.client.world.ClientWorld; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.ChunkSectionPos; -import net.minecraft.util.math.MathHelper; -import net.minecraft.world.chunk.Chunk; -import net.minecraft.world.chunk.ChunkSection; +import net.minecraft.client.Camera; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.core.BlockPos; +import net.minecraft.core.SectionPos; +import net.minecraft.util.Mth; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.LevelChunkSection; import org.apache.commons.lang3.ArrayUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -62,7 +67,7 @@ public class RenderSectionManager { private final ChunkRenderer chunkRenderer; - private final ClientWorld world; + private final ClientLevel world; private final ReferenceSet sectionsWithGlobalEntities = new ReferenceOpenHashSet<>(); @@ -82,7 +87,7 @@ public class RenderSectionManager { private @Nullable BlockPos lastCameraPosition; - public RenderSectionManager(ClientWorld world, int renderDistance, CommandList commandList) { + public RenderSectionManager(ClientLevel world, int renderDistance, CommandList commandList) { this.chunkRenderer = new DefaultChunkRenderer(RenderDevice.INSTANCE, ChunkMeshFormats.COMPACT); this.world = world; @@ -105,7 +110,7 @@ public RenderSectionManager(ClientWorld world, int renderDistance, CommandList c } public void update(Camera camera, Viewport viewport, int frame, boolean spectator) { - this.lastCameraPosition = camera.getBlockPos(); + this.lastCameraPosition = camera.getBlockPosition(); this.createTerrainRenderList(camera, viewport, frame, spectator); @@ -141,14 +146,14 @@ private float getSearchDistance() { private boolean shouldUseOcclusionCulling(Camera camera, boolean spectator) { final boolean useOcclusionCulling; - BlockPos origin = camera.getBlockPos(); + BlockPos origin = camera.getBlockPosition(); if (spectator && this.world.getBlockState(origin) - .isOpaqueFullCube(this.world, origin)) + .isSolidRender(this.world, origin)) { useOcclusionCulling = false; } else { - useOcclusionCulling = MinecraftClient.getInstance().chunkCullingEnabled; + useOcclusionCulling = Minecraft.getInstance().smartCull; } return useOcclusionCulling; } @@ -162,7 +167,7 @@ private void resetRenderLists() { } public void onSectionAdded(int x, int y, int z) { - long key = ChunkSectionPos.asLong(x, y, z); + long key = SectionPos.asLong(x, y, z); if (this.sectionByPosition.containsKey(key)) { return; @@ -175,10 +180,10 @@ public void onSectionAdded(int x, int y, int z) { this.sectionByPosition.put(key, renderSection); - Chunk chunk = this.world.getChunk(x, z); - ChunkSection section = chunk.getSectionArray()[this.world.sectionCoordToIndex(y)]; + ChunkAccess chunk = this.world.getChunk(x, z); + LevelChunkSection section = chunk.getSections()[this.world.getSectionIndexFromSectionY(y)]; - if (section.isEmpty()) { + if (section.hasOnlyAir()) { this.updateSectionInfo(renderSection, BuiltSectionInfo.EMPTY); } else { renderSection.setPendingUpdate(ChunkUpdateType.INITIAL_BUILD); @@ -190,7 +195,7 @@ public void onSectionAdded(int x, int y, int z) { } public void onSectionRemoved(int x, int y, int z) { - RenderSection section = this.sectionByPosition.remove(ChunkSectionPos.asLong(x, y, z)); + RenderSection section = this.sectionByPosition.remove(SectionPos.asLong(x, y, z)); if (section == null) { return; @@ -245,7 +250,7 @@ public void tickVisibleRenders() { continue; } - for (Sprite sprite : sprites) { + for (TextureAtlasSprite sprite : sprites) { SpriteUtil.markSpriteActive(sprite); } } @@ -439,7 +444,7 @@ public void scheduleRebuild(int x, int y, int z, boolean important) { this.sectionCache.invalidate(x, y, z); - RenderSection section = this.sectionByPosition.get(ChunkSectionPos.asLong(x, y, z)); + RenderSection section = this.sectionByPosition.get(SectionPos.asLong(x, y, z)); if (section != null && section.isBuilt()) { ChunkUpdateType pendingUpdate; @@ -458,7 +463,7 @@ public void scheduleRebuild(int x, int y, int z, boolean important) { } } - private static final float NEARBY_REBUILD_DISTANCE = MathHelper.square(16.0f); + private static final float NEARBY_REBUILD_DISTANCE = Mth.square(16.0f); private boolean shouldPrioritizeRebuild(RenderSection section) { return this.lastCameraPosition != null && section.getSquaredDistance(this.lastCameraPosition) < NEARBY_REBUILD_DISTANCE; @@ -475,7 +480,7 @@ private float getEffectiveRenderDistance() { var renderDistance = this.getRenderDistance(); // The fog must be fully opaque in order to skip rendering of chunks behind it - if (!MathHelper.approximatelyEquals(color[3], 1.0f)) { + if (!Mth.equal(color[3], 1.0f)) { return renderDistance; } @@ -511,7 +516,7 @@ private void disconnectNeighborNodes(RenderSection render) { } private RenderSection getRenderSection(int x, int y, int z) { - return this.sectionByPosition.get(ChunkSectionPos.asLong(x, y, z)); + return this.sectionByPosition.get(SectionPos.asLong(x, y, z)); } public Collection getDebugStrings() { @@ -564,13 +569,13 @@ public boolean isSectionBuilt(int x, int y, int z) { } public void onChunkAdded(int x, int z) { - for (int y = this.world.getBottomSectionCoord(); y < this.world.getTopSectionCoord(); y++) { + for (int y = this.world.getMinSection(); y < this.world.getMaxSection(); y++) { this.onSectionAdded(x, y, z); } } public void onChunkRemoved(int x, int z) { - for (int y = this.world.getBottomSectionCoord(); y < this.world.getTopSectionCoord(); y++) { + for (int y = this.world.getMinSection(); y < this.world.getMaxSection(); y++) { this.onSectionRemoved(x, y, z); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ShaderChunkRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ShaderChunkRenderer.java index 955e8efc48..858c0df5b7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ShaderChunkRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ShaderChunkRenderer.java @@ -9,8 +9,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.shader.*; import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkMeshAttribute; import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexType; -import net.minecraft.util.Identifier; - +import net.minecraft.resources.ResourceLocation; import java.util.Map; public abstract class ShaderChunkRenderer implements ChunkRenderer { @@ -43,13 +42,13 @@ private GlProgram createShader(String path, ChunkShaderOpt ShaderConstants constants = options.constants(); GlShader vertShader = ShaderLoader.loadShader(ShaderType.VERTEX, - new Identifier("sodium", path + ".vsh"), constants); + new ResourceLocation("sodium", path + ".vsh"), constants); GlShader fragShader = ShaderLoader.loadShader(ShaderType.FRAGMENT, - new Identifier("sodium", path + ".fsh"), constants); + new ResourceLocation("sodium", path + ".fsh"), constants); try { - return GlProgram.builder(new Identifier("sodium", "chunk_shader")) + return GlProgram.builder(new ResourceLocation("sodium", "chunk_shader")) .attachShader(vertShader) .attachShader(fragShader) .bindAttribute("a_PosId", ChunkShaderBindingPoints.ATTRIBUTE_POSITION_ID) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/SharedQuadIndexBuffer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/SharedQuadIndexBuffer.java index cc2ef5897a..4c0036a235 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/SharedQuadIndexBuffer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/SharedQuadIndexBuffer.java @@ -2,12 +2,12 @@ import me.jellysquid.mods.sodium.client.gl.buffer.GlBuffer; import me.jellysquid.mods.sodium.client.gl.buffer.GlBufferMapFlags; +import me.jellysquid.mods.sodium.client.gl.buffer.GlBufferMapping; import me.jellysquid.mods.sodium.client.gl.buffer.GlBufferUsage; import me.jellysquid.mods.sodium.client.gl.buffer.GlMutableBuffer; import me.jellysquid.mods.sodium.client.gl.device.CommandList; import me.jellysquid.mods.sodium.client.gl.tessellation.GlIndexType; import me.jellysquid.mods.sodium.client.gl.util.EnumBitField; - import java.nio.ByteBuffer; import java.nio.IntBuffer; import java.nio.ShortBuffer; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildContext.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildContext.java index ff915e86c6..4a2f5cd0f1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildContext.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildContext.java @@ -1,18 +1,17 @@ package me.jellysquid.mods.sodium.client.render.chunk.compile; import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexType; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.BlockRenderCache; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.world.ClientWorld; -import net.minecraft.world.World; public class ChunkBuildContext { public final ChunkBuildBuffers buffers; public final BlockRenderCache cache; - public ChunkBuildContext(ClientWorld world, ChunkVertexType vertexType) { + public ChunkBuildContext(ClientLevel world, ChunkVertexType vertexType) { this.buffers = new ChunkBuildBuffers(vertexType); - this.cache = new BlockRenderCache(MinecraftClient.getInstance(), world); + this.cache = new BlockRenderCache(Minecraft.getInstance(), world); } public void cleanup() { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/buffers/BakedChunkModelBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/buffers/BakedChunkModelBuilder.java index 4fdd0f2791..2f0ba5e39b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/buffers/BakedChunkModelBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/buffers/BakedChunkModelBuilder.java @@ -2,8 +2,8 @@ import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.render.chunk.vertex.builder.ChunkMeshBufferBuilder; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionInfo; -import net.minecraft.client.texture.Sprite; public class BakedChunkModelBuilder implements ChunkModelBuilder { private final ChunkMeshBufferBuilder[] vertexBuffers; @@ -20,7 +20,7 @@ public ChunkMeshBufferBuilder getVertexBuffer(ModelQuadFacing facing) { } @Override - public void addSprite(Sprite sprite) { + public void addSprite(TextureAtlasSprite sprite) { this.renderData.addSprite(sprite); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/buffers/ChunkModelBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/buffers/ChunkModelBuilder.java index 42d898ae1e..ce36d0e6fd 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/buffers/ChunkModelBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/buffers/ChunkModelBuilder.java @@ -2,10 +2,10 @@ import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.render.chunk.vertex.builder.ChunkMeshBufferBuilder; -import net.minecraft.client.texture.Sprite; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; public interface ChunkModelBuilder { ChunkMeshBufferBuilder getVertexBuffer(ModelQuadFacing facing); - void addSprite(Sprite sprite); + void addSprite(TextureAtlasSprite sprite); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkBuilder.java index caa547f689..85c2c9491e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkBuilder.java @@ -5,13 +5,14 @@ import me.jellysquid.mods.sodium.client.render.chunk.compile.tasks.ChunkBuilderTask; import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexType; import me.jellysquid.mods.sodium.client.util.task.CancellationToken; -import net.minecraft.client.world.ClientWorld; -import net.minecraft.util.math.MathHelper; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.util.Mth; import org.apache.commons.lang3.Validate; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; @@ -28,7 +29,7 @@ public class ChunkBuilder { private final ChunkBuildContext localContext; - public ChunkBuilder(ClientWorld world, ChunkVertexType vertexType) { + public ChunkBuilder(ClientLevel world, ChunkVertexType vertexType) { int count = getThreadCount(); for (int i = 0; i < count; i++) { @@ -112,7 +113,7 @@ public , OUTPUT> ChunkJobTyped { private final OUTPUT output; @@ -20,7 +20,7 @@ public static ChunkJobResult successfully(OUTPUT output) { } public OUTPUT unwrap() { - if (this.throwable instanceof CrashException crashException) { + if (this.throwable instanceof ReportedException crashException) { // Propagate CrashExceptions directly to provide extra information throw crashException; } else if (this.throwable != null) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockOcclusionCache.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockOcclusionCache.java index 5f39c91fe3..9ff930fd1e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockOcclusionCache.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockOcclusionCache.java @@ -3,13 +3,13 @@ import it.unimi.dsi.fastutil.Hash; import it.unimi.dsi.fastutil.objects.Object2IntLinkedOpenCustomHashMap; import me.jellysquid.mods.sodium.client.util.DirectionUtil; -import net.minecraft.block.BlockState; -import net.minecraft.util.function.BooleanBiFunction; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.util.shape.VoxelShape; -import net.minecraft.util.shape.VoxelShapes; -import net.minecraft.world.BlockView; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.shapes.BooleanOp; +import net.minecraft.world.phys.shapes.Shapes; +import net.minecraft.world.phys.shapes.VoxelShape; public class BlockOcclusionCache { private static final int CACHE_SIZE = 512; @@ -21,7 +21,7 @@ public class BlockOcclusionCache { private final Object2IntLinkedOpenCustomHashMap comparisonLookupTable; private final ShapeComparison cachedComparisonObject = new ShapeComparison(); - private final BlockPos.Mutable cachedPositionObject = new BlockPos.Mutable(); + private final BlockPos.MutableBlockPos cachedPositionObject = new BlockPos.MutableBlockPos(); public BlockOcclusionCache() { this.comparisonLookupTable = new Object2IntLinkedOpenCustomHashMap<>(CACHE_SIZE, 0.5F, new ShapeComparison.ShapeComparisonStrategy()); @@ -35,26 +35,26 @@ public BlockOcclusionCache() { * @param facing The facing direction of the side to check * @return True if the block side facing {@param dir} is not occluded, otherwise false */ - public boolean shouldDrawSide(BlockState selfState, BlockView view, BlockPos selfPos, Direction facing) { - BlockPos.Mutable otherPos = this.cachedPositionObject; - otherPos.set(selfPos.getX() + facing.getOffsetX(), selfPos.getY() + facing.getOffsetY(), selfPos.getZ() + facing.getOffsetZ()); + public boolean shouldDrawSide(BlockState selfState, BlockGetter view, BlockPos selfPos, Direction facing) { + BlockPos.MutableBlockPos otherPos = this.cachedPositionObject; + otherPos.set(selfPos.getX() + facing.getStepX(), selfPos.getY() + facing.getStepY(), selfPos.getZ() + facing.getStepZ()); BlockState otherState = view.getBlockState(otherPos); // Blocks can define special behavior to control whether faces are rendered. // This is mostly used by transparent blocks (Leaves, Glass, etc.) to not render interior faces between blocks // of the same type. - if (selfState.isSideInvisible(otherState, facing)) { + if (selfState.skipRendering(otherState, facing)) { return false; } // If the other block is transparent, then it is unable to hide any geometry. - if (!otherState.isOpaque()) { + if (!otherState.canOcclude()) { return true; } // The cull shape of the block being rendered - VoxelShape selfShape = selfState.getCullingFace(view, selfPos, facing); + VoxelShape selfShape = selfState.getFaceOcclusionShape(view, selfPos, facing); // If the block being rendered has an empty cull shape, intersection tests will always fail if (selfShape.isEmpty()) { @@ -62,7 +62,7 @@ public boolean shouldDrawSide(BlockState selfState, BlockView view, BlockPos sel } // The cull shape of the block neighboring the one being rendered - VoxelShape otherShape = otherState.getCullingFace(view, otherPos, DirectionUtil.getOpposite(facing)); + VoxelShape otherShape = otherState.getFaceOcclusionShape(view, otherPos, DirectionUtil.getOpposite(facing)); // If the other block has an empty cull shape, then it cannot hide any geometry if (otherShape.isEmpty()) { @@ -70,7 +70,7 @@ public boolean shouldDrawSide(BlockState selfState, BlockView view, BlockPos sel } // If both blocks use a full-cube cull shape, then they will always hide the faces between each other - if (selfShape == VoxelShapes.fullCube() && otherShape == VoxelShapes.fullCube()) { + if (selfShape == Shapes.block() && otherShape == Shapes.block()) { return false; } @@ -93,7 +93,7 @@ private boolean lookup(VoxelShape self, VoxelShape other) { } private boolean calculate(ShapeComparison comparison) { - boolean result = VoxelShapes.matchesAnywhere(comparison.self, comparison.other, BooleanBiFunction.ONLY_FIRST); + boolean result = Shapes.joinIsNotEmpty(comparison.self, comparison.other, BooleanOp.ONLY_FIRST); // Remove entries while the table is too large while (this.comparisonLookupTable.size() >= CACHE_SIZE) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderCache.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderCache.java index c8bfd5a131..f666101a99 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderCache.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderCache.java @@ -5,10 +5,9 @@ import me.jellysquid.mods.sodium.client.model.light.data.ArrayLightDataCache; import me.jellysquid.mods.sodium.client.world.WorldSlice; import me.jellysquid.mods.sodium.client.world.cloned.ChunkRenderContext; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.render.block.BlockModels; -import net.minecraft.client.world.ClientWorld; -import net.minecraft.world.World; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.renderer.block.BlockModelShaper; public class BlockRenderCache { private final ArrayLightDataCache lightDataCache; @@ -16,10 +15,10 @@ public class BlockRenderCache { private final BlockRenderer blockRenderer; private final FluidRenderer fluidRenderer; - private final BlockModels blockModels; + private final BlockModelShaper blockModels; private final WorldSlice worldSlice; - public BlockRenderCache(MinecraftClient client, ClientWorld world) { + public BlockRenderCache(Minecraft client, ClientLevel world) { this.worldSlice = new WorldSlice(world); this.lightDataCache = new ArrayLightDataCache(this.worldSlice); @@ -30,10 +29,10 @@ public BlockRenderCache(MinecraftClient client, ClientWorld world) { this.blockRenderer = new BlockRenderer(colorRegistry, lightPipelineProvider); this.fluidRenderer = new FluidRenderer(colorRegistry, lightPipelineProvider); - this.blockModels = client.getBakedModelManager().getBlockModels(); + this.blockModels = client.getModelManager().getBlockModelShaper(); } - public BlockModels getBlockModels() { + public BlockModelShaper getBlockModels() { return this.blockModels; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderContext.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderContext.java index 3554a98405..0fbe2bcc25 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderContext.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderContext.java @@ -1,16 +1,16 @@ package me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline; import me.jellysquid.mods.sodium.client.world.WorldSlice; -import net.minecraft.block.BlockState; -import net.minecraft.client.render.model.BakedModel; -import net.minecraft.util.math.BlockPos; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.state.BlockState; import org.joml.Vector3f; import org.joml.Vector3fc; public class BlockRenderContext { private final WorldSlice world; - private final BlockPos.Mutable pos = new BlockPos.Mutable(); + private final BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(); private final Vector3f origin = new Vector3f(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java index 3b5d32aa09..a67cdc16a3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java @@ -13,24 +13,25 @@ import me.jellysquid.mods.sodium.client.render.chunk.compile.buffers.ChunkModelBuilder; import me.jellysquid.mods.sodium.client.render.chunk.terrain.material.DefaultMaterials; import me.jellysquid.mods.sodium.client.render.chunk.terrain.material.Material; +import me.jellysquid.mods.sodium.client.render.chunk.vertex.builder.ChunkMeshBufferBuilder; import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexEncoder; +import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexEncoder.Vertex; import me.jellysquid.mods.sodium.client.util.DirectionUtil; import net.caffeinemc.mods.sodium.api.util.ColorABGR; -import net.minecraft.block.BlockState; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.render.model.BakedModel; -import net.minecraft.client.render.model.BakedQuad; -import net.minecraft.client.texture.Sprite; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.Vec3d; -import net.minecraft.util.math.random.LocalRandom; -import net.minecraft.util.math.random.Random; - +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.Direction; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.levelgen.SingleThreadedRandomSource; +import net.minecraft.world.phys.Vec3; import java.util.Arrays; import java.util.List; public class BlockRenderer { - private final Random random = new LocalRandom(42L); + private final RandomSource random = new SingleThreadedRandomSource(42L); private final ColorProviderRegistry colorProviderRegistry; private final BlockOcclusionCache occlusionCache; @@ -50,7 +51,7 @@ public BlockRenderer(ColorProviderRegistry colorRegistry, LightPipelineProvider this.lighters = lighters; this.occlusionCache = new BlockOcclusionCache(); - this.useAmbientOcclusion = MinecraftClient.isAmbientOcclusionEnabled(); + this.useAmbientOcclusion = Minecraft.useAmbientOcclusion(); } public void renderModel(BlockRenderContext ctx, ChunkBuildBuffers buffers) { @@ -60,12 +61,12 @@ public void renderModel(BlockRenderContext ctx, ChunkBuildBuffers buffers) { ColorProvider colorizer = this.colorProviderRegistry.getColorProvider(ctx.state().getBlock()); LightPipeline lighter = this.lighters.getLighter(this.getLightingMode(ctx.state(), ctx.model())); - Vec3d renderOffset; + Vec3 renderOffset; - if (ctx.state().hasModelOffset()) { - renderOffset = ctx.state().getModelOffset(ctx.world(), ctx.pos()); + if (ctx.state().hasOffsetFunction()) { + renderOffset = ctx.state().getOffset(ctx.world(), ctx.pos()); } else { - renderOffset = Vec3d.ZERO; + renderOffset = Vec3.ZERO; } for (Direction face : DirectionUtil.ALL_DIRECTIONS) { @@ -94,7 +95,7 @@ private boolean isFaceVisible(BlockRenderContext ctx, Direction face) { return this.occlusionCache.shouldDrawSide(ctx.state(), ctx.world(), ctx.pos(), face); } - private void renderQuadList(BlockRenderContext ctx, Material material, LightPipeline lighter, ColorProvider colorizer, Vec3d offset, + private void renderQuadList(BlockRenderContext ctx, Material material, LightPipeline lighter, ColorProvider colorizer, Vec3 offset, ChunkModelBuilder builder, List quads, Direction cullFace) { // This is a very hot allocation, iterate over it manually @@ -107,7 +108,7 @@ private void renderQuadList(BlockRenderContext ctx, Material material, LightPipe this.writeGeometry(ctx, builder, offset, material, quad, vertexColors, lightData); - Sprite sprite = quad.getSprite(); + TextureAtlasSprite sprite = quad.getSprite(); if (sprite != null) { builder.addSprite(sprite); @@ -136,7 +137,7 @@ private int[] getVertexColors(BlockRenderContext ctx, ColorProvider private void writeGeometry(BlockRenderContext ctx, ChunkModelBuilder builder, - Vec3d offset, + Vec3 offset, Material material, BakedQuadView quad, int[] colors, @@ -151,9 +152,9 @@ private void writeGeometry(BlockRenderContext ctx, int srcIndex = orientation.getVertexIndex(dstIndex); var out = vertices[dstIndex]; - out.x = ctx.origin().x() + quad.getX(srcIndex) + (float) offset.getX(); - out.y = ctx.origin().y() + quad.getY(srcIndex) + (float) offset.getY(); - out.z = ctx.origin().z() + quad.getZ(srcIndex) + (float) offset.getZ(); + out.x = ctx.origin().x() + quad.getX(srcIndex) + (float) offset.x(); + out.y = ctx.origin().y() + quad.getY(srcIndex) + (float) offset.y(); + out.z = ctx.origin().z() + quad.getZ(srcIndex) + (float) offset.z(); out.color = ColorABGR.withAlpha(colors != null ? colors[srcIndex] : 0xFFFFFFFF, light.br[srcIndex]); @@ -168,7 +169,7 @@ private void writeGeometry(BlockRenderContext ctx, } private LightMode getLightingMode(BlockState state, BakedModel model) { - if (this.useAmbientOcclusion && model.useAmbientOcclusion() && state.getLuminance() == 0) { + if (this.useAmbientOcclusion && model.useAmbientOcclusion() && state.getLightEmission() == 0) { return LightMode.SMOOTH; } else { return LightMode.FLAT; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java index cfece30547..4a2a3a1fc9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java @@ -16,27 +16,30 @@ import me.jellysquid.mods.sodium.client.render.chunk.compile.buffers.ChunkModelBuilder; import me.jellysquid.mods.sodium.client.render.chunk.terrain.material.DefaultMaterials; import me.jellysquid.mods.sodium.client.render.chunk.terrain.material.Material; +import me.jellysquid.mods.sodium.client.render.chunk.vertex.builder.ChunkMeshBufferBuilder; import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexEncoder; +import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexEncoder.Vertex; import me.jellysquid.mods.sodium.client.world.WorldSlice; import me.jellysquid.mods.sodium.client.util.DirectionUtil; import net.caffeinemc.mods.sodium.api.util.ColorABGR; import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandler; import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandlerRegistry; -import net.minecraft.block.BlockState; -import net.minecraft.block.SideShapeType; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.texture.Sprite; -import net.minecraft.fluid.Fluid; -import net.minecraft.fluid.FluidState; -import net.minecraft.fluid.Fluids; -import net.minecraft.registry.tag.FluidTags; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.Vec3d; -import net.minecraft.util.shape.VoxelShape; -import net.minecraft.util.shape.VoxelShapes; -import net.minecraft.world.BlockRenderView; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.core.BlockPos; +import net.minecraft.core.BlockPos.MutableBlockPos; +import net.minecraft.core.Direction; +import net.minecraft.tags.FluidTags; +import net.minecraft.util.Mth; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.SupportType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.Fluid; +import net.minecraft.world.level.material.FluidState; +import net.minecraft.world.level.material.Fluids; +import net.minecraft.world.phys.Vec3; +import net.minecraft.world.phys.shapes.Shapes; +import net.minecraft.world.phys.shapes.VoxelShape; import org.apache.commons.lang3.mutable.MutableFloat; import org.apache.commons.lang3.mutable.MutableInt; @@ -45,7 +48,7 @@ public class FluidRenderer { // TODO: move fluid rendering to a separate render pass and control glPolygonOffset and glDepthFunc to fix this properly private static final float EPSILON = 0.001f; - private final BlockPos.Mutable scratchPos = new BlockPos.Mutable(); + private final BlockPos.MutableBlockPos scratchPos = new BlockPos.MutableBlockPos(); private final MutableFloat scratchHeight = new MutableFloat(0); private final MutableInt scratchSamples = new MutableInt(); @@ -66,35 +69,35 @@ public FluidRenderer(ColorProviderRegistry colorProviderRegistry, LightPipelineP this.colorProviderRegistry = colorProviderRegistry; } - private boolean isFluidOccluded(BlockRenderView world, int x, int y, int z, Direction dir, Fluid fluid) { + private boolean isFluidOccluded(BlockAndTintGetter world, int x, int y, int z, Direction dir, Fluid fluid) { BlockPos pos = this.scratchPos.set(x, y, z); BlockState blockState = world.getBlockState(pos); - BlockPos adjPos = this.scratchPos.set(x + dir.getOffsetX(), y + dir.getOffsetY(), z + dir.getOffsetZ()); + BlockPos adjPos = this.scratchPos.set(x + dir.getStepX(), y + dir.getStepY(), z + dir.getStepZ()); - if (blockState.isOpaque()) { - return world.getFluidState(adjPos).getFluid().matchesType(fluid) || blockState.isSideSolid(world, pos, dir, SideShapeType.FULL); + if (blockState.canOcclude()) { + return world.getFluidState(adjPos).getType().isSame(fluid) || blockState.isFaceSturdy(world, pos, dir, SupportType.FULL); } - return world.getFluidState(adjPos).getFluid().matchesType(fluid); + return world.getFluidState(adjPos).getType().isSame(fluid); } - private boolean isSideExposed(BlockRenderView world, int x, int y, int z, Direction dir, float height) { - BlockPos pos = this.scratchPos.set(x + dir.getOffsetX(), y + dir.getOffsetY(), z + dir.getOffsetZ()); + private boolean isSideExposed(BlockAndTintGetter world, int x, int y, int z, Direction dir, float height) { + BlockPos pos = this.scratchPos.set(x + dir.getStepX(), y + dir.getStepY(), z + dir.getStepZ()); BlockState blockState = world.getBlockState(pos); - if (blockState.isOpaque()) { - VoxelShape shape = blockState.getCullingShape(world, pos); + if (blockState.canOcclude()) { + VoxelShape shape = blockState.getOcclusionShape(world, pos); // Hoist these checks to avoid allocating the shape below - if (shape == VoxelShapes.fullCube()) { + if (shape == Shapes.block()) { // The top face always be inset, so if the shape above is a full cube it can't possibly occlude return dir == Direction.UP; } else if (shape.isEmpty()) { return true; } - VoxelShape threshold = VoxelShapes.cuboid(0.0D, 0.0D, 0.0D, 1.0D, height, 1.0D); + VoxelShape threshold = Shapes.box(0.0D, 0.0D, 0.0D, 1.0D, height, 1.0D); - return !VoxelShapes.isSideCovered(threshold, shape, dir); + return !Shapes.blockOccudes(threshold, shape, dir); } return true; @@ -108,7 +111,7 @@ public void render(WorldSlice world, FluidState fluidState, BlockPos blockPos, B int posY = blockPos.getY(); int posZ = blockPos.getZ(); - Fluid fluid = fluidState.getFluid(); + Fluid fluid = fluidState.getType(); boolean sfUp = this.isFluidOccluded(world, posX, posY, posZ, Direction.UP, fluid); boolean sfDown = this.isFluidOccluded(world, posX, posY, posZ, Direction.DOWN, fluid) || @@ -122,12 +125,12 @@ public void render(WorldSlice world, FluidState fluidState, BlockPos blockPos, B return; } - boolean isWater = fluidState.isIn(FluidTags.WATER); + boolean isWater = fluidState.is(FluidTags.WATER); final FluidRenderHandler handler = getFluidRenderHandler(fluidState); final ColorProvider colorProvider = this.getColorProvider(fluid, handler); - Sprite[] sprites = handler.getFluidSprites(world, blockPos, fluidState); + TextureAtlasSprite[] sprites = handler.getFluidSprites(world, blockPos, fluidState); float fluidHeight = this.fluidHeight(world, fluid, blockPos, Direction.UP); float northWestHeight, southWestHeight, southEastHeight, northEastHeight; @@ -137,11 +140,11 @@ public void render(WorldSlice world, FluidState fluidState, BlockPos blockPos, B southEastHeight = 1.0f; northEastHeight = 1.0f; } else { - var scratchPos = new BlockPos.Mutable(); - float heightNorth = this.fluidHeight(world, fluid, scratchPos.set(blockPos, Direction.NORTH), Direction.NORTH); - float heightSouth = this.fluidHeight(world, fluid, scratchPos.set(blockPos, Direction.SOUTH), Direction.SOUTH); - float heightEast = this.fluidHeight(world, fluid, scratchPos.set(blockPos, Direction.EAST), Direction.EAST); - float heightWest = this.fluidHeight(world, fluid, scratchPos.set(blockPos, Direction.WEST), Direction.WEST); + var scratchPos = new BlockPos.MutableBlockPos(); + float heightNorth = this.fluidHeight(world, fluid, scratchPos.setWithOffset(blockPos, Direction.NORTH), Direction.NORTH); + float heightSouth = this.fluidHeight(world, fluid, scratchPos.setWithOffset(blockPos, Direction.SOUTH), Direction.SOUTH); + float heightEast = this.fluidHeight(world, fluid, scratchPos.setWithOffset(blockPos, Direction.EAST), Direction.EAST); + float heightWest = this.fluidHeight(world, fluid, scratchPos.setWithOffset(blockPos, Direction.WEST), Direction.WEST); northWestHeight = this.fluidCornerHeight(world, fluid, fluidHeight, heightNorth, heightWest, scratchPos.set(blockPos) .move(Direction.NORTH) .move(Direction.WEST)); @@ -159,7 +162,7 @@ public void render(WorldSlice world, FluidState fluidState, BlockPos blockPos, B final ModelQuadViewMutable quad = this.quad; - LightMode lightMode = isWater && MinecraftClient.isAmbientOcclusionEnabled() ? LightMode.SMOOTH : LightMode.FLAT; + LightMode lightMode = isWater && Minecraft.useAmbientOcclusion() ? LightMode.SMOOTH : LightMode.FLAT; LightPipeline lighter = this.lighters.getLighter(lightMode); quad.setFlags(0); @@ -170,9 +173,9 @@ public void render(WorldSlice world, FluidState fluidState, BlockPos blockPos, B southEastHeight -= EPSILON; northEastHeight -= EPSILON; - Vec3d velocity = fluidState.getVelocity(world, blockPos); + Vec3 velocity = fluidState.getFlow(world, blockPos); - Sprite sprite; + TextureAtlasSprite sprite; ModelQuadFacing facing; float u1, u2, u3, u4; float v1, v2, v3, v4; @@ -180,42 +183,42 @@ public void render(WorldSlice world, FluidState fluidState, BlockPos blockPos, B if (velocity.x == 0.0D && velocity.z == 0.0D) { sprite = sprites[0]; facing = ModelQuadFacing.POS_Y; - u1 = sprite.getFrameU(0.0f); - v1 = sprite.getFrameV(0.0f); + u1 = sprite.getU(0.0f); + v1 = sprite.getV(0.0f); u2 = u1; - v2 = sprite.getFrameV(1.0f); - u3 = sprite.getFrameU(1.0f); + v2 = sprite.getV(1.0f); + u3 = sprite.getU(1.0f); v3 = v2; u4 = u3; v4 = v1; } else { sprite = sprites[1]; facing = ModelQuadFacing.UNASSIGNED; - float dir = (float) MathHelper.atan2(velocity.z, velocity.x) - (1.5707964f); - float sin = MathHelper.sin(dir) * 0.25F; - float cos = MathHelper.cos(dir) * 0.25F; - u1 = sprite.getFrameU(0.5F + (-cos - sin)); - v1 = sprite.getFrameV(0.5F + -cos + sin); - u2 = sprite.getFrameU(0.5F + -cos + sin); - v2 = sprite.getFrameV(0.5F + cos + sin); - u3 = sprite.getFrameU(0.5F + cos + sin); - v3 = sprite.getFrameV(0.5F + (cos - sin)); - u4 = sprite.getFrameU(0.5F + (cos - sin)); - v4 = sprite.getFrameV(0.5F + (-cos - sin)); + float dir = (float) Mth.atan2(velocity.z, velocity.x) - (1.5707964f); + float sin = Mth.sin(dir) * 0.25F; + float cos = Mth.cos(dir) * 0.25F; + u1 = sprite.getU(0.5F + (-cos - sin)); + v1 = sprite.getV(0.5F + -cos + sin); + u2 = sprite.getU(0.5F + -cos + sin); + v2 = sprite.getV(0.5F + cos + sin); + u3 = sprite.getU(0.5F + cos + sin); + v3 = sprite.getV(0.5F + (cos - sin)); + u4 = sprite.getU(0.5F + (cos - sin)); + v4 = sprite.getV(0.5F + (-cos - sin)); } float uAvg = (u1 + u2 + u3 + u4) / 4.0F; float vAvg = (v1 + v2 + v3 + v4) / 4.0F; - float s3 = sprites[0].getAnimationFrameDelta(); + float s3 = sprites[0].uvShrinkRatio(); - u1 = MathHelper.lerp(s3, u1, uAvg); - u2 = MathHelper.lerp(s3, u2, uAvg); - u3 = MathHelper.lerp(s3, u3, uAvg); - u4 = MathHelper.lerp(s3, u4, uAvg); - v1 = MathHelper.lerp(s3, v1, vAvg); - v2 = MathHelper.lerp(s3, v2, vAvg); - v3 = MathHelper.lerp(s3, v3, vAvg); - v4 = MathHelper.lerp(s3, v4, vAvg); + u1 = Mth.lerp(s3, u1, uAvg); + u2 = Mth.lerp(s3, u2, uAvg); + u3 = Mth.lerp(s3, u3, uAvg); + u4 = Mth.lerp(s3, u4, uAvg); + v1 = Mth.lerp(s3, v1, vAvg); + v2 = Mth.lerp(s3, v2, vAvg); + v3 = Mth.lerp(s3, v3, vAvg); + v4 = Mth.lerp(s3, v4, vAvg); quad.setSprite(sprite); @@ -227,7 +230,7 @@ public void render(WorldSlice world, FluidState fluidState, BlockPos blockPos, B this.updateQuad(quad, world, blockPos, lighter, Direction.UP, 1.0F, colorProvider, fluidState); this.writeQuad(meshBuilder, material, offset, quad, facing, false); - if (fluidState.canFlowTo(world, this.scratchPos.set(posX, posY + 1, posZ))) { + if (fluidState.shouldRenderBackwardUpFace(world, this.scratchPos.set(posX, posY + 1, posZ))) { this.writeQuad(meshBuilder, material, offset, quad, ModelQuadFacing.NEG_Y, true); @@ -236,12 +239,12 @@ public void render(WorldSlice world, FluidState fluidState, BlockPos blockPos, B } if (!sfDown) { - Sprite sprite = sprites[0]; + TextureAtlasSprite sprite = sprites[0]; - float minU = sprite.getMinU(); - float maxU = sprite.getMaxU(); - float minV = sprite.getMinV(); - float maxV = sprite.getMaxV(); + float minU = sprite.getU0(); + float maxU = sprite.getU1(); + float minV = sprite.getV0(); + float maxV = sprite.getV1(); quad.setSprite(sprite); setVertex(quad, 0, 0.0f, yOffset, 1.0F, minU, maxV); @@ -315,11 +318,11 @@ public void render(WorldSlice world, FluidState fluidState, BlockPos blockPos, B } if (this.isSideExposed(world, posX, posY, posZ, dir, Math.max(c1, c2))) { - int adjX = posX + dir.getOffsetX(); - int adjY = posY + dir.getOffsetY(); - int adjZ = posZ + dir.getOffsetZ(); + int adjX = posX + dir.getStepX(); + int adjY = posY + dir.getStepY(); + int adjZ = posZ + dir.getStepZ(); - Sprite sprite = sprites[1]; + TextureAtlasSprite sprite = sprites[1]; boolean isOverlay = false; @@ -333,11 +336,11 @@ public void render(WorldSlice world, FluidState fluidState, BlockPos blockPos, B } } - float u1 = sprite.getFrameU(0.0F); - float u2 = sprite.getFrameU(0.5F); - float v1 = sprite.getFrameV((1.0F - c1) * 0.5F); - float v2 = sprite.getFrameV((1.0F - c2) * 0.5F); - float v3 = sprite.getFrameV(0.5F); + float u1 = sprite.getU(0.0F); + float u2 = sprite.getU(0.5F); + float v1 = sprite.getV((1.0F - c1) * 0.5F); + float v2 = sprite.getV((1.0F - c2) * 0.5F); + float v3 = sprite.getV(0.5F); quad.setSprite(sprite); @@ -372,11 +375,11 @@ private ColorProvider getColorProvider(Fluid fluid, FluidRenderHandl } private static FluidRenderHandler getFluidRenderHandler(FluidState fluidState) { - FluidRenderHandler handler = FluidRenderHandlerRegistry.INSTANCE.get(fluidState.getFluid()); + FluidRenderHandler handler = FluidRenderHandlerRegistry.INSTANCE.get(fluidState.getType()); // Match the vanilla FluidRenderer's behavior if the handler is null if (handler == null) { - boolean isLava = fluidState.isIn(FluidTags.LAVA); + boolean isLava = fluidState.is(FluidTags.LAVA); handler = FluidRenderHandlerRegistry.INSTANCE.get(isLava ? Fluids.LAVA : Fluids.WATER); } return handler; @@ -412,7 +415,7 @@ private void writeQuad(ChunkModelBuilder builder, Material material, BlockPos of out.light = this.quadLightData.lm[i]; } - Sprite sprite = quad.getSprite(); + TextureAtlasSprite sprite = quad.getSprite(); if (sprite != null) { builder.addSprite(sprite); @@ -430,7 +433,7 @@ private static void setVertex(ModelQuadViewMutable quad, int i, float x, float y quad.setTexV(i, v); } - private float fluidCornerHeight(BlockRenderView world, Fluid fluid, float fluidHeight, float fluidHeightX, float fluidHeightY, BlockPos blockPos) { + private float fluidCornerHeight(BlockAndTintGetter world, Fluid fluid, float fluidHeight, float fluidHeightX, float fluidHeightY, BlockPos blockPos) { if (fluidHeightY >= 1.0f || fluidHeightX >= 1.0f) { return 1.0f; } @@ -466,17 +469,17 @@ private void modifyHeight(MutableFloat totalHeight, MutableInt samples, float ta } } - private float fluidHeight(BlockRenderView world, Fluid fluid, BlockPos blockPos, Direction direction) { + private float fluidHeight(BlockAndTintGetter world, Fluid fluid, BlockPos blockPos, Direction direction) { BlockState blockState = world.getBlockState(blockPos); FluidState fluidState = blockState.getFluidState(); - if (fluid.matchesType(fluidState.getFluid())) { - FluidState fluidStateUp = world.getFluidState(blockPos.up()); + if (fluid.isSame(fluidState.getType())) { + FluidState fluidStateUp = world.getFluidState(blockPos.above()); - if (fluid.matchesType(fluidStateUp.getFluid())) { + if (fluid.isSame(fluidStateUp.getType())) { return 1.0f; } else { - return fluidState.getHeight(); + return fluidState.getOwnHeight(); } } if (!blockState.isSolid()) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java index ce40765408..6505904450 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java @@ -14,19 +14,18 @@ import me.jellysquid.mods.sodium.client.util.task.CancellationToken; import me.jellysquid.mods.sodium.client.world.WorldSlice; import me.jellysquid.mods.sodium.client.world.cloned.ChunkRenderContext; -import net.minecraft.block.BlockRenderType; -import net.minecraft.block.BlockState; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.render.block.entity.BlockEntityRenderer; -import net.minecraft.client.render.chunk.ChunkOcclusionDataBuilder; -import net.minecraft.client.render.model.BakedModel; -import net.minecraft.fluid.FluidState; -import net.minecraft.util.crash.CrashException; -import net.minecraft.util.crash.CrashReport; -import net.minecraft.util.crash.CrashReportSection; -import net.minecraft.util.math.BlockPos; - +import net.minecraft.CrashReport; +import net.minecraft.CrashReportCategory; +import net.minecraft.ReportedException; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; +import net.minecraft.client.renderer.chunk.VisGraph; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.RenderShape; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.FluidState; import java.util.Map; /** @@ -51,7 +50,7 @@ public ChunkBuilderMeshingTask(RenderSection render, ChunkRenderContext renderCo @Override public ChunkBuildOutput execute(ChunkBuildContext buildContext, CancellationToken cancellationToken) { BuiltSectionInfo.Builder renderData = new BuiltSectionInfo.Builder(); - ChunkOcclusionDataBuilder occluder = new ChunkOcclusionDataBuilder(); + VisGraph occluder = new VisGraph(); ChunkBuildBuffers buffers = buildContext.buffers; buffers.init(renderData, this.render.getSectionIndex()); @@ -70,8 +69,8 @@ public ChunkBuildOutput execute(ChunkBuildContext buildContext, CancellationToke int maxZ = minZ + 16; // Initialise with minX/minY/minZ so initial getBlockState crash context is correct - BlockPos.Mutable blockPos = new BlockPos.Mutable(minX, minY, minZ); - BlockPos.Mutable modelOffset = new BlockPos.Mutable(); + BlockPos.MutableBlockPos blockPos = new BlockPos.MutableBlockPos(minX, minY, minZ); + BlockPos.MutableBlockPos modelOffset = new BlockPos.MutableBlockPos(); BlockRenderContext context = new BlockRenderContext(slice); @@ -92,11 +91,11 @@ public ChunkBuildOutput execute(ChunkBuildContext buildContext, CancellationToke blockPos.set(x, y, z); modelOffset.set(x & 15, y & 15, z & 15); - if (blockState.getRenderType() == BlockRenderType.MODEL) { + if (blockState.getRenderShape() == RenderShape.MODEL) { BakedModel model = cache.getBlockModels() - .getModel(blockState); + .getBlockModel(blockState); - long seed = blockState.getRenderingSeed(blockPos); + long seed = blockState.getSeed(blockPos); context.update(blockPos, modelOffset, blockState, model, seed); cache.getBlockRenderer() @@ -113,26 +112,26 @@ public ChunkBuildOutput execute(ChunkBuildContext buildContext, CancellationToke BlockEntity entity = slice.getBlockEntity(blockPos); if (entity != null) { - BlockEntityRenderer renderer = MinecraftClient.getInstance().getBlockEntityRenderDispatcher().get(entity); + BlockEntityRenderer renderer = Minecraft.getInstance().getBlockEntityRenderDispatcher().getRenderer(entity); if (renderer != null) { - renderData.addBlockEntity(entity, !renderer.rendersOutsideBoundingBox(entity)); + renderData.addBlockEntity(entity, !renderer.shouldRenderOffScreen(entity)); } } } - if (blockState.isOpaqueFullCube(slice, blockPos)) { - occluder.markClosed(blockPos); + if (blockState.isSolidRender(slice, blockPos)) { + occluder.setOpaque(blockPos); } } } } - } catch (CrashException ex) { + } catch (ReportedException ex) { // Propagate existing crashes (add context) throw fillCrashInfo(ex.getReport(), slice, blockPos); } catch (Exception ex) { // Create a new crash report for other exceptions (e.g. thrown in getQuads) - throw fillCrashInfo(CrashReport.create(ex, "Encountered exception while building chunk meshes"), slice, blockPos); + throw fillCrashInfo(CrashReport.forThrowable(ex, "Encountered exception while building chunk meshes"), slice, blockPos); } Map meshes = new Reference2ReferenceOpenHashMap<>(); @@ -146,25 +145,25 @@ public ChunkBuildOutput execute(ChunkBuildContext buildContext, CancellationToke } } - renderData.setOcclusionData(occluder.build()); + renderData.setOcclusionData(occluder.resolve()); return new ChunkBuildOutput(this.render, renderData.build(), meshes, this.buildTime); } - private CrashException fillCrashInfo(CrashReport report, WorldSlice slice, BlockPos pos) { - CrashReportSection crashReportSection = report.addElement("Block being rendered", 1); + private ReportedException fillCrashInfo(CrashReport report, WorldSlice slice, BlockPos pos) { + CrashReportCategory crashReportSection = report.addCategory("Block being rendered", 1); BlockState state = null; try { state = slice.getBlockState(pos); } catch (Exception ignored) {} - CrashReportSection.addBlockInfo(crashReportSection, slice, pos, state); + CrashReportCategory.populateBlockDetails(crashReportSection, slice, pos, state); - crashReportSection.add("Chunk section", this.render); + crashReportSection.setDetail("Chunk section", this.render); if (this.renderContext != null) { - crashReportSection.add("Render context volume", this.renderContext.getVolume()); + crashReportSection.setDetail("Render context volume", this.renderContext.getVolume()); } - return new CrashException(report); + return new ReportedException(report); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/BuiltSectionInfo.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/BuiltSectionInfo.java index 1e764cc48c..3f4eaaf8ba 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/BuiltSectionInfo.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/BuiltSectionInfo.java @@ -5,10 +5,10 @@ import me.jellysquid.mods.sodium.client.render.chunk.occlusion.VisibilityEncoding; import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; import me.jellysquid.mods.sodium.client.render.texture.SpriteUtil; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.client.render.chunk.ChunkOcclusionData; -import net.minecraft.client.texture.Sprite; -import net.minecraft.util.math.Direction; +import net.minecraft.client.renderer.chunk.VisibilitySet; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.entity.BlockEntity; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -27,16 +27,16 @@ public class BuiltSectionInfo { public final BlockEntity @Nullable[] globalBlockEntities; public final BlockEntity @Nullable[] culledBlockEntities; - public final Sprite @Nullable[] animatedSprites; + public final TextureAtlasSprite @Nullable[] animatedSprites; private BuiltSectionInfo(@NotNull Collection blockRenderPasses, @NotNull Collection globalBlockEntities, @NotNull Collection culledBlockEntities, - @NotNull Collection animatedSprites, - @NotNull ChunkOcclusionData occlusionData) { + @NotNull Collection animatedSprites, + @NotNull VisibilitySet occlusionData) { this.globalBlockEntities = toArray(globalBlockEntities, BlockEntity[]::new); this.culledBlockEntities = toArray(culledBlockEntities, BlockEntity[]::new); - this.animatedSprites = toArray(animatedSprites, Sprite[]::new); + this.animatedSprites = toArray(animatedSprites, TextureAtlasSprite[]::new); int flags = 0; @@ -61,15 +61,15 @@ public static class Builder { private final List blockRenderPasses = new ArrayList<>(); private final List globalBlockEntities = new ArrayList<>(); private final List culledBlockEntities = new ArrayList<>(); - private final Set animatedSprites = new ObjectOpenHashSet<>(); + private final Set animatedSprites = new ObjectOpenHashSet<>(); - private ChunkOcclusionData occlusionData; + private VisibilitySet occlusionData; public void addRenderPass(TerrainRenderPass pass) { this.blockRenderPasses.add(pass); } - public void setOcclusionData(ChunkOcclusionData data) { + public void setOcclusionData(VisibilitySet data) { this.occlusionData = data; } @@ -78,7 +78,7 @@ public void setOcclusionData(ChunkOcclusionData data) { * before rendering as necessary. * @param sprite The sprite */ - public void addSprite(Sprite sprite) { + public void addSprite(TextureAtlasSprite sprite) { if (SpriteUtil.hasAnimation(sprite)) { this.animatedSprites.add(sprite); } @@ -99,8 +99,8 @@ public BuiltSectionInfo build() { } private static BuiltSectionInfo createEmptyData() { - ChunkOcclusionData occlusionData = new ChunkOcclusionData(); - occlusionData.addOpenEdgeFaces(EnumSet.allOf(Direction.class)); + VisibilitySet occlusionData = new VisibilitySet(); + occlusionData.add(EnumSet.allOf(Direction.class)); BuiltSectionInfo.Builder meshInfo = new BuiltSectionInfo.Builder(); meshInfo.setOcclusionData(occlusionData); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java index 8deee78c21..8427ceb1bf 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java @@ -4,7 +4,6 @@ import me.jellysquid.mods.sodium.client.gl.util.VertexRange; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.render.chunk.region.RenderRegion; - import java.util.Arrays; public class SectionRenderDataStorage { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/map/ChunkTracker.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/map/ChunkTracker.java index 7d7bdfeadd..8382be72dd 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/map/ChunkTracker.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/map/ChunkTracker.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.render.chunk.map; import it.unimi.dsi.fastutil.longs.*; -import net.minecraft.util.math.ChunkPos; +import net.minecraft.world.level.ChunkPos; public class ChunkTracker implements ClientChunkEventListener { private final Long2IntOpenHashMap chunkStatus = new Long2IntOpenHashMap(); @@ -26,7 +26,7 @@ public void updateLoadDistance(int loadDistance) { @Override public void onChunkStatusAdded(int x, int z, int flags) { - var key = ChunkPos.toLong(x, z); + var key = ChunkPos.asLong(x, z); var prev = this.chunkStatus.get(key); var cur = prev | flags; @@ -42,7 +42,7 @@ public void onChunkStatusAdded(int x, int z, int flags) { @Override public void onChunkStatusRemoved(int x, int z, int flags) { - var key = ChunkPos.toLong(x, z); + var key = ChunkPos.asLong(x, z); var prev = this.chunkStatus.get(key); int cur = prev & ~flags; @@ -69,13 +69,13 @@ private void updateNeighbors(int x, int z) { } private void updateMerged(int x, int z) { - long key = ChunkPos.toLong(x, z); + long key = ChunkPos.asLong(x, z); int flags = this.chunkStatus.get(key); for (int ox = -1; ox <= 1; ox++) { for (int oz = -1; oz <= 1; oz++) { - flags &= this.chunkStatus.get(ChunkPos.toLong(ox + x, oz + z)); + flags &= this.chunkStatus.get(ChunkPos.asLong(ox + x, oz + z)); } } @@ -108,8 +108,8 @@ public static void forEachChunk(LongCollection queue, ChunkEventHandler handler) while (iterator.hasNext()) { var pos = iterator.nextLong(); - var x = ChunkPos.getPackedX(pos); - var z = ChunkPos.getPackedZ(pos); + var x = ChunkPos.getX(pos); + var z = ChunkPos.getZ(pos); handler.apply(x, z); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/map/ChunkTrackerHolder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/map/ChunkTrackerHolder.java index ec5ade380e..02db46267d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/map/ChunkTrackerHolder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/map/ChunkTrackerHolder.java @@ -1,9 +1,9 @@ package me.jellysquid.mods.sodium.client.render.chunk.map; -import net.minecraft.client.world.ClientWorld; +import net.minecraft.client.multiplayer.ClientLevel; public interface ChunkTrackerHolder { - static ChunkTracker get(ClientWorld world) { + static ChunkTracker get(ClientLevel world) { return ((ChunkTrackerHolder) world).sodium$getTracker(); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/occlusion/GraphDirection.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/occlusion/GraphDirection.java index 200363b321..0695fcc865 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/occlusion/GraphDirection.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/occlusion/GraphDirection.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.render.chunk.occlusion; -import net.minecraft.util.math.Direction; +import net.minecraft.core.Direction; public class GraphDirection { public static final int DOWN = 0; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/occlusion/OcclusionCuller.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/occlusion/OcclusionCuller.java index be13b962f9..62f2a360bf 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/occlusion/OcclusionCuller.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/occlusion/OcclusionCuller.java @@ -7,18 +7,18 @@ import me.jellysquid.mods.sodium.client.util.collections.DoubleBufferedQueue; import me.jellysquid.mods.sodium.client.util.collections.ReadQueue; import me.jellysquid.mods.sodium.client.util.collections.WriteQueue; -import net.minecraft.util.math.ChunkSectionPos; -import net.minecraft.util.math.MathHelper; -import net.minecraft.world.World; +import net.minecraft.core.SectionPos; +import net.minecraft.util.Mth; +import net.minecraft.world.level.Level; import org.jetbrains.annotations.NotNull; public class OcclusionCuller { private final Long2ReferenceMap sections; - private final World world; + private final Level world; private final DoubleBufferedQueue queue = new DoubleBufferedQueue<>(); - public OcclusionCuller(Long2ReferenceMap sections, World world) { + public OcclusionCuller(Long2ReferenceMap sections, Level world) { this.sections = sections; this.world = world; } @@ -135,7 +135,7 @@ private static void visitNode(final WriteQueue queue, @NotNull Re render.addIncomingDirections(incoming); } - private static int getOutwardDirections(ChunkSectionPos origin, RenderSection section) { + private static int getOutwardDirections(SectionPos origin, RenderSection section) { int planes = 0; planes |= section.getChunkX() <= origin.getX() ? 1 << GraphDirection.WEST : 0; @@ -195,14 +195,14 @@ private void init(Visitor visitor, { var origin = viewport.getChunkCoord(); - if (origin.getY() < this.world.getBottomSectionCoord()) { + if (origin.getY() < this.world.getMinSection()) { // below the world this.initOutsideWorldHeight(queue, viewport, searchDistance, frame, - this.world.getBottomSectionCoord(), GraphDirection.DOWN); - } else if (origin.getY() >= this.world.getTopSectionCoord()) { + this.world.getMinSection(), GraphDirection.DOWN); + } else if (origin.getY() >= this.world.getMaxSection()) { // above the world this.initOutsideWorldHeight(queue, viewport, searchDistance, frame, - this.world.getTopSectionCoord() - 1, GraphDirection.UP); + this.world.getMaxSection() - 1, GraphDirection.UP); } else { this.initWithinWorld(visitor, queue, viewport, useOcclusionCulling, frame); } @@ -246,7 +246,7 @@ private void initOutsideWorldHeight(WriteQueue queue, int direction) { var origin = viewport.getChunkCoord(); - var radius = MathHelper.floor(searchDistance / 16.0f); + var radius = Mth.floor(searchDistance / 16.0f); // Layer 0 this.tryVisitNode(queue, origin.getX(), height, origin.getZ(), direction, frame, viewport); @@ -301,7 +301,7 @@ private void tryVisitNode(WriteQueue queue, int x, int y, int z, } private RenderSection getRenderSection(int x, int y, int z) { - return this.sections.get(ChunkSectionPos.asLong(x, y, z)); + return this.sections.get(SectionPos.asLong(x, y, z)); } public interface Visitor { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/occlusion/VisibilityEncoding.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/occlusion/VisibilityEncoding.java index 28a2ed6f1b..3072927fa7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/occlusion/VisibilityEncoding.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/occlusion/VisibilityEncoding.java @@ -1,18 +1,18 @@ package me.jellysquid.mods.sodium.client.render.chunk.occlusion; -import net.minecraft.client.render.chunk.ChunkOcclusionData; +import net.minecraft.client.renderer.chunk.VisibilitySet; import org.jetbrains.annotations.NotNull; public class VisibilityEncoding { public static final long NULL = 0L; - public static long encode(@NotNull ChunkOcclusionData occlusionData) { + public static long encode(@NotNull VisibilitySet occlusionData) { long visibilityData = 0; for (int from = 0; from < GraphDirection.COUNT; from++) { for (int to = 0; to < GraphDirection.COUNT; to++) { - if (occlusionData.isVisibleThrough(GraphDirection.toEnum(from), GraphDirection.toEnum(to))) { + if (occlusionData.visibilityBetween(GraphDirection.toEnum(from), GraphDirection.toEnum(to))) { visibilityData |= 1L << bit(from, to); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java index e41da2387e..b7da3b35fd 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java @@ -12,7 +12,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkMeshFormats; import me.jellysquid.mods.sodium.client.util.MathUtil; -import net.minecraft.util.math.ChunkSectionPos; +import net.minecraft.core.SectionPos; import org.apache.commons.lang3.Validate; import java.util.Arrays; @@ -60,7 +60,7 @@ public RenderRegion(int x, int y, int z, StagingBuffer stagingBuffer) { } public static long key(int x, int y, int z) { - return ChunkSectionPos.asLong(x, y, z); + return SectionPos.asLong(x, y, z); } public int getChunkX() { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java index 7947eb70dc..e27ea68f5a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java @@ -2,8 +2,10 @@ import it.unimi.dsi.fastutil.longs.Long2ReferenceOpenHashMap; import it.unimi.dsi.fastutil.objects.Reference2ReferenceMap; +import it.unimi.dsi.fastutil.objects.Reference2ReferenceMap.Entry; import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; import me.jellysquid.mods.sodium.client.SodiumClientMod; +import me.jellysquid.mods.sodium.client.gl.arena.GlBufferArena; import me.jellysquid.mods.sodium.client.gl.arena.PendingUpload; import me.jellysquid.mods.sodium.client.gl.arena.staging.FallbackStagingBuffer; import me.jellysquid.mods.sodium.client.gl.arena.staging.MappedStagingBuffer; @@ -13,6 +15,8 @@ import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildOutput; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; +import me.jellysquid.mods.sodium.client.render.chunk.data.SectionRenderDataStorage; +import me.jellysquid.mods.sodium.client.render.chunk.region.RenderRegion.DeviceResources; import me.jellysquid.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses; import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkShaderFogComponent.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkShaderFogComponent.java index d3809677f7..8f305870c6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkShaderFogComponent.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkShaderFogComponent.java @@ -46,7 +46,7 @@ public Smooth(ShaderBindingContext context) { @Override public void setup() { this.uFogColor.set(RenderSystem.getShaderFogColor()); - this.uFogShape.set(RenderSystem.getShaderFogShape().getId()); + this.uFogShape.set(RenderSystem.getShaderFogShape().getIndex()); this.uFogStart.setFloat(RenderSystem.getShaderFogStart()); this.uFogEnd.setFloat(RenderSystem.getShaderFogEnd()); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/terrain/DefaultTerrainRenderPasses.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/terrain/DefaultTerrainRenderPasses.java index 4c83078e2a..ce1b4aca42 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/terrain/DefaultTerrainRenderPasses.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/terrain/DefaultTerrainRenderPasses.java @@ -1,11 +1,11 @@ package me.jellysquid.mods.sodium.client.render.chunk.terrain; -import net.minecraft.client.render.RenderLayer; +import net.minecraft.client.renderer.RenderType; public class DefaultTerrainRenderPasses { - public static final TerrainRenderPass SOLID = new TerrainRenderPass(RenderLayer.getSolid(), false, false); - public static final TerrainRenderPass CUTOUT = new TerrainRenderPass(RenderLayer.getCutoutMipped(), false, true); - public static final TerrainRenderPass TRANSLUCENT = new TerrainRenderPass(RenderLayer.getTranslucent(), true, false); + public static final TerrainRenderPass SOLID = new TerrainRenderPass(RenderType.solid(), false, false); + public static final TerrainRenderPass CUTOUT = new TerrainRenderPass(RenderType.cutoutMipped(), false, true); + public static final TerrainRenderPass TRANSLUCENT = new TerrainRenderPass(RenderType.translucent(), true, false); public static final TerrainRenderPass[] ALL = new TerrainRenderPass[] { SOLID, CUTOUT, TRANSLUCENT }; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/terrain/TerrainRenderPass.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/terrain/TerrainRenderPass.java index 317de3b3ae..9e2d7348c3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/terrain/TerrainRenderPass.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/terrain/TerrainRenderPass.java @@ -1,15 +1,15 @@ package me.jellysquid.mods.sodium.client.render.chunk.terrain; -import net.minecraft.client.render.RenderLayer; +import net.minecraft.client.renderer.RenderType; public class TerrainRenderPass { @Deprecated(forRemoval = true) - private final RenderLayer layer; + private final RenderType layer; private final boolean useReverseOrder; private final boolean fragmentDiscard; - public TerrainRenderPass(RenderLayer layer, boolean useReverseOrder, boolean allowFragmentDiscard) { + public TerrainRenderPass(RenderType layer, boolean useReverseOrder, boolean allowFragmentDiscard) { this.layer = layer; this.useReverseOrder = useReverseOrder; @@ -22,12 +22,12 @@ public boolean isReverseOrder() { @Deprecated public void startDrawing() { - this.layer.startDrawing(); + this.layer.setupRenderState(); } @Deprecated public void endDrawing() { - this.layer.endDrawing(); + this.layer.clearRenderState(); } public boolean supportsFragmentDiscard() { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/terrain/material/DefaultMaterials.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/terrain/material/DefaultMaterials.java index 1175ef596c..c2fe2b9d73 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/terrain/material/DefaultMaterials.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/terrain/material/DefaultMaterials.java @@ -2,10 +2,10 @@ import me.jellysquid.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses; import me.jellysquid.mods.sodium.client.render.chunk.terrain.material.parameters.AlphaCutoffParameter; -import net.minecraft.block.BlockState; -import net.minecraft.client.render.RenderLayer; -import net.minecraft.client.render.RenderLayers; -import net.minecraft.fluid.FluidState; +import net.minecraft.client.renderer.ItemBlockRenderTypes; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.FluidState; public class DefaultMaterials { public static final Material SOLID = new Material(DefaultTerrainRenderPasses.SOLID, AlphaCutoffParameter.ZERO, true); @@ -14,21 +14,21 @@ public class DefaultMaterials { public static final Material TRANSLUCENT = new Material(DefaultTerrainRenderPasses.TRANSLUCENT, AlphaCutoffParameter.ZERO, true); public static Material forBlockState(BlockState state) { - return forRenderLayer(RenderLayers.getBlockLayer(state)); + return forRenderLayer(ItemBlockRenderTypes.getChunkRenderType(state)); } public static Material forFluidState(FluidState state) { - return forRenderLayer(RenderLayers.getFluidLayer(state)); + return forRenderLayer(ItemBlockRenderTypes.getRenderLayer(state)); } - public static Material forRenderLayer(RenderLayer layer) { - if (layer == RenderLayer.getSolid()) { + public static Material forRenderLayer(RenderType layer) { + if (layer == RenderType.solid()) { return SOLID; - } else if (layer == RenderLayer.getCutout()) { + } else if (layer == RenderType.cutout()) { return CUTOUT; - } else if (layer == RenderLayer.getCutoutMipped() || layer == RenderLayer.getTripwire()) { + } else if (layer == RenderType.cutoutMipped() || layer == RenderType.tripwire()) { return CUTOUT_MIPPED; - } else if (layer == RenderLayer.getTranslucent()) { + } else if (layer == RenderType.translucent()) { return TRANSLUCENT; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/vertex/builder/ChunkMeshBufferBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/vertex/builder/ChunkMeshBufferBuilder.java index a6ec8717c8..b72a89fd35 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/vertex/builder/ChunkMeshBufferBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/vertex/builder/ChunkMeshBufferBuilder.java @@ -4,7 +4,6 @@ import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexEncoder; import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexType; import org.lwjgl.system.MemoryUtil; - import java.nio.ByteBuffer; public class ChunkMeshBufferBuilder { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/immediate/CloudRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/immediate/CloudRenderer.java index 1996f7467a..be749d02c3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/immediate/CloudRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/immediate/CloudRenderer.java @@ -1,30 +1,37 @@ package me.jellysquid.mods.sodium.client.render.immediate; import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.platform.NativeImage; +import com.mojang.blaze3d.shaders.FogShape; import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.Tesselator; +import com.mojang.blaze3d.vertex.VertexBuffer; +import com.mojang.blaze3d.vertex.VertexFormat; import net.caffeinemc.mods.sodium.api.vertex.format.common.ColorVertex; import net.caffeinemc.mods.sodium.api.vertex.buffer.VertexBufferWriter; import me.jellysquid.mods.sodium.client.util.MathUtil; import net.caffeinemc.mods.sodium.api.util.ColorABGR; import net.caffeinemc.mods.sodium.api.util.ColorARGB; import net.caffeinemc.mods.sodium.api.util.ColorMixer; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gl.ShaderProgram; -import net.minecraft.client.gl.VertexBuffer; -import net.minecraft.client.network.ClientPlayerEntity; -import net.minecraft.client.option.CloudRenderMode; -import net.minecraft.client.render.*; -import net.minecraft.client.texture.NativeImage; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.client.world.ClientWorld; -import net.minecraft.entity.effect.StatusEffectInstance; -import net.minecraft.entity.effect.StatusEffects; -import net.minecraft.resource.Resource; -import net.minecraft.resource.ResourceFactory; -import net.minecraft.resource.ResourceManager; -import net.minecraft.util.Identifier; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.Vec3d; +import net.minecraft.client.Camera; +import net.minecraft.client.CloudStatus; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.client.renderer.FogRenderer; +import net.minecraft.client.renderer.ShaderInstance; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.resources.Resource; +import net.minecraft.server.packs.resources.ResourceManager; +import net.minecraft.server.packs.resources.ResourceProvider; +import net.minecraft.util.Mth; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.effect.MobEffects; +import net.minecraft.world.level.material.FogType; +import net.minecraft.world.phys.Vec3; import org.apache.commons.lang3.Validate; import org.jetbrains.annotations.Nullable; import org.joml.Matrix4f; @@ -35,7 +42,7 @@ import java.io.InputStream; public class CloudRenderer { - private static final Identifier CLOUDS_TEXTURE_ID = new Identifier("textures/environment/clouds.png"); + private static final ResourceLocation CLOUDS_TEXTURE_ID = new ResourceLocation("textures/environment/clouds.png"); private static final int CLOUD_COLOR_NEG_Y = ColorABGR.pack(0.7F, 0.7F, 0.7F, 1.0f); private static final int CLOUD_COLOR_POS_Y = ColorABGR.pack(1.0f, 1.0f, 1.0f, 1.0f); @@ -53,45 +60,45 @@ public class CloudRenderer { private VertexBuffer vertexBuffer; private CloudEdges edges; - private ShaderProgram shader; - private final BackgroundRenderer.FogData fogData = new BackgroundRenderer.FogData(BackgroundRenderer.FogType.FOG_TERRAIN); + private ShaderInstance shader; + private final FogRenderer.FogData fogData = new FogRenderer.FogData(FogRenderer.FogMode.FOG_TERRAIN); private int prevCenterCellX, prevCenterCellY, cachedRenderDistance; - private CloudRenderMode cloudRenderMode; + private CloudStatus cloudRenderMode; - public CloudRenderer(ResourceFactory factory) { + public CloudRenderer(ResourceProvider factory) { this.reloadTextures(factory); } - public void render(@Nullable ClientWorld world, ClientPlayerEntity player, MatrixStack matrices, Matrix4f projectionMatrix, float ticks, float tickDelta, double cameraX, double cameraY, double cameraZ) { + public void render(@Nullable ClientLevel world, LocalPlayer player, PoseStack matrices, Matrix4f projectionMatrix, float ticks, float tickDelta, double cameraX, double cameraY, double cameraZ) { if (world == null) { return; } - float cloudHeight = world.getDimensionEffects().getCloudsHeight(); + float cloudHeight = world.effects().getCloudHeight(); // Vanilla uses NaN height as a way to disable cloud rendering if (Float.isNaN(cloudHeight)) { return; } - Vec3d color = world.getCloudsColor(tickDelta); + Vec3 color = world.getCloudColor(tickDelta); double cloudTime = (ticks + tickDelta) * 0.03F; double cloudCenterX = (cameraX + cloudTime); double cloudCenterZ = (cameraZ) + 0.33D; - int renderDistance = MinecraftClient.getInstance().options.getClampedViewDistance(); + int renderDistance = Minecraft.getInstance().options.getEffectiveRenderDistance(); int cloudDistance = Math.max(32, (renderDistance * 2) + 9); int centerCellX = (int) (Math.floor(cloudCenterX / 12)); int centerCellZ = (int) (Math.floor(cloudCenterZ / 12)); - if (this.vertexBuffer == null || this.prevCenterCellX != centerCellX || this.prevCenterCellY != centerCellZ || this.cachedRenderDistance != renderDistance || cloudRenderMode != MinecraftClient.getInstance().options.getCloudRenderModeValue()) { - BufferBuilder bufferBuilder = Tessellator.getInstance().getBuffer(); - bufferBuilder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR); + if (this.vertexBuffer == null || this.prevCenterCellX != centerCellX || this.prevCenterCellY != centerCellZ || this.cachedRenderDistance != renderDistance || cloudRenderMode != Minecraft.getInstance().options.getCloudsType()) { + BufferBuilder bufferBuilder = Tesselator.getInstance().getBuilder(); + bufferBuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); - this.cloudRenderMode = MinecraftClient.getInstance().options.getCloudRenderModeValue(); + this.cloudRenderMode = Minecraft.getInstance().options.getCloudsType(); this.rebuildGeometry(bufferBuilder, cloudDistance, centerCellX, centerCellZ); @@ -111,14 +118,14 @@ public void render(@Nullable ClientWorld world, ClientPlayerEntity player, Matri float previousEnd = RenderSystem.getShaderFogEnd(); float previousStart = RenderSystem.getShaderFogStart(); - this.fogData.fogEnd = cloudDistance * 8; - this.fogData.fogStart = (cloudDistance * 8) - 16; + this.fogData.end = cloudDistance * 8; + this.fogData.start = (cloudDistance * 8) - 16; applyFogModifiers(world, this.fogData, player, cloudDistance * 8, tickDelta); - RenderSystem.setShaderFogEnd(this.fogData.fogEnd); - RenderSystem.setShaderFogStart(this.fogData.fogStart); + RenderSystem.setShaderFogEnd(this.fogData.end); + RenderSystem.setShaderFogStart(this.fogData.start); float translateX = (float) (cloudCenterX - (centerCellX * 12)); float translateZ = (float) (cloudCenterZ - (centerCellZ * 12)); @@ -128,7 +135,7 @@ public void render(@Nullable ClientWorld world, ClientPlayerEntity player, Matri this.vertexBuffer.bind(); boolean insideClouds = cameraY < cloudHeight + 4.5f && cameraY > cloudHeight - 0.5f; - boolean fastClouds = cloudRenderMode == CloudRenderMode.FAST; + boolean fastClouds = cloudRenderMode == CloudStatus.FAST; if (insideClouds || fastClouds) { RenderSystem.disableCull(); @@ -138,9 +145,9 @@ public void render(@Nullable ClientWorld world, ClientPlayerEntity player, Matri RenderSystem.setShaderColor((float) color.x, (float) color.y, (float) color.z, 0.8f); - matrices.push(); + matrices.pushPose(); - Matrix4f modelViewMatrix = matrices.peek().getPositionMatrix(); + Matrix4f modelViewMatrix = matrices.last().pose(); modelViewMatrix.translate(-translateX, cloudHeight - (float) cameraY + 0.33F, -translateZ); // PASS 1: Set up depth buffer @@ -148,19 +155,19 @@ public void render(@Nullable ClientWorld world, ClientPlayerEntity player, Matri RenderSystem.depthMask(true); RenderSystem.colorMask(false, false, false, false); - this.vertexBuffer.draw(modelViewMatrix, projectionMatrix, this.shader); + this.vertexBuffer.drawWithShader(modelViewMatrix, projectionMatrix, this.shader); // PASS 2: Render geometry RenderSystem.enableBlend(); - RenderSystem.blendFuncSeparate(GlStateManager.SrcFactor.SRC_ALPHA, GlStateManager.DstFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SrcFactor.ONE, GlStateManager.DstFactor.ONE_MINUS_SRC_ALPHA); + RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA); RenderSystem.depthMask(false); RenderSystem.enableDepthTest(); RenderSystem.depthFunc(GL30C.GL_EQUAL); RenderSystem.colorMask(true, true, true, true); - this.vertexBuffer.draw(modelViewMatrix, projectionMatrix, this.shader); + this.vertexBuffer.drawWithShader(modelViewMatrix, projectionMatrix, this.shader); - matrices.pop(); + matrices.popPose(); VertexBuffer.unbind(); @@ -174,57 +181,57 @@ public void render(@Nullable ClientWorld world, ClientPlayerEntity player, Matri RenderSystem.setShaderFogStart(previousStart); } - private void applyFogModifiers(ClientWorld world, BackgroundRenderer.FogData fogData, ClientPlayerEntity player, int cloudDistance, float tickDelta) { - if (MinecraftClient.getInstance().gameRenderer == null || MinecraftClient.getInstance().gameRenderer.getCamera() == null) { + private void applyFogModifiers(ClientLevel world, FogRenderer.FogData fogData, LocalPlayer player, int cloudDistance, float tickDelta) { + if (Minecraft.getInstance().gameRenderer == null || Minecraft.getInstance().gameRenderer.getMainCamera() == null) { return; } - Camera camera = MinecraftClient.getInstance().gameRenderer.getCamera(); - CameraSubmersionType cameraSubmersionType = camera.getSubmersionType(); - if (cameraSubmersionType == CameraSubmersionType.LAVA) { + Camera camera = Minecraft.getInstance().gameRenderer.getMainCamera(); + FogType cameraSubmersionType = camera.getFluidInCamera(); + if (cameraSubmersionType == FogType.LAVA) { if (player.isSpectator()) { - fogData.fogStart = -8.0f; - fogData.fogEnd = (cloudDistance) * 0.5f; - } else if (player.hasStatusEffect(StatusEffects.FIRE_RESISTANCE)) { - fogData.fogStart = 0.0f; - fogData.fogEnd = 3.0f; + fogData.start = -8.0f; + fogData.end = (cloudDistance) * 0.5f; + } else if (player.hasEffect(MobEffects.FIRE_RESISTANCE)) { + fogData.start = 0.0f; + fogData.end = 3.0f; } else { - fogData.fogStart = 0.25f; - fogData.fogEnd = 1.0f; + fogData.start = 0.25f; + fogData.end = 1.0f; } - } else if (cameraSubmersionType == CameraSubmersionType.POWDER_SNOW) { + } else if (cameraSubmersionType == FogType.POWDER_SNOW) { if (player.isSpectator()) { - fogData.fogStart = -8.0f; - fogData.fogEnd = (cloudDistance) * 0.5f; + fogData.start = -8.0f; + fogData.end = (cloudDistance) * 0.5f; } else { - fogData.fogStart = 0.0f; - fogData.fogEnd = 2.0f; + fogData.start = 0.0f; + fogData.end = 2.0f; } - } else if (cameraSubmersionType == CameraSubmersionType.WATER) { - fogData.fogStart = -8.0f; - fogData.fogEnd = 96.0f; - fogData.fogEnd *= Math.max(0.25f, player.getUnderwaterVisibility()); - if (fogData.fogEnd > (cloudDistance)) { - fogData.fogEnd = cloudDistance; - fogData.fogShape = FogShape.CYLINDER; + } else if (cameraSubmersionType == FogType.WATER) { + fogData.start = -8.0f; + fogData.end = 96.0f; + fogData.end *= Math.max(0.25f, player.getWaterVision()); + if (fogData.end > (cloudDistance)) { + fogData.end = cloudDistance; + fogData.shape = FogShape.CYLINDER; } - } else if (world.getDimensionEffects().useThickFog(MathHelper.floor(camera.getPos().x), MathHelper.floor(camera.getPos().z)) || MinecraftClient.getInstance().inGameHud.getBossBarHud().shouldThickenFog()) { - fogData.fogStart = (cloudDistance) * 0.05f; - fogData.fogEnd = Math.min((cloudDistance), 192.0f) * 0.5f; + } else if (world.effects().isFoggyAt(Mth.floor(camera.getPosition().x), Mth.floor(camera.getPosition().z)) || Minecraft.getInstance().gui.getBossOverlay().shouldCreateWorldFog()) { + fogData.start = (cloudDistance) * 0.05f; + fogData.end = Math.min((cloudDistance), 192.0f) * 0.5f; } - BackgroundRenderer.StatusEffectFogModifier fogModifier = BackgroundRenderer.getFogModifier(player, tickDelta); + FogRenderer.MobEffectFogFunction fogModifier = FogRenderer.getPriorityFogFunction(player, tickDelta); if (fogModifier != null) { - StatusEffectInstance statusEffectInstance = player.getStatusEffect(fogModifier.getStatusEffect()); + MobEffectInstance statusEffectInstance = player.getEffect(fogModifier.getMobEffect()); if (statusEffectInstance != null) { - fogModifier.applyStartEndModifier(fogData, player, statusEffectInstance, (cloudDistance * 8), tickDelta); + fogModifier.setupFog(fogData, player, statusEffectInstance, (cloudDistance * 8), tickDelta); } } } private void rebuildGeometry(BufferBuilder bufferBuilder, int cloudDistance, int centerCellX, int centerCellZ) { var writer = VertexBufferWriter.of(bufferBuilder); - boolean fastClouds = cloudRenderMode == CloudRenderMode.FAST; + boolean fastClouds = cloudRenderMode == CloudStatus.FAST; for (int offsetX = -cloudDistance; offsetX < cloudDistance; offsetX++) { for (int offsetZ = -cloudDistance; offsetZ < cloudDistance; offsetZ++) { @@ -336,13 +343,13 @@ private static long writeVertex(long buffer, float x, float y, float z, int colo return buffer + ColorVertex.STRIDE; } - public void reloadTextures(ResourceFactory factory) { + public void reloadTextures(ResourceProvider factory) { this.destroy(); this.edges = createCloudEdges(); try { - this.shader = new ShaderProgram(factory, "clouds", VertexFormats.POSITION_COLOR); + this.shader = new ShaderInstance(factory, "clouds", DefaultVertexFormat.POSITION_COLOR); } catch (IOException e) { throw new RuntimeException(e); } @@ -361,11 +368,11 @@ public void destroy() { } private static CloudEdges createCloudEdges() { - ResourceManager resourceManager = MinecraftClient.getInstance().getResourceManager(); + ResourceManager resourceManager = Minecraft.getInstance().getResourceManager(); Resource resource = resourceManager.getResource(CLOUDS_TEXTURE_ID) .orElseThrow(); - try (InputStream inputStream = resource.getInputStream()){ + try (InputStream inputStream = resource.open()){ try (NativeImage nativeImage = NativeImage.read(inputStream)) { return new CloudEdges(nativeImage); } @@ -395,7 +402,7 @@ public CloudEdges(NativeImage texture) { for (int x = 0; x < width; x++) { for (int z = 0; z < height; z++) { int index = index(x, z, width, height); - int cell = texture.getColor(x, z); + int cell = texture.getPixelRGBA(x, z); this.colors[index] = cell; @@ -404,25 +411,25 @@ public CloudEdges(NativeImage texture) { if (isOpaqueCell(cell)) { edges |= DIR_NEG_Y | DIR_POS_Y; - int negX = texture.getColor(wrap(x - 1, width), wrap(z, height)); + int negX = texture.getPixelRGBA(wrap(x - 1, width), wrap(z, height)); if (cell != negX) { edges |= DIR_NEG_X; } - int posX = texture.getColor(wrap(x + 1, width), wrap(z, height)); + int posX = texture.getPixelRGBA(wrap(x + 1, width), wrap(z, height)); if (!isOpaqueCell(posX) && cell != posX) { edges |= DIR_POS_X; } - int negZ = texture.getColor(wrap(x, width), wrap(z - 1, height)); + int negZ = texture.getPixelRGBA(wrap(x, width), wrap(z - 1, height)); if (cell != negZ) { edges |= DIR_NEG_Z; } - int posZ = texture.getColor(wrap(x, width), wrap(z + 1, height)); + int posZ = texture.getPixelRGBA(wrap(x, width), wrap(z + 1, height)); if (!isOpaqueCell(posZ) && cell != posZ) { edges |= DIR_POS_Z; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/immediate/model/BakedModelEncoder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/immediate/model/BakedModelEncoder.java index a8fc2e30dc..8efeedadac 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/immediate/model/BakedModelEncoder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/immediate/model/BakedModelEncoder.java @@ -1,20 +1,20 @@ package me.jellysquid.mods.sodium.client.render.immediate.model; +import com.mojang.blaze3d.vertex.PoseStack; import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; import net.caffeinemc.mods.sodium.api.math.MatrixHelper; import net.caffeinemc.mods.sodium.api.util.ColorABGR; import net.caffeinemc.mods.sodium.api.util.ColorU8; import net.caffeinemc.mods.sodium.api.vertex.buffer.VertexBufferWriter; import net.caffeinemc.mods.sodium.api.vertex.format.common.ModelVertex; -import net.minecraft.client.util.math.MatrixStack; import org.joml.Matrix3f; import org.joml.Matrix4f; import org.lwjgl.system.MemoryStack; public class BakedModelEncoder { - public static void writeQuadVertices(VertexBufferWriter writer, MatrixStack.Entry matrices, ModelQuadView quad, int color, int light, int overlay) { - Matrix3f matNormal = matrices.getNormalMatrix(); - Matrix4f matPosition = matrices.getPositionMatrix(); + public static void writeQuadVertices(VertexBufferWriter writer, PoseStack.Pose matrices, ModelQuadView quad, int color, int light, int overlay) { + Matrix3f matNormal = matrices.normal(); + Matrix4f matPosition = matrices.pose(); try (MemoryStack stack = MemoryStack.stackPush()) { long buffer = stack.nmalloc(4 * ModelVertex.STRIDE); @@ -42,9 +42,9 @@ public static void writeQuadVertices(VertexBufferWriter writer, MatrixStack.Entr } } - public static void writeQuadVertices(VertexBufferWriter writer, MatrixStack.Entry matrices, ModelQuadView quad, float r, float g, float b, float[] brightnessTable, boolean colorize, int[] light, int overlay) { - Matrix3f matNormal = matrices.getNormalMatrix(); - Matrix4f matPosition = matrices.getPositionMatrix(); + public static void writeQuadVertices(VertexBufferWriter writer, PoseStack.Pose matrices, ModelQuadView quad, float r, float g, float b, float[] brightnessTable, boolean colorize, int[] light, int overlay) { + Matrix3f matNormal = matrices.normal(); + Matrix4f matPosition = matrices.pose(); try (MemoryStack stack = MemoryStack.stackPush()) { long buffer = stack.nmalloc(4 * ModelVertex.STRIDE); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/immediate/model/EntityRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/immediate/model/EntityRenderer.java index e938a071f8..989e6a11cc 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/immediate/model/EntityRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/immediate/model/EntityRenderer.java @@ -1,11 +1,11 @@ package me.jellysquid.mods.sodium.client.render.immediate.model; +import com.mojang.blaze3d.vertex.PoseStack; import net.caffeinemc.mods.sodium.api.math.MatrixHelper; import net.caffeinemc.mods.sodium.api.vertex.buffer.VertexBufferWriter; import net.caffeinemc.mods.sodium.api.vertex.format.common.ModelVertex; -import net.minecraft.client.model.ModelPart; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.util.math.Direction; +import net.minecraft.client.model.geom.ModelPart; +import net.minecraft.core.Direction; import org.apache.commons.lang3.ArrayUtils; import org.joml.Matrix4f; import org.joml.Vector2f; @@ -79,7 +79,7 @@ public class EntityRenderer { } } - public static void render(MatrixStack matrixStack, VertexBufferWriter writer, ModelPart part, int light, int overlay, int color) { + public static void render(PoseStack matrixStack, VertexBufferWriter writer, ModelPart part, int light, int overlay, int color) { ModelPartData accessor = ModelPartData.from(part); if (!accessor.isVisible()) { @@ -93,26 +93,26 @@ public static void render(MatrixStack matrixStack, VertexBufferWriter writer, Mo return; } - matrixStack.push(); + matrixStack.pushPose(); - part.rotate(matrixStack); + part.translateAndRotate(matrixStack); if (!accessor.isHidden()) { - renderCuboids(matrixStack.peek(), writer, cuboids, light, overlay, color); + renderCuboids(matrixStack.last(), writer, cuboids, light, overlay, color); } renderChildren(matrixStack, writer, light, overlay, color, children); - matrixStack.pop(); + matrixStack.popPose(); } - private static void renderChildren(MatrixStack matrices, VertexBufferWriter writer, int light, int overlay, int color, ModelPart[] children) { + private static void renderChildren(PoseStack matrices, VertexBufferWriter writer, int light, int overlay, int color, ModelPart[] children) { for (ModelPart part : children) { render(matrices, writer, part, light, overlay, color); } } - private static void renderCuboids(MatrixStack.Entry matrices, VertexBufferWriter writer, ModelCuboid[] cuboids, int light, int overlay, int color) { + private static void renderCuboids(PoseStack.Pose matrices, VertexBufferWriter writer, ModelCuboid[] cuboids, int light, int overlay, int color) { prepareNormals(matrices); for (ModelCuboid cuboid : cuboids) { @@ -162,15 +162,15 @@ private static void emitVertex(long ptr, Vector3f pos, int color, Vector2f tex, ModelVertex.write(ptr, pos.x, pos.y, pos.z, color, tex.x, tex.y, overlay, light, normal); } - private static void prepareVertices(MatrixStack.Entry matrices, ModelCuboid cuboid) { - buildVertexPosition(CUBE_CORNERS[VERTEX_X1_Y1_Z1], cuboid.x1, cuboid.y1, cuboid.z1, matrices.getPositionMatrix()); - buildVertexPosition(CUBE_CORNERS[VERTEX_X2_Y1_Z1], cuboid.x2, cuboid.y1, cuboid.z1, matrices.getPositionMatrix()); - buildVertexPosition(CUBE_CORNERS[VERTEX_X2_Y2_Z1], cuboid.x2, cuboid.y2, cuboid.z1, matrices.getPositionMatrix()); - buildVertexPosition(CUBE_CORNERS[VERTEX_X1_Y2_Z1], cuboid.x1, cuboid.y2, cuboid.z1, matrices.getPositionMatrix()); - buildVertexPosition(CUBE_CORNERS[VERTEX_X1_Y1_Z2], cuboid.x1, cuboid.y1, cuboid.z2, matrices.getPositionMatrix()); - buildVertexPosition(CUBE_CORNERS[VERTEX_X2_Y1_Z2], cuboid.x2, cuboid.y1, cuboid.z2, matrices.getPositionMatrix()); - buildVertexPosition(CUBE_CORNERS[VERTEX_X2_Y2_Z2], cuboid.x2, cuboid.y2, cuboid.z2, matrices.getPositionMatrix()); - buildVertexPosition(CUBE_CORNERS[VERTEX_X1_Y2_Z2], cuboid.x1, cuboid.y2, cuboid.z2, matrices.getPositionMatrix()); + private static void prepareVertices(PoseStack.Pose matrices, ModelCuboid cuboid) { + buildVertexPosition(CUBE_CORNERS[VERTEX_X1_Y1_Z1], cuboid.x1, cuboid.y1, cuboid.z1, matrices.pose()); + buildVertexPosition(CUBE_CORNERS[VERTEX_X2_Y1_Z1], cuboid.x2, cuboid.y1, cuboid.z1, matrices.pose()); + buildVertexPosition(CUBE_CORNERS[VERTEX_X2_Y2_Z1], cuboid.x2, cuboid.y2, cuboid.z1, matrices.pose()); + buildVertexPosition(CUBE_CORNERS[VERTEX_X1_Y2_Z1], cuboid.x1, cuboid.y2, cuboid.z1, matrices.pose()); + buildVertexPosition(CUBE_CORNERS[VERTEX_X1_Y1_Z2], cuboid.x1, cuboid.y1, cuboid.z2, matrices.pose()); + buildVertexPosition(CUBE_CORNERS[VERTEX_X2_Y1_Z2], cuboid.x2, cuboid.y1, cuboid.z2, matrices.pose()); + buildVertexPosition(CUBE_CORNERS[VERTEX_X2_Y2_Z2], cuboid.x2, cuboid.y2, cuboid.z2, matrices.pose()); + buildVertexPosition(CUBE_CORNERS[VERTEX_X1_Y2_Z2], cuboid.x1, cuboid.y2, cuboid.z2, matrices.pose()); buildVertexTexCoord(VERTEX_TEXTURES[FACE_NEG_Y], cuboid.u1, cuboid.v0, cuboid.u2, cuboid.v1); buildVertexTexCoord(VERTEX_TEXTURES[FACE_POS_Y], cuboid.u2, cuboid.v1, cuboid.u3, cuboid.v0); @@ -180,13 +180,13 @@ private static void prepareVertices(MatrixStack.Entry matrices, ModelCuboid cubo buildVertexTexCoord(VERTEX_TEXTURES[FACE_POS_X], cuboid.u0, cuboid.v1, cuboid.u1, cuboid.v2); } - private static void prepareNormals(MatrixStack.Entry matrices) { - CUBE_NORMALS[FACE_NEG_Y] = MatrixHelper.transformNormal(matrices.getNormalMatrix(), Direction.DOWN); - CUBE_NORMALS[FACE_POS_Y] = MatrixHelper.transformNormal(matrices.getNormalMatrix(), Direction.UP); - CUBE_NORMALS[FACE_NEG_Z] = MatrixHelper.transformNormal(matrices.getNormalMatrix(), Direction.NORTH); - CUBE_NORMALS[FACE_POS_Z] = MatrixHelper.transformNormal(matrices.getNormalMatrix(), Direction.SOUTH); - CUBE_NORMALS[FACE_POS_X] = MatrixHelper.transformNormal(matrices.getNormalMatrix(), Direction.WEST); - CUBE_NORMALS[FACE_NEG_X] = MatrixHelper.transformNormal(matrices.getNormalMatrix(), Direction.EAST); + private static void prepareNormals(PoseStack.Pose matrices) { + CUBE_NORMALS[FACE_NEG_Y] = MatrixHelper.transformNormal(matrices.normal(), Direction.DOWN); + CUBE_NORMALS[FACE_POS_Y] = MatrixHelper.transformNormal(matrices.normal(), Direction.UP); + CUBE_NORMALS[FACE_NEG_Z] = MatrixHelper.transformNormal(matrices.normal(), Direction.NORTH); + CUBE_NORMALS[FACE_POS_Z] = MatrixHelper.transformNormal(matrices.normal(), Direction.SOUTH); + CUBE_NORMALS[FACE_POS_X] = MatrixHelper.transformNormal(matrices.normal(), Direction.WEST); + CUBE_NORMALS[FACE_NEG_X] = MatrixHelper.transformNormal(matrices.normal(), Direction.EAST); // When mirroring is used, the normals for EAST and WEST are swapped. CUBE_NORMALS_MIRRORED[FACE_NEG_Y] = CUBE_NORMALS[FACE_NEG_Y]; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/immediate/model/ModelCuboid.java b/src/main/java/me/jellysquid/mods/sodium/client/render/immediate/model/ModelCuboid.java index 349f63b3a4..95b948f5b9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/immediate/model/ModelCuboid.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/immediate/model/ModelCuboid.java @@ -1,9 +1,8 @@ package me.jellysquid.mods.sodium.client.render.immediate.model; -import net.minecraft.util.math.Direction; import org.joml.*; - import java.util.Set; +import net.minecraft.core.Direction; public class ModelCuboid { public final float x1, y1, z1; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/immediate/model/ModelPartData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/immediate/model/ModelPartData.java index 45a7803c28..00ab9145fb 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/immediate/model/ModelPartData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/immediate/model/ModelPartData.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.render.immediate.model; -import net.minecraft.client.model.ModelPart; +import net.minecraft.client.model.geom.ModelPart; public interface ModelPartData { static ModelPartData from(ModelPart child) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/texture/SpriteUtil.java b/src/main/java/me/jellysquid/mods/sodium/client/render/texture/SpriteUtil.java index b8e8a6b879..2e059411f1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/texture/SpriteUtil.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/texture/SpriteUtil.java @@ -1,20 +1,20 @@ package me.jellysquid.mods.sodium.client.render.texture; -import net.minecraft.client.texture.Sprite; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; import org.jetbrains.annotations.Nullable; public class SpriteUtil { - public static void markSpriteActive(@Nullable Sprite sprite) { + public static void markSpriteActive(@Nullable TextureAtlasSprite sprite) { if (sprite == null) { // Can happen in some cases, for example if a mod passes a BakedQuad with a null sprite // to a VertexConsumer that does not have a texture element. return; } - ((SpriteContentsExtended) sprite.getContents()).sodium$setActive(true); + ((SpriteContentsExtended) sprite.contents()).sodium$setActive(true); } - public static boolean hasAnimation(Sprite sprite) { - return ((SpriteContentsExtended) sprite.getContents()).sodium$hasAnimation(); + public static boolean hasAnimation(TextureAtlasSprite sprite) { + return ((SpriteContentsExtended) sprite.contents()).sodium$hasAnimation(); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/vertex/VertexConsumerTracker.java b/src/main/java/me/jellysquid/mods/sodium/client/render/vertex/VertexConsumerTracker.java index 8a7c81e7cf..abb9d02584 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/vertex/VertexConsumerTracker.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/vertex/VertexConsumerTracker.java @@ -1,10 +1,10 @@ package me.jellysquid.mods.sodium.client.render.vertex; +import com.mojang.blaze3d.vertex.VertexConsumer; import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; import it.unimi.dsi.fastutil.objects.ReferenceSet; import it.unimi.dsi.fastutil.objects.ReferenceSets; import me.jellysquid.mods.sodium.client.SodiumClientMod; -import net.minecraft.client.render.VertexConsumer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/vertex/VertexConsumerUtils.java b/src/main/java/me/jellysquid/mods/sodium/client/render/vertex/VertexConsumerUtils.java index 7a2463aa0f..ec795d0dd6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/vertex/VertexConsumerUtils.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/vertex/VertexConsumerUtils.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.render.vertex; +import com.mojang.blaze3d.vertex.VertexConsumer; import net.caffeinemc.mods.sodium.api.vertex.buffer.VertexBufferWriter; -import net.minecraft.client.render.VertexConsumer; public class VertexConsumerUtils { /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/vertex/VertexFormatDescriptionImpl.java b/src/main/java/me/jellysquid/mods/sodium/client/render/vertex/VertexFormatDescriptionImpl.java index 1fa17d9db7..000d96890e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/vertex/VertexFormatDescriptionImpl.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/vertex/VertexFormatDescriptionImpl.java @@ -3,9 +3,11 @@ import me.jellysquid.mods.sodium.mixin.core.render.VertexFormatAccessor; import net.caffeinemc.mods.sodium.api.vertex.attributes.CommonVertexAttribute; import net.caffeinemc.mods.sodium.api.vertex.format.VertexFormatDescription; -import net.minecraft.client.render.VertexFormat; -import net.minecraft.client.render.VertexFormats; - +import com.google.common.collect.ImmutableList; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.VertexFormat; +import com.mojang.blaze3d.vertex.VertexFormatElement; +import it.unimi.dsi.fastutil.ints.IntList; import java.util.Arrays; import java.util.EnumSet; import java.util.NoSuchElementException; @@ -20,7 +22,7 @@ public class VertexFormatDescriptionImpl implements VertexFormatDescription { public VertexFormatDescriptionImpl(VertexFormat format, int id) { this.id = id; - this.stride = format.getVertexSizeByte(); + this.stride = format.getVertexSize(); this.offsets = getOffsets(format); this.isSimple = checkSimple(format); @@ -33,7 +35,7 @@ private static boolean checkSimple(VertexFormat format) { for (int elementIndex = 0; elementIndex < elementList.size(); elementIndex++) { var element = elementList.get(elementIndex); var commonType = CommonVertexAttribute.getCommonType(element); - if (element != VertexFormats.PADDING_ELEMENT && (commonType == null || !attributeSet.add(commonType))) { + if (element != DefaultVertexFormat.ELEMENT_PADDING && (commonType == null || !attributeSet.add(commonType))) { return false; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/vertex/VertexFormatRegistryImpl.java b/src/main/java/me/jellysquid/mods/sodium/client/render/vertex/VertexFormatRegistryImpl.java index 61b0602a94..4fb3a4d5aa 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/vertex/VertexFormatRegistryImpl.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/vertex/VertexFormatRegistryImpl.java @@ -1,10 +1,9 @@ package me.jellysquid.mods.sodium.client.render.vertex; +import com.mojang.blaze3d.vertex.VertexFormat; import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; import net.caffeinemc.mods.sodium.api.vertex.format.VertexFormatDescription; import net.caffeinemc.mods.sodium.api.vertex.format.VertexFormatRegistry; -import net.minecraft.client.render.VertexFormat; - import java.util.Map; import java.util.concurrent.locks.StampedLock; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/vertex/buffer/SodiumBufferBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/vertex/buffer/SodiumBufferBuilder.java index b67e882e26..bab08e76da 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/vertex/buffer/SodiumBufferBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/vertex/buffer/SodiumBufferBuilder.java @@ -1,5 +1,7 @@ package me.jellysquid.mods.sodium.client.render.vertex.buffer; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.VertexConsumer; import net.caffeinemc.mods.sodium.api.util.ColorABGR; import net.caffeinemc.mods.sodium.api.util.ColorARGB; import net.caffeinemc.mods.sodium.api.util.NormI8; @@ -7,8 +9,6 @@ import net.caffeinemc.mods.sodium.api.vertex.attributes.common.*; import net.caffeinemc.mods.sodium.api.vertex.buffer.VertexBufferWriter; import net.caffeinemc.mods.sodium.api.vertex.format.VertexFormatDescription; -import net.minecraft.client.render.BufferBuilder; -import net.minecraft.client.render.VertexConsumer; import org.lwjgl.system.MemoryStack; import org.lwjgl.system.MemoryUtil; import org.spongepowered.asm.mixin.Unique; @@ -213,18 +213,18 @@ public void vertex(float x, float y, float z, this.writtenAttributes = ATTRIBUTE_POSITION_BIT | ATTRIBUTE_COLOR_BIT | ATTRIBUTE_TEXTURE_BIT | ATTRIBUTE_OVERLAY_BIT | ATTRIBUTE_LIGHT_BIT | ATTRIBUTE_NORMAL_BIT; - this.next(); + this.endVertex(); } @Override - public void fixedColor(int red, int green, int blue, int alpha) { - ((BufferBuilder)this.builder).fixedColor(red, green, blue, alpha); + public void defaultColor(int red, int green, int blue, int alpha) { + ((BufferBuilder)this.builder).defaultColor(red, green, blue, alpha); this.packedFixedColor = ColorABGR.pack(red, green, blue, alpha); } @Override - public void unfixColor() { - ((BufferBuilder)this.builder).unfixColor(); + public void unsetDefaultColor() { + ((BufferBuilder)this.builder).unsetDefaultColor(); } @Override @@ -262,14 +262,14 @@ public VertexConsumer color(int argb) { // No, this isn't a typo. One method tak } @Override - public VertexConsumer texture(float u, float v) { + public VertexConsumer uv(float u, float v) { this.putTextureAttribute(u, v); return this; } @Override - public VertexConsumer overlay(int uv) { + public VertexConsumer overlayCoords(int uv) { this.putOverlayAttribute(uv); return this; @@ -277,7 +277,7 @@ public VertexConsumer overlay(int uv) { @Override - public VertexConsumer light(int uv) { + public VertexConsumer uv2(int uv) { this.putLightAttribute(uv); return this; @@ -290,7 +290,7 @@ public VertexConsumer normal(float x, float y, float z) { } @Override - public void next() { + public void endVertex() { if (this.builder.sodium$usingFixedColor()) { this.putColorAttribute(this.packedFixedColor); } @@ -317,13 +317,13 @@ private boolean isVertexFinished() { } @Override - public VertexConsumer light(int u, int v) { - return this.light(packU16x2(u, v)); + public VertexConsumer uv2(int u, int v) { + return this.uv2(packU16x2(u, v)); } @Override - public VertexConsumer overlay(int u, int v) { - return this.overlay(packU16x2(u, v)); + public VertexConsumer overlayCoords(int u, int v) { + return this.overlayCoords(packU16x2(u, v)); } @Unique diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/vertex/serializers/generated/VertexSerializerFactory.java b/src/main/java/me/jellysquid/mods/sodium/client/render/vertex/serializers/generated/VertexSerializerFactory.java index 13ad668599..3903f3c1fe 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/vertex/serializers/generated/VertexSerializerFactory.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/vertex/serializers/generated/VertexSerializerFactory.java @@ -5,7 +5,6 @@ import net.caffeinemc.mods.sodium.api.vertex.serializer.VertexSerializer; import org.lwjgl.system.MemoryUtil; import org.objectweb.asm.*; - import java.lang.invoke.MethodHandles; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/viewport/Viewport.java b/src/main/java/me/jellysquid/mods/sodium/client/render/viewport/Viewport.java index 3bd7bceb39..4ef000ef5e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/viewport/Viewport.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/viewport/Viewport.java @@ -1,28 +1,28 @@ package me.jellysquid.mods.sodium.client.render.viewport; import me.jellysquid.mods.sodium.client.render.viewport.frustum.Frustum; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.ChunkSectionPos; +import net.minecraft.core.BlockPos; +import net.minecraft.core.SectionPos; import org.joml.Vector3d; public final class Viewport { private final Frustum frustum; private final CameraTransform transform; - private final ChunkSectionPos chunkCoords; + private final SectionPos chunkCoords; private final BlockPos blockCoords; public Viewport(Frustum frustum, Vector3d position) { this.frustum = frustum; this.transform = new CameraTransform(position.x, position.y, position.z); - this.chunkCoords = ChunkSectionPos.from( - ChunkSectionPos.getSectionCoord(position.x), - ChunkSectionPos.getSectionCoord(position.y), - ChunkSectionPos.getSectionCoord(position.z) + this.chunkCoords = SectionPos.of( + SectionPos.posToSectionCoord(position.x), + SectionPos.posToSectionCoord(position.y), + SectionPos.posToSectionCoord(position.z) ); - this.blockCoords = BlockPos.ofFloored(position.x, position.y, position.z); + this.blockCoords = BlockPos.containing(position.x, position.y, position.z); } public boolean isBoxVisible(int intOriginX, int intOriginY, int intOriginZ, float floatSizeX, float floatSizeY, float floatSizeZ) { @@ -45,7 +45,7 @@ public CameraTransform getTransform() { return this.transform; } - public ChunkSectionPos getChunkCoord() { + public SectionPos getChunkCoord() { return this.chunkCoords; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/DirectionUtil.java b/src/main/java/me/jellysquid/mods/sodium/client/util/DirectionUtil.java index 1a0d6de577..13c1daecd8 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/DirectionUtil.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/DirectionUtil.java @@ -1,8 +1,7 @@ package me.jellysquid.mods.sodium.client.util; -import net.minecraft.util.math.Direction; - import java.util.Arrays; +import net.minecraft.core.Direction; /** * Contains a number of cached arrays to avoid allocations since calling Enum#values() requires the backing array to diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/ModelQuadUtil.java b/src/main/java/me/jellysquid/mods/sodium/client/util/ModelQuadUtil.java index 518cb5306b..c95a7fa044 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/ModelQuadUtil.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/ModelQuadUtil.java @@ -3,8 +3,8 @@ import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import net.caffeinemc.mods.sodium.api.util.NormI8; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.MathHelper; +import net.minecraft.core.Direction; +import net.minecraft.util.Mth; import org.joml.Vector3f; /** @@ -51,7 +51,7 @@ public static ModelQuadFacing findNormalFace(float x, float y, float z) { Direction closestFace = null; for (Direction face : DirectionUtil.ALL_DIRECTIONS) { - float dot = normal.dot(face.getUnitVector()); + float dot = normal.dot(face.step()); if (dot > maxDot) { maxDot = dot; @@ -59,7 +59,7 @@ public static ModelQuadFacing findNormalFace(float x, float y, float z) { } } - if (closestFace != null && MathHelper.approximatelyEquals(maxDot, 1.0f)) { + if (closestFace != null && Mth.equal(maxDot, 1.0f)) { return ModelQuadFacing.fromDirection(closestFace); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/NativeImageHelper.java b/src/main/java/me/jellysquid/mods/sodium/client/util/NativeImageHelper.java index f626166db6..625f1961af 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/NativeImageHelper.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/NativeImageHelper.java @@ -1,18 +1,17 @@ package me.jellysquid.mods.sodium.client.util; import me.jellysquid.mods.sodium.mixin.features.textures.NativeImageAccessor; -import net.minecraft.client.texture.NativeImage; - +import com.mojang.blaze3d.platform.NativeImage; import java.util.Locale; public class NativeImageHelper { public static long getPointerRGBA(NativeImage nativeImage) { - if (nativeImage.getFormat() != NativeImage.Format.RGBA) { + if (nativeImage.format() != NativeImage.Format.RGBA) { throw new IllegalArgumentException(String.format(Locale.ROOT, - "Tried to get pointer to RGBA pixel data on NativeImage of wrong format; have %s", nativeImage.getFormat())); + "Tried to get pointer to RGBA pixel data on NativeImage of wrong format; have %s", nativeImage.format())); } return ((NativeImageAccessor) (Object) nativeImage) // duck type since NativeImage is final - .getPointer(); + .getPixels(); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/color/BoxBlur.java b/src/main/java/me/jellysquid/mods/sodium/client/util/color/BoxBlur.java index 121d8c9283..2058e1c01e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/color/BoxBlur.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/color/BoxBlur.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.util.color; import net.caffeinemc.mods.sodium.api.util.ColorARGB; -import net.minecraft.util.math.MathHelper; +import net.minecraft.util.Mth; public class BoxBlur { @@ -77,7 +77,7 @@ private static void blurImpl(int[] src, int[] dst, int width, int height, int ra * @author 2No2Name */ private static int getAveragingMultiplier(int size) { - return MathHelper.ceil((1L << 24) / (double) size); + return Mth.ceil((1L << 24) / (double) size); } /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/color/ColorSRGB.java b/src/main/java/me/jellysquid/mods/sodium/client/util/color/ColorSRGB.java index e65678bb97..519d1387a7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/color/ColorSRGB.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/color/ColorSRGB.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.util.color; -import net.minecraft.util.math.ColorHelper; +import net.minecraft.util.FastColor; /** * This is a port of the fast-srgb8 library from thomcc on GitHub. @@ -82,7 +82,7 @@ public static float srgbToLinear(int c) { * @param a The alpha-component in linear RGB space (0 to 255) */ public static int linearToSrgb(float r, float g, float b, int a) { - return ColorHelper.Abgr.getAbgr(a, linearToSrgb(b), linearToSrgb(g), linearToSrgb(r)); + return FastColor.ABGR32.color(a, linearToSrgb(b), linearToSrgb(g), linearToSrgb(r)); } /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/color/FastCubicSampler.java b/src/main/java/me/jellysquid/mods/sodium/client/util/color/FastCubicSampler.java index 66e00920d7..b9e68cd450 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/color/FastCubicSampler.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/color/FastCubicSampler.java @@ -1,18 +1,17 @@ package me.jellysquid.mods.sodium.client.util.color; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.Vec3d; - import java.util.function.Function; +import net.minecraft.util.Mth; +import net.minecraft.world.phys.Vec3; public class FastCubicSampler { private static final double[] DENSITY_CURVE = new double[] { 0.0D, 1.0D, 4.0D, 6.0D, 4.0D, 1.0D, 0.0D }; private static final int DIAMETER = 6; - public static Vec3d sampleColor(Vec3d pos, ColorFetcher colorFetcher, Function transformer) { - int intX = MathHelper.floor(pos.getX()); - int intY = MathHelper.floor(pos.getY()); - int intZ = MathHelper.floor(pos.getZ()); + public static Vec3 sampleColor(Vec3 pos, ColorFetcher colorFetcher, Function transformer) { + int intX = Mth.floor(pos.x()); + int intY = Mth.floor(pos.y()); + int intZ = Mth.floor(pos.z()); int[] values = new int[DIAMETER * DIAMETER * DIAMETER]; @@ -33,35 +32,35 @@ public static Vec3d sampleColor(Vec3d pos, ColorFetcher colorFetcher, Function void sodium$unpack(T[] out, Palette palette); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/ReadableContainerExtended.java b/src/main/java/me/jellysquid/mods/sodium/client/world/ReadableContainerExtended.java index 71746d4cb0..13b6f1e723 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/ReadableContainerExtended.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/ReadableContainerExtended.java @@ -1,14 +1,14 @@ package me.jellysquid.mods.sodium.client.world; -import net.minecraft.world.chunk.ReadableContainer; +import net.minecraft.world.level.chunk.PalettedContainerRO; public interface ReadableContainerExtended { @SuppressWarnings("unchecked") - static ReadableContainerExtended of(ReadableContainer container) { + static ReadableContainerExtended of(PalettedContainerRO container) { return (ReadableContainerExtended) container; } - static ReadableContainer clone(ReadableContainer container) { + static PalettedContainerRO clone(PalettedContainerRO container) { if (container == null) { return null; } @@ -19,5 +19,5 @@ static ReadableContainer clone(ReadableContainer container) { void sodium$unpack(T[] values); void sodium$unpack(T[] values, int minX, int minY, int minZ, int maxX, int maxY, int maxZ); - ReadableContainer sodium$copy(); + PalettedContainerRO sodium$copy(); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java index 90dcab6948..f3eef1e245 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java @@ -9,23 +9,27 @@ import me.jellysquid.mods.sodium.client.world.cloned.ClonedChunkSection; import me.jellysquid.mods.sodium.client.world.cloned.ClonedChunkSectionCache; import net.fabricmc.fabric.api.rendering.data.v1.RenderAttachedBlockView; -import net.minecraft.block.BlockState; -import net.minecraft.block.Blocks; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.world.ClientWorld; -import net.minecraft.fluid.FluidState; -import net.minecraft.registry.entry.RegistryEntry; -import net.minecraft.util.math.*; -import net.minecraft.world.BlockRenderView; -import net.minecraft.world.LightType; -import net.minecraft.world.World; -import net.minecraft.world.biome.Biome; -import net.minecraft.world.biome.ColorResolver; -import net.minecraft.world.chunk.ChunkNibbleArray; -import net.minecraft.world.chunk.ChunkSection; -import net.minecraft.world.chunk.WorldChunk; -import net.minecraft.world.chunk.light.LightingProvider; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Holder; +import net.minecraft.core.SectionPos; +import net.minecraft.util.Mth; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.ColorResolver; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LightLayer; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.DataLayer; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.levelgen.structure.BoundingBox; +import net.minecraft.world.level.lighting.LevelLightEngine; +import net.minecraft.world.level.material.FluidState; import org.jetbrains.annotations.Nullable; import java.util.Arrays; @@ -41,8 +45,8 @@ * *

Object pooling should be used to avoid huge allocations as this class contains many large arrays.

*/ -public final class WorldSlice implements BlockRenderView, BiomeColorView, RenderAttachedBlockView { - private static final LightType[] LIGHT_TYPES = LightType.values(); +public final class WorldSlice implements BlockAndTintGetter, BiomeColorView, RenderAttachedBlockView { + private static final LightLayer[] LIGHT_TYPES = LightLayer.values(); // The number of blocks in a section. private static final int SECTION_BLOCK_COUNT = 16 * 16 * 16; @@ -51,7 +55,7 @@ public final class WorldSlice implements BlockRenderView, BiomeColorView, Render private static final int NEIGHBOR_BLOCK_RADIUS = 2; // The radius of chunks around the origin chunk that should be copied. - private static final int NEIGHBOR_CHUNK_RADIUS = MathHelper.roundUpToMultiple(NEIGHBOR_BLOCK_RADIUS, 16) >> 4; + private static final int NEIGHBOR_CHUNK_RADIUS = Mth.roundToward(NEIGHBOR_BLOCK_RADIUS, 16) >> 4; // The number of sections on each axis of this slice. private static final int SECTION_ARRAY_LENGTH = 1 + (NEIGHBOR_CHUNK_RADIUS * 2); @@ -63,10 +67,10 @@ public final class WorldSlice implements BlockRenderView, BiomeColorView, Render private static final int LOCAL_XYZ_BITS = 4; // The default block state used for out-of-bounds access - private static final BlockState EMPTY_BLOCK_STATE = Blocks.AIR.getDefaultState(); + private static final BlockState EMPTY_BLOCK_STATE = Blocks.AIR.defaultBlockState(); // The world this slice has copied data from - private final ClientWorld world; + private final ClientLevel world; // The accessor used for fetching biome data from the slice private final BiomeSlice biomeSlice; @@ -78,7 +82,7 @@ public final class WorldSlice implements BlockRenderView, BiomeColorView, Render private final BlockState[][] blockArrays; // (Local Section -> Light Arrays) table. - private final @Nullable ChunkNibbleArray[][] lightArrays; + private final @Nullable DataLayer[][] lightArrays; // (Local Section -> Block Entity) table. private final @Nullable Int2ReferenceMap[] blockEntityArrays; @@ -90,25 +94,25 @@ public final class WorldSlice implements BlockRenderView, BiomeColorView, Render private int originX, originY, originZ; // The volume that this WorldSlice contains - private BlockBox volume; + private BoundingBox volume; - public static ChunkRenderContext prepare(World world, ChunkSectionPos origin, ClonedChunkSectionCache sectionCache) { - WorldChunk chunk = world.getChunk(origin.getX(), origin.getZ()); - ChunkSection section = chunk.getSectionArray()[world.sectionCoordToIndex(origin.getY())]; + public static ChunkRenderContext prepare(Level world, SectionPos origin, ClonedChunkSectionCache sectionCache) { + LevelChunk chunk = world.getChunk(origin.getX(), origin.getZ()); + LevelChunkSection section = chunk.getSections()[world.getSectionIndexFromSectionY(origin.getY())]; // If the chunk section is absent or empty, simply terminate now. There will never be anything in this chunk // section to render, so we need to signal that a chunk render task shouldn't created. This saves a considerable // amount of time in queueing instant build tasks and greatly accelerates how quickly the world can be loaded. - if (section == null || section.isEmpty()) { + if (section == null || section.hasOnlyAir()) { return null; } - BlockBox volume = new BlockBox(origin.getMinX() - NEIGHBOR_BLOCK_RADIUS, - origin.getMinY() - NEIGHBOR_BLOCK_RADIUS, - origin.getMinZ() - NEIGHBOR_BLOCK_RADIUS, - origin.getMaxX() + NEIGHBOR_BLOCK_RADIUS, - origin.getMaxY() + NEIGHBOR_BLOCK_RADIUS, - origin.getMaxZ() + NEIGHBOR_BLOCK_RADIUS); + BoundingBox volume = new BoundingBox(origin.minBlockX() - NEIGHBOR_BLOCK_RADIUS, + origin.minBlockY() - NEIGHBOR_BLOCK_RADIUS, + origin.minBlockZ() - NEIGHBOR_BLOCK_RADIUS, + origin.maxBlockX() + NEIGHBOR_BLOCK_RADIUS, + origin.maxBlockY() + NEIGHBOR_BLOCK_RADIUS, + origin.maxBlockZ() + NEIGHBOR_BLOCK_RADIUS); // The min/max bounds of the chunks copied by this slice final int minChunkX = origin.getX() - NEIGHBOR_CHUNK_RADIUS; @@ -134,17 +138,17 @@ public static ChunkRenderContext prepare(World world, ChunkSectionPos origin, Cl } @SuppressWarnings("unchecked") - public WorldSlice(ClientWorld world) { + public WorldSlice(ClientLevel world) { this.world = world; this.blockArrays = new BlockState[SECTION_ARRAY_SIZE][SECTION_BLOCK_COUNT]; - this.lightArrays = new ChunkNibbleArray[SECTION_ARRAY_SIZE][LIGHT_TYPES.length]; + this.lightArrays = new DataLayer[SECTION_ARRAY_SIZE][LIGHT_TYPES.length]; this.blockEntityArrays = new Int2ReferenceMap[SECTION_ARRAY_SIZE]; this.blockEntityRenderDataArrays = new Int2ReferenceMap[SECTION_ARRAY_SIZE]; this.biomeSlice = new BiomeSlice(); - this.biomeColors = new BiomeColorCache(this.biomeSlice, MinecraftClient.getInstance().options.getBiomeBlendRadius().getValue()); + this.biomeColors = new BiomeColorCache(this.biomeSlice, Minecraft.getInstance().options.biomeBlendRadius().get()); for (BlockState[] blockArray : this.blockArrays) { Arrays.fill(blockArray, EMPTY_BLOCK_STATE); @@ -176,8 +180,8 @@ private void copySectionData(ChunkRenderContext context, int sectionIndex) { this.unpackBlockData(this.blockArrays[sectionIndex], context, section); - this.lightArrays[sectionIndex][LightType.BLOCK.ordinal()] = section.getLightArray(LightType.BLOCK); - this.lightArrays[sectionIndex][LightType.SKY.ordinal()] = section.getLightArray(LightType.SKY); + this.lightArrays[sectionIndex][LightLayer.BLOCK.ordinal()] = section.getLightArray(LightLayer.BLOCK); + this.lightArrays[sectionIndex][LightLayer.SKY.ordinal()] = section.getLightArray(LightLayer.SKY); this.blockEntityArrays[sectionIndex] = section.getBlockEntityMap(); this.blockEntityRenderDataArrays[sectionIndex] = section.getBlockEntityRenderDataMap(); @@ -191,22 +195,22 @@ private void unpackBlockData(BlockState[] blockArray, ChunkRenderContext context var container = ReadableContainerExtended.of(section.getBlockData()); - ChunkSectionPos origin = context.getOrigin(); - ChunkSectionPos pos = section.getPosition(); + SectionPos origin = context.getOrigin(); + SectionPos pos = section.getPosition(); if (origin.equals(pos)) { container.sodium$unpack(blockArray); } else { var bounds = context.getVolume(); - int minBlockX = Math.max(bounds.getMinX(), pos.getMinX()); - int maxBlockX = Math.min(bounds.getMaxX(), pos.getMaxX()); + int minBlockX = Math.max(bounds.minX(), pos.minBlockX()); + int maxBlockX = Math.min(bounds.maxX(), pos.maxBlockX()); - int minBlockY = Math.max(bounds.getMinY(), pos.getMinY()); - int maxBlockY = Math.min(bounds.getMaxY(), pos.getMaxY()); + int minBlockY = Math.max(bounds.minY(), pos.minBlockY()); + int maxBlockY = Math.min(bounds.maxY(), pos.maxBlockY()); - int minBlockZ = Math.max(bounds.getMinZ(), pos.getMinZ()); - int maxBlockZ = Math.min(bounds.getMaxZ(), pos.getMaxZ()); + int minBlockZ = Math.max(bounds.minZ(), pos.minBlockZ()); + int maxBlockZ = Math.min(bounds.maxZ(), pos.maxBlockZ()); container.sodium$unpack(blockArray, minBlockX & 15, minBlockY & 15, minBlockZ & 15, maxBlockX & 15, maxBlockY & 15, maxBlockZ & 15); @@ -231,7 +235,7 @@ public BlockState getBlockState(BlockPos pos) { } public BlockState getBlockState(int x, int y, int z) { - if (!this.volume.contains(x, y, z)) { + if (!this.volume.isInside(x, y, z)) { return EMPTY_BLOCK_STATE; } @@ -250,19 +254,19 @@ public FluidState getFluidState(BlockPos pos) { } @Override - public float getBrightness(Direction direction, boolean shaded) { - return this.world.getBrightness(direction, shaded); + public float getShade(Direction direction, boolean shaded) { + return this.world.getShade(direction, shaded); } @Override - public LightingProvider getLightingProvider() { + public LevelLightEngine getLightEngine() { // Not thread-safe to access lighting data from off-thread, even if Minecraft allows it. throw new UnsupportedOperationException(); } @Override - public int getLightLevel(LightType type, BlockPos pos) { - if (!this.volume.contains(pos.getX(), pos.getY(), pos.getZ())) { + public int getBrightness(LightLayer type, BlockPos pos) { + if (!this.volume.isInside(pos.getX(), pos.getY(), pos.getZ())) { return 0; } @@ -281,8 +285,8 @@ public int getLightLevel(LightType type, BlockPos pos) { } @Override - public int getBaseLightLevel(BlockPos pos, int ambientDarkness) { - if (!this.volume.contains(pos.getX(), pos.getY(), pos.getZ())) { + public int getRawBrightness(BlockPos pos, int ambientDarkness) { + if (!this.volume.isInside(pos.getX(), pos.getY(), pos.getZ())) { return 0; } @@ -292,8 +296,8 @@ public int getBaseLightLevel(BlockPos pos, int ambientDarkness) { var lightArrays = this.lightArrays[getLocalSectionIndex(relX >> 4, relY >> 4, relZ >> 4)]; - var skyLightArray = lightArrays[LightType.SKY.ordinal()]; - var blockLightArray = lightArrays[LightType.BLOCK.ordinal()]; + var skyLightArray = lightArrays[LightLayer.SKY.ordinal()]; + var blockLightArray = lightArrays[LightLayer.BLOCK.ordinal()]; int localX = relX & 15; int localY = relY & 15; @@ -311,7 +315,7 @@ public BlockEntity getBlockEntity(BlockPos pos) { } public BlockEntity getBlockEntity(int x, int y, int z) { - if (!this.volume.contains(x, y, z)) { + if (!this.volume.isInside(x, y, z)) { return null; } @@ -329,7 +333,7 @@ public BlockEntity getBlockEntity(int x, int y, int z) { } @Override - public int getColor(BlockPos pos, ColorResolver resolver) { + public int getBlockTint(BlockPos pos, ColorResolver resolver) { return this.biomeColors.getColor(resolver, pos.getX(), pos.getY(), pos.getZ()); } @@ -339,8 +343,8 @@ public int getHeight() { } @Override - public int getBottomY() { - return this.world.getBottomY(); + public int getMinBuildHeight() { + return this.world.getMinBuildHeight(); } @Override @@ -350,7 +354,7 @@ public int getColor(BiomeColorSource source, int x, int y, int z) { @Override public @Nullable Object getBlockEntityRenderData(BlockPos pos) { - if (!this.volume.contains(pos.getX(), pos.getY(), pos.getZ())) { + if (!this.volume.isInside(pos.getX(), pos.getY(), pos.getZ())) { return null; } @@ -373,7 +377,7 @@ public boolean hasBiomes() { } @Override - public RegistryEntry getBiomeFabric(BlockPos pos) { + public Holder getBiomeFabric(BlockPos pos) { return this.biomeSlice.getBiome(pos.getX(), pos.getY(), pos.getZ()); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeColorCache.java b/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeColorCache.java index dea7f0ff7c..0a5e3a9577 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeColorCache.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeColorCache.java @@ -4,10 +4,10 @@ import me.jellysquid.mods.sodium.client.util.color.BoxBlur; import me.jellysquid.mods.sodium.client.util.color.BoxBlur.ColorBuffer; import me.jellysquid.mods.sodium.client.world.cloned.ChunkRenderContext; -import net.minecraft.client.color.world.BiomeColors; -import net.minecraft.util.math.MathHelper; -import net.minecraft.world.biome.Biome; -import net.minecraft.world.biome.ColorResolver; +import net.minecraft.client.renderer.BiomeColors; +import net.minecraft.util.Mth; +import net.minecraft.world.level.ColorResolver; +import net.minecraft.world.level.biome.Biome; public class BiomeColorCache { private static final int NEIGHBOR_BLOCK_RADIUS = 2; @@ -39,29 +39,29 @@ public BiomeColorCache(BiomeSlice biomeData, int blendRadius) { } public void update(ChunkRenderContext context) { - this.minX = (context.getOrigin().getMinX() - NEIGHBOR_BLOCK_RADIUS) - this.blendRadius; - this.minY = (context.getOrigin().getMinY() - NEIGHBOR_BLOCK_RADIUS); - this.minZ = (context.getOrigin().getMinZ() - NEIGHBOR_BLOCK_RADIUS) - this.blendRadius; + this.minX = (context.getOrigin().minBlockX() - NEIGHBOR_BLOCK_RADIUS) - this.blendRadius; + this.minY = (context.getOrigin().minBlockY() - NEIGHBOR_BLOCK_RADIUS); + this.minZ = (context.getOrigin().minBlockZ() - NEIGHBOR_BLOCK_RADIUS) - this.blendRadius; - this.maxX = (context.getOrigin().getMaxX() + NEIGHBOR_BLOCK_RADIUS) + this.blendRadius; - this.maxY = (context.getOrigin().getMaxY() + NEIGHBOR_BLOCK_RADIUS); - this.maxZ = (context.getOrigin().getMaxZ() + NEIGHBOR_BLOCK_RADIUS) + this.blendRadius; + this.maxX = (context.getOrigin().maxBlockX() + NEIGHBOR_BLOCK_RADIUS) + this.blendRadius; + this.maxY = (context.getOrigin().maxBlockY() + NEIGHBOR_BLOCK_RADIUS); + this.maxZ = (context.getOrigin().maxBlockZ() + NEIGHBOR_BLOCK_RADIUS) + this.blendRadius; this.populateStamp++; } public int getColor(BiomeColorSource source, int blockX, int blockY, int blockZ) { return switch (source) { - case GRASS -> getColor(BiomeColors.GRASS_COLOR, blockX, blockY, blockZ); - case FOLIAGE -> getColor(BiomeColors.FOLIAGE_COLOR, blockX, blockY, blockZ); - case WATER -> getColor(BiomeColors.WATER_COLOR, blockX, blockY, blockZ); + case GRASS -> getColor(BiomeColors.GRASS_COLOR_RESOLVER, blockX, blockY, blockZ); + case FOLIAGE -> getColor(BiomeColors.FOLIAGE_COLOR_RESOLVER, blockX, blockY, blockZ); + case WATER -> getColor(BiomeColors.WATER_COLOR_RESOLVER, blockX, blockY, blockZ); }; } public int getColor(ColorResolver resolver, int blockX, int blockY, int blockZ) { - var relX = MathHelper.clamp(blockX, this.minX, this.maxX) - this.minX; - var relY = MathHelper.clamp(blockY, this.minY, this.maxY) - this.minY; - var relZ = MathHelper.clamp(blockZ, this.minZ, this.maxZ) - this.minZ; + var relX = Mth.clamp(blockX, this.minX, this.maxX) - this.minX; + var relY = Mth.clamp(blockY, this.minY, this.maxY) - this.minY; + var relZ = Mth.clamp(blockZ, this.minZ, this.maxZ) - this.minZ; if (!this.slices.containsKey(resolver)) { this.initializeSlices(resolver); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeColorMaps.java b/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeColorMaps.java index 6d37219fdc..c89a326078 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeColorMaps.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeColorMaps.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.world.biome; -import net.minecraft.client.color.world.FoliageColors; -import net.minecraft.client.color.world.GrassColors; +import net.minecraft.world.level.FoliageColor; +import net.minecraft.world.level.GrassColor; public class BiomeColorMaps { private static final int WIDTH = 256; @@ -15,7 +15,7 @@ public static int getGrassColor(int index) { return DEFAULT_COLOR; } - return GrassColors.colorMap[index]; + return GrassColor.pixels[index]; } public static int getFoliageColor(int index) { @@ -23,7 +23,7 @@ public static int getFoliageColor(int index) { return DEFAULT_COLOR; } - return FoliageColors.colorMap[index]; + return FoliageColor.pixels[index]; } public static int getIndex(double temperature, double humidity) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeColorSource.java b/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeColorSource.java index 9a7078cafd..f7777a2ba2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeColorSource.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeColorSource.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.world.biome; -import net.minecraft.client.color.world.BiomeColors; -import net.minecraft.world.biome.ColorResolver; +import net.minecraft.client.renderer.BiomeColors; +import net.minecraft.world.level.ColorResolver; public enum BiomeColorSource { GRASS, @@ -12,11 +12,11 @@ public enum BiomeColorSource { public static final int COUNT = VALUES.length; public static BiomeColorSource from(ColorResolver resolver) { - if (resolver == BiomeColors.GRASS_COLOR) { + if (resolver == BiomeColors.GRASS_COLOR_RESOLVER) { return GRASS; - } else if (resolver == BiomeColors.FOLIAGE_COLOR) { + } else if (resolver == BiomeColors.FOLIAGE_COLOR_RESOLVER) { return FOLIAGE; - } else if (resolver == BiomeColors.WATER_COLOR) { + } else if (resolver == BiomeColors.WATER_COLOR_RESOLVER) { return WATER; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeSlice.java b/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeSlice.java index 3631699e0b..088e20edb9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeSlice.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeSlice.java @@ -3,22 +3,25 @@ import me.jellysquid.mods.sodium.client.world.BiomeSeedProvider; import me.jellysquid.mods.sodium.client.world.WorldSlice; import me.jellysquid.mods.sodium.client.world.cloned.ChunkRenderContext; -import net.minecraft.client.world.ClientWorld; -import net.minecraft.registry.RegistryKeys; -import net.minecraft.registry.entry.RegistryEntry; -import net.minecraft.util.math.MathHelper; -import net.minecraft.world.World; -import net.minecraft.world.biome.Biome; -import net.minecraft.world.biome.BiomeKeys; -import net.minecraft.world.biome.source.BiomeCoords; -import net.minecraft.world.biome.source.SeedMixer; +import me.jellysquid.mods.sodium.client.world.cloned.ClonedChunkSection; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.core.Holder; +import net.minecraft.core.Holder.Reference; +import net.minecraft.core.QuartPos; +import net.minecraft.core.registries.Registries; +import net.minecraft.util.LinearCongruentialGenerator; +import net.minecraft.util.Mth; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.Biomes; +import net.minecraft.world.level.chunk.PalettedContainerRO; public class BiomeSlice { private static final int SIZE = 3 * 4; // 3 chunks * 4 biomes per chunk // Arrays are in ZYX order @SuppressWarnings("unchecked") - private final RegistryEntry[] biomes = new RegistryEntry[SIZE * SIZE * SIZE]; + private final Holder[] biomes = new Holder[SIZE * SIZE * SIZE]; private final boolean[] uniform = new boolean[SIZE * SIZE * SIZE]; private final BiasMap bias = new BiasMap(); @@ -26,10 +29,10 @@ public class BiomeSlice { private int worldX, worldY, worldZ; - public void update(ClientWorld world, ChunkRenderContext context) { - this.worldX = context.getOrigin().getMinX() - 16; - this.worldY = context.getOrigin().getMinY() - 16; - this.worldZ = context.getOrigin().getMinZ() - 16; + public void update(ClientLevel world, ChunkRenderContext context) { + this.worldX = context.getOrigin().minBlockX() - 16; + this.worldY = context.getOrigin().minBlockY() - 16; + this.worldZ = context.getOrigin().minBlockZ() - 16; this.biomeSeed = BiomeSeedProvider.getBiomeSeed(world); @@ -39,10 +42,10 @@ public void update(ClientWorld world, ChunkRenderContext context) { this.calculateUniform(); } - private void copyBiomeData(World world, ChunkRenderContext context) { - var defaultValue = world.getRegistryManager() - .get(RegistryKeys.BIOME) - .entryOf(BiomeKeys.PLAINS); + private void copyBiomeData(Level world, ChunkRenderContext context) { + var defaultValue = world.registryAccess() + .registryOrThrow(Registries.BIOME) + .getHolderOrThrow(Biomes.PLAINS); for (int sectionX = 0; sectionX < 3; sectionX++) { for (int sectionY = 0; sectionY < 3; sectionY++) { @@ -53,7 +56,7 @@ private void copyBiomeData(World world, ChunkRenderContext context) { } } - private void copySectionBiomeData(ChunkRenderContext context, int sectionX, int sectionY, int sectionZ, RegistryEntry defaultBiome) { + private void copySectionBiomeData(ChunkRenderContext context, int sectionX, int sectionY, int sectionZ, Holder defaultBiome) { var section = context.getSections()[WorldSlice.getLocalSectionIndex(sectionX, sectionY, sectionZ)]; var biomeData = section.getBiomeData(); @@ -95,15 +98,15 @@ private void calculateBias() { for (int cellX = 1; cellX < 11; cellX++) { int worldCellX = offsetX + cellX; - long seedX = SeedMixer.mixSeed(seed, worldCellX); + long seedX = LinearCongruentialGenerator.next(seed, worldCellX); for (int cellY = 1; cellY < 11; cellY++) { int worldCellY = offsetY + cellY; - long seedXY = SeedMixer.mixSeed(seedX, worldCellY); + long seedXY = LinearCongruentialGenerator.next(seedX, worldCellY); for (int cellZ = 1; cellZ < 11; cellZ++) { int worldCellZ = offsetZ + cellZ; - long seedXYZ = SeedMixer.mixSeed(seedXY, worldCellZ); + long seedXYZ = LinearCongruentialGenerator.next(seedXY, worldCellZ); this.calculateBias(dataArrayIndex(cellX, cellY, cellZ), worldCellX, worldCellY, worldCellZ, seedXYZ); @@ -114,12 +117,12 @@ private void calculateBias() { } private void calculateBias(int index, int x, int y, int z, long seed) { - seed = SeedMixer.mixSeed(seed, x); - seed = SeedMixer.mixSeed(seed, y); - seed = SeedMixer.mixSeed(seed, z); + seed = LinearCongruentialGenerator.next(seed, x); + seed = LinearCongruentialGenerator.next(seed, y); + seed = LinearCongruentialGenerator.next(seed, z); - var gradX = getBias(seed); seed = SeedMixer.mixSeed(seed, this.biomeSeed); - var gradY = getBias(seed); seed = SeedMixer.mixSeed(seed, this.biomeSeed); + var gradX = getBias(seed); seed = LinearCongruentialGenerator.next(seed, this.biomeSeed); + var gradY = getBias(seed); seed = LinearCongruentialGenerator.next(seed, this.biomeSeed); var gradZ = getBias(seed); this.bias.set(index, gradX, gradY, gradZ); @@ -145,15 +148,15 @@ private boolean hasUniformNeighbors(int x, int y, int z) { return true; } - public RegistryEntry getBiome(int x, int y, int z) { + public Holder getBiome(int x, int y, int z) { int relX = x - this.worldX; int relY = y - this.worldY; int relZ = z - this.worldZ; int centerIndex = dataArrayIndex( - BiomeCoords.fromBlock(relX - 2), - BiomeCoords.fromBlock(relY - 2), - BiomeCoords.fromBlock(relZ - 2)); + QuartPos.fromBlock(relX - 2), + QuartPos.fromBlock(relY - 2), + QuartPos.fromBlock(relZ - 2)); if (this.uniform[centerIndex]) { return this.biomes[centerIndex]; @@ -162,18 +165,18 @@ public RegistryEntry getBiome(int x, int y, int z) { return this.getBiomeUsingVoronoi(relX, relY, relZ); } - private RegistryEntry getBiomeUsingVoronoi(int worldX, int worldY, int worldZ) { + private Holder getBiomeUsingVoronoi(int worldX, int worldY, int worldZ) { int x = worldX - 2; int y = worldY - 2; int z = worldZ - 2; - int intX = BiomeCoords.fromBlock(x); - int intY = BiomeCoords.fromBlock(y); - int intZ = BiomeCoords.fromBlock(z); + int intX = QuartPos.fromBlock(x); + int intY = QuartPos.fromBlock(y); + int intZ = QuartPos.fromBlock(z); - float fracX = BiomeCoords.method_39920(x) * 0.25f; - float fracY = BiomeCoords.method_39920(y) * 0.25f; - float fracZ = BiomeCoords.method_39920(z) * 0.25f; + float fracX = QuartPos.quartLocal(x) * 0.25f; + float fracY = QuartPos.quartLocal(y) * 0.25f; + float fracZ = QuartPos.quartLocal(z) * 0.25f; float closestDistance = Float.POSITIVE_INFINITY; int closestArrayIndex = 0; @@ -200,9 +203,9 @@ private RegistryEntry getBiomeUsingVoronoi(int worldX, int worldY, int wo float biasY = biasToVector(this.bias.getY(biasIndex)); float biasZ = biasToVector(this.bias.getZ(biasIndex)); - float distanceX = MathHelper.square(adjFracX + biasX); - float distanceY = MathHelper.square(adjFracY + biasY); - float distanceZ = MathHelper.square(adjFracZ + biasZ); + float distanceX = Mth.square(adjFracX + biasX); + float distanceY = Mth.square(adjFracY + biasY); + float distanceZ = Mth.square(adjFracZ + biasZ); float distance = distanceX + distanceY + distanceZ; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ChunkRenderContext.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ChunkRenderContext.java index c595cc1bcc..ffcad4d750 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ChunkRenderContext.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ChunkRenderContext.java @@ -1,15 +1,15 @@ package me.jellysquid.mods.sodium.client.world.cloned; -import net.minecraft.util.math.BlockBox; -import net.minecraft.util.math.ChunkSectionPos; +import net.minecraft.core.SectionPos; +import net.minecraft.world.level.levelgen.structure.BoundingBox; import org.jetbrains.annotations.Nullable; public class ChunkRenderContext { - private final ChunkSectionPos origin; + private final SectionPos origin; private final ClonedChunkSection[] sections; - private final BlockBox volume; + private final BoundingBox volume; - public ChunkRenderContext(ChunkSectionPos origin, ClonedChunkSection[] sections, BlockBox volume) { + public ChunkRenderContext(SectionPos origin, ClonedChunkSection[] sections, BoundingBox volume) { this.origin = origin; this.sections = sections; this.volume = volume; @@ -19,11 +19,11 @@ public ClonedChunkSection[] getSections() { return this.sections; } - public ChunkSectionPos getOrigin() { + public SectionPos getOrigin() { return this.origin; } - public BlockBox getVolume() { + public BoundingBox getVolume() { return this.volume; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java index 46dc1c7996..16df518764 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java @@ -1,59 +1,64 @@ package me.jellysquid.mods.sodium.client.world.cloned; import it.unimi.dsi.fastutil.ints.Int2ReferenceMap; +import it.unimi.dsi.fastutil.ints.Int2ReferenceMap.Entry; import it.unimi.dsi.fastutil.ints.Int2ReferenceMaps; import it.unimi.dsi.fastutil.ints.Int2ReferenceOpenHashMap; import me.jellysquid.mods.sodium.client.world.ReadableContainerExtended; import me.jellysquid.mods.sodium.client.world.WorldSlice; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.block.Blocks; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.registry.entry.RegistryEntry; -import net.minecraft.util.math.BlockBox; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.ChunkSectionPos; -import net.minecraft.world.LightType; -import net.minecraft.world.World; -import net.minecraft.world.biome.Biome; -import net.minecraft.world.chunk.*; -import net.minecraft.world.gen.chunk.DebugChunkGenerator; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.SectionPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LightLayer; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.DataLayer; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.PalettedContainerRO; +import net.minecraft.world.level.levelgen.DebugLevelSource; +import net.minecraft.world.level.levelgen.structure.BoundingBox; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Map; public class ClonedChunkSection { - private static final ChunkNibbleArray DEFAULT_SKY_LIGHT_ARRAY = new ChunkNibbleArray(15); - private static final ChunkNibbleArray DEFAULT_BLOCK_LIGHT_ARRAY = new ChunkNibbleArray(0); - private static final PalettedContainer DEFAULT_STATE_CONTAINER = new PalettedContainer<>(Block.STATE_IDS, Blocks.AIR.getDefaultState(), PalettedContainer.PaletteProvider.BLOCK_STATE); + private static final DataLayer DEFAULT_SKY_LIGHT_ARRAY = new DataLayer(15); + private static final DataLayer DEFAULT_BLOCK_LIGHT_ARRAY = new DataLayer(0); + private static final PalettedContainer DEFAULT_STATE_CONTAINER = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); - private final ChunkSectionPos pos; + private final SectionPos pos; private final @Nullable Int2ReferenceMap blockEntityMap; private final @Nullable Int2ReferenceMap blockEntityRenderDataMap; - private final @Nullable ChunkNibbleArray[] lightDataArrays; + private final @Nullable DataLayer[] lightDataArrays; - private final @Nullable ReadableContainer blockData; + private final @Nullable PalettedContainerRO blockData; - private final @Nullable ReadableContainer> biomeData; + private final @Nullable PalettedContainerRO> biomeData; private long lastUsedTimestamp = Long.MAX_VALUE; - public ClonedChunkSection(World world, WorldChunk chunk, @Nullable ChunkSection section, ChunkSectionPos pos) { + public ClonedChunkSection(Level world, LevelChunk chunk, @Nullable LevelChunkSection section, SectionPos pos) { this.pos = pos; - ReadableContainer blockData = null; - ReadableContainer> biomeData = null; + PalettedContainerRO blockData = null; + PalettedContainerRO> biomeData = null; Int2ReferenceMap blockEntityMap = null; Int2ReferenceMap blockEntityRenderDataMap = null; if (section != null) { - if (!section.isEmpty()) { - if (!world.isDebugWorld()) { - blockData = ReadableContainerExtended.clone(section.getBlockStateContainer()); + if (!section.hasOnlyAir()) { + if (!world.isDebug()) { + blockData = ReadableContainerExtended.clone(section.getStates()); } else { blockData = constructDebugWorldContainer(pos); } @@ -64,7 +69,7 @@ public ClonedChunkSection(World world, WorldChunk chunk, @Nullable ChunkSection } } - biomeData = ReadableContainerExtended.clone(section.getBiomeContainer()); + biomeData = ReadableContainerExtended.clone(section.getBiomes()); } this.blockData = blockData; @@ -81,26 +86,26 @@ public ClonedChunkSection(World world, WorldChunk chunk, @Nullable ChunkSection * match vanilla's odd approach of short-circuiting getBlockState calls inside its render region class. */ @NotNull - private static PalettedContainer constructDebugWorldContainer(ChunkSectionPos pos) { + private static PalettedContainer constructDebugWorldContainer(SectionPos pos) { // Fast path for sections which are guaranteed to be empty if (pos.getY() != 3 && pos.getY() != 4) return DEFAULT_STATE_CONTAINER; // We use swapUnsafe in the loops to avoid acquiring/releasing the lock on each iteration - var container = new PalettedContainer<>(Block.STATE_IDS, Blocks.AIR.getDefaultState(), PalettedContainer.PaletteProvider.BLOCK_STATE); + var container = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); if (pos.getY() == 3) { // Set the blocks at relative Y 12 (world Y 60) to barriers - BlockState barrier = Blocks.BARRIER.getDefaultState(); + BlockState barrier = Blocks.BARRIER.defaultBlockState(); for (int z = 0; z < 16; z++) { for (int x = 0; x < 16; x++) { - container.swapUnsafe(x, 12, z, barrier); + container.getAndSetUnchecked(x, 12, z, barrier); } } } else if (pos.getY() == 4) { // Set the blocks at relative Y 6 (world Y 70) to the appropriate state from the generator for (int z = 0; z < 16; z++) { for (int x = 0; x < 16; x++) { - container.swapUnsafe(x, 6, z, DebugChunkGenerator.getBlockState(ChunkSectionPos.getOffsetPos(pos.getX(), x), ChunkSectionPos.getOffsetPos(pos.getZ(), z))); + container.getAndSetUnchecked(x, 6, z, DebugLevelSource.getBlockStateFor(SectionPos.sectionToBlockCoord(pos.getX(), x), SectionPos.sectionToBlockCoord(pos.getZ(), z))); } } } @@ -108,13 +113,13 @@ private static PalettedContainer constructDebugWorldContainer(ChunkS } @NotNull - private static ChunkNibbleArray[] copyLightData(World world, ChunkSectionPos pos) { - var arrays = new ChunkNibbleArray[2]; - arrays[LightType.BLOCK.ordinal()] = copyLightArray(world, LightType.BLOCK, pos); + private static DataLayer[] copyLightData(Level world, SectionPos pos) { + var arrays = new DataLayer[2]; + arrays[LightLayer.BLOCK.ordinal()] = copyLightArray(world, LightLayer.BLOCK, pos); // Dimensions without sky-light should not have a default-initialized array - if (world.getDimension().hasSkyLight()) { - arrays[LightType.SKY.ordinal()] = copyLightArray(world, LightType.SKY, pos); + if (world.dimensionType().hasSkyLight()) { + arrays[LightLayer.SKY.ordinal()] = copyLightArray(world, LightLayer.SKY, pos); } return arrays; @@ -125,10 +130,10 @@ private static ChunkNibbleArray[] copyLightData(World world, ChunkSectionPos pos * the light array is not loaded. */ @NotNull - private static ChunkNibbleArray copyLightArray(World world, LightType type, ChunkSectionPos pos) { - var array = world.getLightingProvider() - .get(type) - .getLightSection(pos); + private static DataLayer copyLightArray(Level world, LightLayer type, SectionPos pos) { + var array = world.getLightEngine() + .getLayerListener(type) + .getDataLayerData(pos); if (array == null) { array = switch (type) { @@ -141,9 +146,9 @@ private static ChunkNibbleArray copyLightArray(World world, LightType type, Chun } @Nullable - private static Int2ReferenceMap copyBlockEntities(WorldChunk chunk, ChunkSectionPos chunkCoord) { - BlockBox box = new BlockBox(chunkCoord.getMinX(), chunkCoord.getMinY(), chunkCoord.getMinZ(), - chunkCoord.getMaxX(), chunkCoord.getMaxY(), chunkCoord.getMaxZ()); + private static Int2ReferenceMap copyBlockEntities(LevelChunk chunk, SectionPos chunkCoord) { + BoundingBox box = new BoundingBox(chunkCoord.minBlockX(), chunkCoord.minBlockY(), chunkCoord.minBlockZ(), + chunkCoord.maxBlockX(), chunkCoord.maxBlockY(), chunkCoord.maxBlockZ()); Int2ReferenceOpenHashMap blockEntities = null; @@ -152,7 +157,7 @@ private static Int2ReferenceMap copyBlockEntities(WorldChunk chunk, BlockPos pos = entry.getKey(); BlockEntity entity = entry.getValue(); - if (box.contains(pos)) { + if (box.isInside(pos)) { if (blockEntities == null) { blockEntities = new Int2ReferenceOpenHashMap<>(); } @@ -195,15 +200,15 @@ private static Int2ReferenceMap copyBlockEntityRenderData(Int2ReferenceM return blockEntityRenderDataMap; } - public ChunkSectionPos getPosition() { + public SectionPos getPosition() { return this.pos; } - public @Nullable ReadableContainer getBlockData() { + public @Nullable PalettedContainerRO getBlockData() { return this.blockData; } - public @Nullable ReadableContainer> getBiomeData() { + public @Nullable PalettedContainerRO> getBiomeData() { return this.biomeData; } @@ -215,7 +220,7 @@ public ChunkSectionPos getPosition() { return this.blockEntityRenderDataMap; } - public @Nullable ChunkNibbleArray getLightArray(LightType lightType) { + public @Nullable DataLayer getLightArray(LightLayer lightType) { return this.lightDataArrays[lightType.ordinal()]; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSectionCache.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSectionCache.java index b6d395a333..aa46f27df3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSectionCache.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSectionCache.java @@ -1,26 +1,26 @@ package me.jellysquid.mods.sodium.client.world.cloned; import it.unimi.dsi.fastutil.longs.Long2ReferenceLinkedOpenHashMap; -import net.minecraft.util.math.ChunkSectionPos; -import net.minecraft.world.World; -import net.minecraft.world.chunk.ChunkSection; -import net.minecraft.world.chunk.WorldChunk; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.concurrent.TimeUnit; +import net.minecraft.core.SectionPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; public class ClonedChunkSectionCache { private static final int MAX_CACHE_SIZE = 512; /* number of entries */ private static final long MAX_CACHE_DURATION = TimeUnit.SECONDS.toNanos(5); /* number of nanoseconds */ - private final World world; + private final Level world; private final Long2ReferenceLinkedOpenHashMap positionToEntry = new Long2ReferenceLinkedOpenHashMap<>(); private long time; // updated once per frame to be the elapsed time since application start - public ClonedChunkSectionCache(World world) { + public ClonedChunkSectionCache(Level world) { this.world = world; this.time = getMonotonicTimeSource(); } @@ -33,7 +33,7 @@ public void cleanup() { @Nullable public ClonedChunkSection acquire(int x, int y, int z) { - var pos = ChunkSectionPos.asLong(x, y, z); + var pos = SectionPos.asLong(x, y, z); var section = this.positionToEntry.getAndMoveToLast(pos); if (section == null) { @@ -53,23 +53,23 @@ public ClonedChunkSection acquire(int x, int y, int z) { @NotNull private ClonedChunkSection clone(int x, int y, int z) { - WorldChunk chunk = this.world.getChunk(x, z); + LevelChunk chunk = this.world.getChunk(x, z); if (chunk == null) { - throw new RuntimeException("Chunk is not loaded at: " + ChunkSectionPos.asLong(x, y, z)); + throw new RuntimeException("Chunk is not loaded at: " + SectionPos.asLong(x, y, z)); } - @Nullable ChunkSection section = null; + @Nullable LevelChunkSection section = null; - if (!this.world.isOutOfHeightLimit(ChunkSectionPos.getBlockCoord(y))) { - section = chunk.getSectionArray()[this.world.sectionCoordToIndex(y)]; + if (!this.world.isOutsideBuildHeight(SectionPos.sectionToBlockCoord(y))) { + section = chunk.getSections()[this.world.getSectionIndexFromSectionY(y)]; } - return new ClonedChunkSection(this.world, chunk, section, ChunkSectionPos.from(x, y, z)); + return new ClonedChunkSection(this.world, chunk, section, SectionPos.of(x, y, z)); } public void invalidate(int x, int y, int z) { - this.positionToEntry.remove(ChunkSectionPos.asLong(x, y, z)); + this.positionToEntry.remove(SectionPos.asLong(x, y, z)); } private static long getMonotonicTimeSource() { diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/MinecraftClientMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/MinecraftClientMixin.java index 7861b371a9..8a9d843a20 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/MinecraftClientMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/core/MinecraftClientMixin.java @@ -3,11 +3,10 @@ import it.unimi.dsi.fastutil.longs.LongArrayFIFOQueue; import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.gui.screen.ConfigCorruptedScreen; +import net.minecraft.client.Minecraft; +import net.minecraft.server.packs.resources.ReloadableResourceManager; +import net.minecraft.util.profiling.ProfilerFiller; import me.jellysquid.mods.sodium.client.compatibility.checks.ResourcePackScanner; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.RunArgs; -import net.minecraft.resource.ReloadableResourceManagerImpl; -import net.minecraft.util.profiler.Profiler; import org.lwjgl.opengl.GL32C; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; @@ -19,11 +18,11 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import java.util.concurrent.CompletableFuture; -@Mixin(MinecraftClient.class) +@Mixin(Minecraft.class) public class MinecraftClientMixin { @Shadow @Final - private ReloadableResourceManagerImpl resourceManager; + private ReloadableResourceManager resourceManager; @Unique private final LongArrayFIFOQueue fences = new LongArrayFIFOQueue(); @@ -31,9 +30,9 @@ public class MinecraftClientMixin { * We run this at the beginning of the frame (except for the first frame) to give the previous frame plenty of time * to render on the GPU. This allows us to stall on ClientWaitSync for less time. */ - @Inject(method = "render", at = @At("HEAD")) + @Inject(method = "runTick", at = @At("HEAD")) private void preRender(boolean tick, CallbackInfo ci) { - Profiler profiler = MinecraftClient.getInstance().getProfiler(); + ProfilerFiller profiler = Minecraft.getInstance().getProfiler(); profiler.push("wait_for_gpu"); while (this.fences.size() > SodiumClientMod.options().advanced.cpuRenderAheadLimit) { @@ -62,7 +61,7 @@ private void preRender(boolean tick, CallbackInfo ci) { profiler.pop(); } - @Inject(method = "render", at = @At("RETURN")) + @Inject(method = "runTick", at = @At("RETURN")) private void postRender(boolean tick, CallbackInfo ci) { var fence = GL32C.glFenceSync(GL32C.GL_SYNC_GPU_COMMANDS_COMPLETE, 0); @@ -76,7 +75,7 @@ private void postRender(boolean tick, CallbackInfo ci) { /** * Check for problematic core shader resource packs after the initial game launch. */ - @Inject(method = "onInitFinished", at = @At("TAIL")) + @Inject(method = "buildInitialScreens", at = @At("TAIL")) private void postInit(CallbackInfoReturnable cir) { ResourcePackScanner.checkIfCoreShaderLoaded(this.resourceManager); } @@ -84,7 +83,7 @@ private void postInit(CallbackInfoReturnable cir) { /** * Check for problematic core shader resource packs after every resource reload. */ - @Inject(method = "reloadResources()Ljava/util/concurrent/CompletableFuture;", at = @At("TAIL")) + @Inject(method = "reloadResourcePacks()Ljava/util/concurrent/CompletableFuture;", at = @At("TAIL")) private void postResourceReload(CallbackInfoReturnable> cir) { ResourcePackScanner.checkIfCoreShaderLoaded(this.resourceManager); } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/WindowMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/WindowMixin.java index d2cc7bcb3a..63aece3fe9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/WindowMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/core/WindowMixin.java @@ -1,8 +1,8 @@ package me.jellysquid.mods.sodium.mixin.core; +import com.mojang.blaze3d.platform.Window; import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.compatibility.workarounds.Workarounds; -import net.minecraft.client.util.Window; import org.lwjgl.glfw.GLFW; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/gui/WorldLoadingStateMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/gui/WorldLoadingStateMixin.java index bff42806ff..0795a9fa24 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/gui/WorldLoadingStateMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/core/gui/WorldLoadingStateMixin.java @@ -1,20 +1,20 @@ package me.jellysquid.mods.sodium.mixin.core.gui; -import net.minecraft.client.network.ClientPlayerEntity; -import net.minecraft.client.network.WorldLoadingState; -import net.minecraft.util.math.BlockPos; +import net.minecraft.client.multiplayer.LevelLoadStatusManager; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.core.BlockPos; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; -@Mixin(WorldLoadingState.class) +@Mixin(LevelLoadStatusManager.class) public class WorldLoadingStateMixin { - @Redirect(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;getBlockPos()Lnet/minecraft/util/math/BlockPos;")) - private BlockPos redirect$getPlayerBlockPosition(ClientPlayerEntity instance) { + @Redirect(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/player/LocalPlayer;blockPosition()Lnet/minecraft/core/BlockPos;")) + private BlockPos redirect$getPlayerBlockPosition(LocalPlayer instance) { // Ensure the "eye" position (which the chunk rendering code is actually concerned about) is used instead of // the "feet" position. This solves a problem where the loading screen can become stuck waiting for the chunk // at the player's feet to load, when it is determined to not be visible due to the true location of the // player's eyes. - return BlockPos.ofFloored(instance.getX(), instance.getEyeY(), instance.getZ()); + return BlockPos.containing(instance.getX(), instance.getEyeY(), instance.getZ()); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/model/colors/BlockColorsMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/model/colors/BlockColorsMixin.java index 8941076d51..7aabba754a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/model/colors/BlockColorsMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/core/model/colors/BlockColorsMixin.java @@ -3,10 +3,10 @@ import it.unimi.dsi.fastutil.objects.*; import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.model.color.interop.BlockColorsExtended; -import net.minecraft.block.Block; -import net.minecraft.client.color.block.BlockColorProvider; +import net.minecraft.client.color.block.BlockColor; import net.minecraft.client.color.block.BlockColors; -import net.minecraft.registry.Registries; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.world.level.block.Block; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; @@ -17,25 +17,25 @@ public class BlockColorsMixin implements BlockColorsExtended { // We're keeping a copy as we need to be able to iterate over the entry pairs, rather than just the values. @Unique - private final Reference2ReferenceMap blocksToColor = new Reference2ReferenceOpenHashMap<>(); + private final Reference2ReferenceMap blocksToColor = new Reference2ReferenceOpenHashMap<>(); @Unique private final ReferenceSet overridenBlocks = new ReferenceOpenHashSet<>(); - @Inject(method = "registerColorProvider", at = @At("HEAD")) - private void preRegisterColorProvider(BlockColorProvider provider, Block[] blocks, CallbackInfo ci) { + @Inject(method = "register", at = @At("HEAD")) + private void preRegisterColorProvider(BlockColor provider, Block[] blocks, CallbackInfo ci) { for (Block block : blocks) { // There will be one provider already registered for vanilla blocks, if we are replacing it, // it means a mod is using custom logic and we need to disable per-vertex coloring if (this.blocksToColor.put(block, provider) != null) { this.overridenBlocks.add(block); - SodiumClientMod.logger().info("Block {} had its color provider replaced with {} and will not use per-vertex coloring", Registries.BLOCK.getId(block), provider.toString()); + SodiumClientMod.logger().info("Block {} had its color provider replaced with {} and will not use per-vertex coloring", BuiltInRegistries.BLOCK.getKey(block), provider.toString()); } } } @Override - public Reference2ReferenceMap sodium$getProviders() { + public Reference2ReferenceMap sodium$getProviders() { return Reference2ReferenceMaps.unmodifiable(this.blocksToColor); } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/model/colors/ItemColorsMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/model/colors/ItemColorsMixin.java index f8d30bbfc4..46e0cea3b3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/model/colors/ItemColorsMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/core/model/colors/ItemColorsMixin.java @@ -3,10 +3,10 @@ import it.unimi.dsi.fastutil.objects.Reference2ReferenceMap; import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; import me.jellysquid.mods.sodium.client.model.color.interop.ItemColorsExtended; -import net.minecraft.client.color.item.ItemColorProvider; +import net.minecraft.client.color.item.ItemColor; import net.minecraft.client.color.item.ItemColors; -import net.minecraft.item.ItemConvertible; -import net.minecraft.item.ItemStack; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.ItemLike; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; @@ -16,18 +16,18 @@ @Mixin(ItemColors.class) public class ItemColorsMixin implements ItemColorsExtended { @Unique - private final Reference2ReferenceMap itemsToColor = + private final Reference2ReferenceMap itemsToColor = new Reference2ReferenceOpenHashMap<>(); @Inject(method = "register", at = @At("TAIL")) - private void preRegisterColor(ItemColorProvider provider, ItemConvertible[] items, CallbackInfo ci) { - for (ItemConvertible convertible : items) { + private void preRegisterColor(ItemColor provider, ItemLike[] items, CallbackInfo ci) { + for (ItemLike convertible : items) { this.itemsToColor.put(convertible.asItem(), provider); } } @Override - public ItemColorProvider sodium$getColorProvider(ItemStack stack) { + public ItemColor sodium$getColorProvider(ItemStack stack) { return this.itemsToColor.get(stack.getItem()); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/model/quad/BakedQuadMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/model/quad/BakedQuadMixin.java index e20ede8345..460247e9d1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/model/quad/BakedQuadMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/core/model/quad/BakedQuadMixin.java @@ -4,9 +4,9 @@ import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFlags; import me.jellysquid.mods.sodium.client.util.ModelQuadUtil; -import net.minecraft.client.render.model.BakedQuad; -import net.minecraft.client.texture.Sprite; -import net.minecraft.util.math.Direction; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.core.Direction; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -21,19 +21,19 @@ public class BakedQuadMixin implements BakedQuadView { @Shadow @Final - protected int[] vertexData; + protected int[] vertices; @Shadow @Final - protected Sprite sprite; + protected TextureAtlasSprite sprite; @Shadow @Final - protected int colorIndex; + protected int tintIndex; @Shadow @Final - protected Direction face; // This is really the light face, but we can't rename it. + protected Direction direction; // This is really the light face, but we can't rename it. @Shadow @Final @@ -49,7 +49,7 @@ public class BakedQuadMixin implements BakedQuadView { private ModelQuadFacing normalFace; @Inject(method = "", at = @At("RETURN")) - private void init(int[] vertexData, int colorIndex, Direction face, Sprite sprite, boolean shade, CallbackInfo ci) { + private void init(int[] vertexData, int colorIndex, Direction face, TextureAtlasSprite sprite, boolean shade, CallbackInfo ci) { this.normal = ModelQuadUtil.calculateNormal(this); this.normalFace = ModelQuadUtil.findNormalFace(this.normal); @@ -58,37 +58,37 @@ private void init(int[] vertexData, int colorIndex, Direction face, Sprite sprit @Override public float getX(int idx) { - return Float.intBitsToFloat(this.vertexData[vertexOffset(idx) + POSITION_INDEX]); + return Float.intBitsToFloat(this.vertices[vertexOffset(idx) + POSITION_INDEX]); } @Override public float getY(int idx) { - return Float.intBitsToFloat(this.vertexData[vertexOffset(idx) + POSITION_INDEX + 1]); + return Float.intBitsToFloat(this.vertices[vertexOffset(idx) + POSITION_INDEX + 1]); } @Override public float getZ(int idx) { - return Float.intBitsToFloat(this.vertexData[vertexOffset(idx) + POSITION_INDEX + 2]); + return Float.intBitsToFloat(this.vertices[vertexOffset(idx) + POSITION_INDEX + 2]); } @Override public int getColor(int idx) { - return this.vertexData[vertexOffset(idx) + COLOR_INDEX]; + return this.vertices[vertexOffset(idx) + COLOR_INDEX]; } @Override - public Sprite getSprite() { + public TextureAtlasSprite getSprite() { return this.sprite; } @Override public float getTexU(int idx) { - return Float.intBitsToFloat(this.vertexData[vertexOffset(idx) + TEXTURE_INDEX]); + return Float.intBitsToFloat(this.vertices[vertexOffset(idx) + TEXTURE_INDEX]); } @Override public float getTexV(int idx) { - return Float.intBitsToFloat(this.vertexData[vertexOffset(idx) + TEXTURE_INDEX + 1]); + return Float.intBitsToFloat(this.vertices[vertexOffset(idx) + TEXTURE_INDEX + 1]); } @Override @@ -98,7 +98,7 @@ public int getFlags() { @Override public int getColorIndex() { - return this.colorIndex; + return this.tintIndex; } @Override @@ -108,7 +108,7 @@ public ModelQuadFacing getNormalFace() { @Override public Direction getLightFace() { - return this.face; + return this.direction; } @Override diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/VertexFormatAccessor.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/VertexFormatAccessor.java index 9c66a5af23..9b1086e70d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/VertexFormatAccessor.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/VertexFormatAccessor.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.mixin.core.render; +import com.mojang.blaze3d.vertex.VertexFormat; import it.unimi.dsi.fastutil.ints.IntList; -import net.minecraft.client.render.VertexFormat; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/frustum/FrustumMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/frustum/FrustumMixin.java index 03fa18ddc8..36639b6ba4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/frustum/FrustumMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/frustum/FrustumMixin.java @@ -1,9 +1,9 @@ package me.jellysquid.mods.sodium.mixin.core.render.frustum; import me.jellysquid.mods.sodium.client.render.viewport.frustum.SimpleFrustum; +import net.minecraft.client.renderer.culling.Frustum; import me.jellysquid.mods.sodium.client.render.viewport.Viewport; import me.jellysquid.mods.sodium.client.render.viewport.ViewportProvider; -import net.minecraft.client.render.Frustum; import org.joml.FrustumIntersection; import org.joml.Vector3d; import org.spongepowered.asm.mixin.Final; @@ -13,20 +13,20 @@ @Mixin(Frustum.class) public class FrustumMixin implements ViewportProvider { @Shadow - private double x; + private double camX; @Shadow - private double y; + private double camY; @Shadow - private double z; + private double camZ; @Shadow @Final - private FrustumIntersection frustumIntersection; + private FrustumIntersection intersection; @Override public Viewport sodium$createViewport() { - return new Viewport(new SimpleFrustum(this.frustumIntersection), new Vector3d(this.x, this.y, this.z)); + return new Viewport(new SimpleFrustum(this.intersection), new Vector3d(this.camX, this.camY, this.camZ)); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/BufferBuilderMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/BufferBuilderMixin.java index 579273d22c..00633532d0 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/BufferBuilderMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/BufferBuilderMixin.java @@ -12,7 +12,6 @@ import net.caffeinemc.mods.sodium.api.vertex.format.VertexFormatDescription; import net.caffeinemc.mods.sodium.api.vertex.format.VertexFormatRegistry; import net.caffeinemc.mods.sodium.api.vertex.serializer.VertexSerializerRegistry; -import net.minecraft.client.render.*; import org.lwjgl.system.MemoryStack; import org.lwjgl.system.MemoryUtil; import org.objectweb.asm.Opcodes; @@ -23,25 +22,27 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.DefaultedVertexConsumer; +import com.mojang.blaze3d.vertex.VertexFormat; import java.nio.ByteBuffer; @Mixin(BufferBuilder.class) -public abstract class BufferBuilderMixin extends FixedColorVertexConsumer implements VertexBufferWriter, ExtendedBufferBuilder { +public abstract class BufferBuilderMixin extends DefaultedVertexConsumer implements VertexBufferWriter, ExtendedBufferBuilder { @Shadow - protected abstract void grow(int size); + protected abstract void ensureCapacity(int size); @Shadow private ByteBuffer buffer; @Shadow - private int vertexCount; + private int vertices; @Shadow - private int elementOffset; + private int nextElementByte; @Shadow - private VertexFormat.DrawMode drawMode; + private VertexFormat.Mode mode; @Unique private VertexFormatDescription formatDescription; @@ -52,10 +53,10 @@ public abstract class BufferBuilderMixin extends FixedColorVertexConsumer implem private SodiumBufferBuilder fastDelegate; @Inject( - method = "setFormat", + method = "switchFormat", at = @At( value = "FIELD", - target = "Lnet/minecraft/client/render/BufferBuilder;format:Lnet/minecraft/client/render/VertexFormat;", + target = "Lcom/mojang/blaze3d/vertex/BufferBuilder;format:Lcom/mojang/blaze3d/vertex/VertexFormat;", opcode = Opcodes.PUTFIELD ) ) @@ -66,7 +67,7 @@ private void onFormatChanged(VertexFormat format, CallbackInfo ci) { this.fastDelegate = this.formatDescription.isSimpleFormat() ? new SodiumBufferBuilder(this) : null; } - @Inject(method = { "reset", "resetBuilding", "begin" }, at = @At("RETURN")) + @Inject(method = { "discard", "reset", "begin" }, at = @At("RETURN")) private void resetDelegate(CallbackInfo ci) { if (this.fastDelegate != null) { this.fastDelegate.reset(); @@ -80,7 +81,7 @@ private void resetDelegate(CallbackInfo ci) { @Override public int sodium$getElementOffset() { - return this.elementOffset; + return this.nextElementByte; } @Override @@ -95,10 +96,10 @@ private void resetDelegate(CallbackInfo ci) { @Override public void sodium$moveToNextVertex() { - this.vertexCount++; - this.elementOffset += this.vertexStride; + this.vertices++; + this.nextElementByte += this.vertexStride; - this.grow(this.vertexStride); + this.ensureCapacity(this.vertexStride); if (this.shouldDuplicateVertices()) { this.duplicateVertex(); @@ -107,25 +108,25 @@ private void resetDelegate(CallbackInfo ci) { @Override public boolean sodium$usingFixedColor() { - return this.colorFixed; + return this.defaultColorSet; } @Unique private boolean shouldDuplicateVertices() { - return this.drawMode == VertexFormat.DrawMode.LINES || this.drawMode == VertexFormat.DrawMode.LINE_STRIP; + return this.mode == VertexFormat.Mode.LINES || this.mode == VertexFormat.Mode.LINE_STRIP; } @Unique private void duplicateVertex() { MemoryIntrinsics.copyMemory( - MemoryUtil.memAddress(this.buffer, this.elementOffset - this.vertexStride), - MemoryUtil.memAddress(this.buffer, this.elementOffset), + MemoryUtil.memAddress(this.buffer, this.nextElementByte - this.vertexStride), + MemoryUtil.memAddress(this.buffer, this.nextElementByte), this.vertexStride); - this.elementOffset += this.vertexStride; - this.vertexCount++; + this.nextElementByte += this.vertexStride; + this.vertices++; - this.grow(this.vertexStride); + this.ensureCapacity(this.vertexStride); } @Override @@ -138,11 +139,11 @@ public void push(MemoryStack stack, long src, int count, VertexFormatDescription var length = count * this.vertexStride; // Ensure that there is always space for 1 more vertex; see BufferBuilder.next() - this.grow(length + this.vertexStride); + this.ensureCapacity(length + this.vertexStride); // The buffer may change in the even, so we need to make sure that the // pointer is retrieved *after* the resize - var dst = MemoryUtil.memAddress(this.buffer, this.elementOffset); + var dst = MemoryUtil.memAddress(this.buffer, this.nextElementByte); if (format == this.formatDescription) { // The layout is the same, so we can just perform a memory copy @@ -153,8 +154,8 @@ public void push(MemoryStack stack, long src, int count, VertexFormatDescription this.copySlow(src, dst, count, format); } - this.vertexCount += count; - this.elementOffset += length; + this.vertices += count; + this.nextElementByte += length; } @Unique diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/OutlineVertexConsumerMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/OutlineVertexConsumerMixin.java index 158bc5b0b9..246fb0e285 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/OutlineVertexConsumerMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/OutlineVertexConsumerMixin.java @@ -1,12 +1,12 @@ package me.jellysquid.mods.sodium.mixin.core.render.immediate.consumer; +import com.mojang.blaze3d.vertex.DefaultedVertexConsumer; +import com.mojang.blaze3d.vertex.VertexConsumer; import net.caffeinemc.mods.sodium.api.util.ColorABGR; import net.caffeinemc.mods.sodium.api.vertex.attributes.CommonVertexAttribute; import net.caffeinemc.mods.sodium.api.vertex.attributes.common.ColorAttribute; import net.caffeinemc.mods.sodium.api.vertex.format.VertexFormatDescription; import net.caffeinemc.mods.sodium.api.vertex.buffer.VertexBufferWriter; -import net.minecraft.client.render.FixedColorVertexConsumer; -import net.minecraft.client.render.VertexConsumer; import org.lwjgl.system.MemoryStack; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; @@ -16,8 +16,8 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -@Mixin(targets = "net/minecraft/client/render/OutlineVertexConsumerProvider$OutlineVertexConsumer") -public abstract class OutlineVertexConsumerMixin extends FixedColorVertexConsumer implements VertexBufferWriter { +@Mixin(targets = "net/minecraft/client/renderer/OutlineBufferSource$EntityOutlineGenerator") +public abstract class OutlineVertexConsumerMixin extends DefaultedVertexConsumer implements VertexBufferWriter { @Shadow @Final private VertexConsumer delegate; @@ -38,7 +38,7 @@ public boolean canUseIntrinsics() { @Override public void push(MemoryStack stack, long ptr, int count, VertexFormatDescription format) { transform(ptr, count, format, - ColorABGR.pack(this.fixedRed, this.fixedGreen, this.fixedBlue, this.fixedAlpha)); + ColorABGR.pack(this.defaultR, this.defaultG, this.defaultB, this.defaultA)); VertexBufferWriter.of(this.delegate) .push(stack, ptr, count, format); diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/OverlayVertexConsumerMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/OverlayVertexConsumerMixin.java index 332d28e519..322d65a8bf 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/OverlayVertexConsumerMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/OverlayVertexConsumerMixin.java @@ -1,15 +1,15 @@ package me.jellysquid.mods.sodium.mixin.core.render.immediate.consumer; +import com.mojang.blaze3d.vertex.SheetedDecalTextureGenerator; +import com.mojang.blaze3d.vertex.VertexConsumer; import net.caffeinemc.mods.sodium.api.util.ColorABGR; import net.caffeinemc.mods.sodium.api.util.NormI8; import net.caffeinemc.mods.sodium.api.vertex.attributes.CommonVertexAttribute; import net.caffeinemc.mods.sodium.api.vertex.attributes.common.ColorAttribute; import net.caffeinemc.mods.sodium.api.vertex.attributes.common.TextureAttribute; import net.caffeinemc.mods.sodium.api.vertex.format.VertexFormatDescription; +import net.minecraft.core.Direction; import net.caffeinemc.mods.sodium.api.vertex.buffer.VertexBufferWriter; -import net.minecraft.client.render.OverlayVertexConsumer; -import net.minecraft.client.render.VertexConsumer; -import net.minecraft.util.math.Direction; import org.joml.Matrix3f; import org.joml.Matrix4f; import org.joml.Vector3f; @@ -24,7 +24,7 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -@Mixin(OverlayVertexConsumer.class) +@Mixin(SheetedDecalTextureGenerator.class) public class OverlayVertexConsumerMixin implements VertexBufferWriter { @Shadow @Final @@ -32,11 +32,11 @@ public class OverlayVertexConsumerMixin implements VertexBufferWriter { @Shadow @Final - private Matrix3f inverseNormalMatrix; + private Matrix3f normalInversePose; @Shadow @Final - private Matrix4f inverseTextureMatrix; + private Matrix4f cameraInversePose; @Shadow @Final @@ -58,7 +58,7 @@ public boolean canUseIntrinsics() { @Override public void push(MemoryStack stack, long ptr, int count, VertexFormatDescription format) { transform(ptr, count, format, - this.inverseNormalMatrix, this.inverseTextureMatrix, this.textureScale); + this.normalInversePose, this.cameraInversePose, this.textureScale); VertexBufferWriter.of(this.delegate) .push(stack, ptr, count, format); @@ -101,12 +101,12 @@ private static void transform(long ptr, int count, VertexFormatDescription forma normal.z = NormI8.unpackZ(packedNormal); Vector3f transformedNormal = inverseNormalMatrix.transform(normal); - Direction direction = Direction.getFacing(transformedNormal.x(), transformedNormal.y(), transformedNormal.z()); + Direction direction = Direction.getNearest(transformedNormal.x(), transformedNormal.y(), transformedNormal.z()); Vector4f transformedTexture = inverseTextureMatrix.transform(position); transformedTexture.rotateY(3.1415927F); transformedTexture.rotateX(-1.5707964F); - transformedTexture.rotate(direction.getRotationQuaternion()); + transformedTexture.rotate(direction.getRotation()); float textureU = -transformedTexture.x() * textureScale; float textureV = -transformedTexture.y() * textureScale; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/SpriteTexturedVertexConsumerMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/SpriteTexturedVertexConsumerMixin.java index de9f94d8c3..8d732c1051 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/SpriteTexturedVertexConsumerMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/SpriteTexturedVertexConsumerMixin.java @@ -1,12 +1,12 @@ package me.jellysquid.mods.sodium.mixin.core.render.immediate.consumer; +import com.mojang.blaze3d.vertex.VertexConsumer; import net.caffeinemc.mods.sodium.api.vertex.attributes.CommonVertexAttribute; import net.caffeinemc.mods.sodium.api.vertex.attributes.common.TextureAttribute; import net.caffeinemc.mods.sodium.api.vertex.format.VertexFormatDescription; +import net.minecraft.client.renderer.SpriteCoordinateExpander; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.caffeinemc.mods.sodium.api.vertex.buffer.VertexBufferWriter; -import net.minecraft.client.render.SpriteTexturedVertexConsumer; -import net.minecraft.client.render.VertexConsumer; -import net.minecraft.client.texture.Sprite; import org.lwjgl.system.MemoryStack; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; @@ -16,7 +16,7 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -@Mixin(SpriteTexturedVertexConsumer.class) +@Mixin(SpriteCoordinateExpander.class) public class SpriteTexturedVertexConsumerMixin implements VertexBufferWriter { @Shadow @Final @@ -32,12 +32,12 @@ public class SpriteTexturedVertexConsumerMixin implements VertexBufferWriter { private float maxU, maxV; @Inject(method = "", at = @At("RETURN")) - private void onInit(VertexConsumer delegate, Sprite sprite, CallbackInfo ci) { - this.minU = sprite.getMinU(); - this.minV = sprite.getMinV(); + private void onInit(VertexConsumer delegate, TextureAtlasSprite sprite, CallbackInfo ci) { + this.minU = sprite.getU0(); + this.minV = sprite.getV0(); - this.maxU = sprite.getMaxU(); - this.maxV = sprite.getMaxV(); + this.maxU = sprite.getU1(); + this.maxV = sprite.getV1(); this.canUseIntrinsics = VertexBufferWriter.tryOf(this.delegate) != null; } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/VertexConsumerProviderImmediateMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/VertexConsumerProviderImmediateMixin.java index ed0ae76c06..55bde3c952 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/VertexConsumerProviderImmediateMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/VertexConsumerProviderImmediateMixin.java @@ -1,20 +1,20 @@ package me.jellysquid.mods.sodium.mixin.core.render.immediate.consumer; +import com.mojang.blaze3d.vertex.VertexConsumer; import me.jellysquid.mods.sodium.client.render.vertex.buffer.ExtendedBufferBuilder; import me.jellysquid.mods.sodium.client.render.vertex.buffer.SodiumBufferBuilder; -import net.minecraft.client.render.RenderLayer; -import net.minecraft.client.render.VertexConsumer; -import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; 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.ModifyVariable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -@Mixin(VertexConsumerProvider.Immediate.class) +@Mixin(MultiBufferSource.BufferSource.class) public class VertexConsumerProviderImmediateMixin { @Inject(method = "getBuffer", at = @At("RETURN"), cancellable = true) - private void useFasterVertexConsumer(RenderLayer layer, CallbackInfoReturnable cir) { + private void useFasterVertexConsumer(RenderType layer, CallbackInfoReturnable cir) { if (cir.getReturnValue() instanceof ExtendedBufferBuilder bufferBuilder) { SodiumBufferBuilder replacement = bufferBuilder.sodium$getDelegate(); if (replacement != null) { diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/VertexConsumersMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/VertexConsumersMixin.java index c4a94e7c2b..9d4146fdc9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/VertexConsumersMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/VertexConsumersMixin.java @@ -2,8 +2,8 @@ import net.caffeinemc.mods.sodium.api.vertex.format.VertexFormatDescription; +import com.mojang.blaze3d.vertex.VertexConsumer; import net.caffeinemc.mods.sodium.api.vertex.buffer.VertexBufferWriter; -import net.minecraft.client.render.VertexConsumer; import org.lwjgl.system.MemoryStack; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; @@ -14,7 +14,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; public class VertexConsumersMixin { - @Mixin(targets = "net/minecraft/client/render/VertexConsumers$Dual") + @Mixin(targets = "com/mojang/blaze3d/vertex/VertexMultiConsumer$Double") public static class DualMixin implements VertexBufferWriter { @Shadow @Final @@ -43,7 +43,7 @@ public void push(MemoryStack stack, long ptr, int count, VertexFormatDescription } } - @Mixin(targets = "net/minecraft/client/render/VertexConsumers$Union") + @Mixin(targets = "com/mojang/blaze3d/vertex/VertexMultiConsumer$Multiple") public static class UnionMixin implements VertexBufferWriter { @Shadow @Final diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/world/BufferBuilderStorageMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/world/BufferBuilderStorageMixin.java index 3445429d3b..7127417040 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/world/BufferBuilderStorageMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/world/BufferBuilderStorageMixin.java @@ -1,16 +1,16 @@ package me.jellysquid.mods.sodium.mixin.core.render.world; import me.jellysquid.mods.sodium.client.render.chunk.NonStoringBuilderPool; -import net.minecraft.client.render.BufferBuilderStorage; -import net.minecraft.client.render.chunk.BlockBufferBuilderPool; +import net.minecraft.client.renderer.RenderBuffers; +import net.minecraft.client.renderer.SectionBufferBuilderPool; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; -@Mixin(BufferBuilderStorage.class) +@Mixin(RenderBuffers.class) public class BufferBuilderStorageMixin { - @Redirect(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/chunk/BlockBufferBuilderPool;allocate(I)Lnet/minecraft/client/render/chunk/BlockBufferBuilderPool;")) - private BlockBufferBuilderPool sodium$doNotAllocateChunks(int i) { + @Redirect(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/SectionBufferBuilderPool;allocate(I)Lnet/minecraft/client/renderer/SectionBufferBuilderPool;")) + private SectionBufferBuilderPool sodium$doNotAllocateChunks(int i) { return new NonStoringBuilderPool(); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/world/WorldRendererMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/world/WorldRendererMixin.java index c5017db25e..ba1270a078 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/world/WorldRendererMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/world/WorldRendererMixin.java @@ -1,19 +1,27 @@ package me.jellysquid.mods.sodium.mixin.core.render.world; +import com.mojang.blaze3d.vertex.PoseStack; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; +import me.jellysquid.mods.sodium.client.render.viewport.Viewport; import me.jellysquid.mods.sodium.client.render.viewport.ViewportProvider; import me.jellysquid.mods.sodium.client.util.FlawlessFrames; import me.jellysquid.mods.sodium.client.world.WorldRendererExtended; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.option.GameOptions; -import net.minecraft.client.render.*; -import net.minecraft.client.render.block.entity.BlockEntityRenderDispatcher; -import net.minecraft.client.render.entity.EntityRenderDispatcher; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.client.world.ClientWorld; -import net.minecraft.util.math.BlockPos; +import net.minecraft.client.Camera; +import net.minecraft.client.Minecraft; +import net.minecraft.client.Options; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.client.renderer.RenderBuffers; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRenderDispatcher; +import net.minecraft.client.renderer.culling.Frustum; +import net.minecraft.client.renderer.entity.EntityRenderDispatcher; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.BlockDestructionProgress; import org.jetbrains.annotations.Nullable; import org.joml.Matrix4f; import org.spongepowered.asm.mixin.*; @@ -24,19 +32,19 @@ import java.util.SortedSet; -@Mixin(WorldRenderer.class) +@Mixin(LevelRenderer.class) public abstract class WorldRendererMixin implements WorldRendererExtended { @Shadow @Final - private BufferBuilderStorage bufferBuilders; + private RenderBuffers renderBuffers; @Shadow @Final - private Long2ObjectMap> blockBreakingProgressions; + private Long2ObjectMap> destructionProgress; @Shadow @Nullable - private ClientWorld world; + private ClientLevel level; @Unique private SodiumWorldRenderer renderer; @@ -48,19 +56,19 @@ public abstract class WorldRendererMixin implements WorldRendererExtended { return this.renderer; } - @Redirect(method = "reload()V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/option/GameOptions;getClampedViewDistance()I", ordinal = 1)) - private int nullifyBuiltChunkStorage(GameOptions options) { + @Redirect(method = "allChanged()V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Options;getEffectiveRenderDistance()I", ordinal = 1)) + private int nullifyBuiltChunkStorage(Options options) { // Do not allow any resources to be allocated return 0; } @Inject(method = "", at = @At("RETURN")) - private void init(MinecraftClient client, EntityRenderDispatcher entityRenderDispatcher, BlockEntityRenderDispatcher blockEntityRenderDispatcher, BufferBuilderStorage bufferBuilderStorage, CallbackInfo ci) { + private void init(Minecraft client, EntityRenderDispatcher entityRenderDispatcher, BlockEntityRenderDispatcher blockEntityRenderDispatcher, RenderBuffers bufferBuilderStorage, CallbackInfo ci) { this.renderer = new SodiumWorldRenderer(client); } - @Inject(method = "setWorld", at = @At("RETURN")) - private void onWorldChanged(ClientWorld world, CallbackInfo ci) { + @Inject(method = "setLevel", at = @At("RETURN")) + private void onWorldChanged(ClientLevel world, CallbackInfo ci) { RenderDevice.enterManagedCode(); try { @@ -75,7 +83,7 @@ private void onWorldChanged(ClientWorld world, CallbackInfo ci) { * @author JellySquid */ @Overwrite - public int getCompletedChunkCount() { + public int countRenderedSections() { return this.renderer.getVisibleChunkCount(); } @@ -84,11 +92,11 @@ public int getCompletedChunkCount() { * @author JellySquid */ @Overwrite - public boolean isTerrainRenderComplete() { + public boolean hasRenderedAllSections() { return this.renderer.isTerrainRenderComplete(); } - @Inject(method = "scheduleTerrainUpdate", at = @At("RETURN")) + @Inject(method = "needsUpdate", at = @At("RETURN")) private void onTerrainUpdateScheduled(CallbackInfo ci) { this.renderer.scheduleTerrainUpdate(); } @@ -98,7 +106,7 @@ private void onTerrainUpdateScheduled(CallbackInfo ci) { * @author JellySquid */ @Overwrite - private void renderLayer(RenderLayer renderLayer, MatrixStack matrices, double x, double y, double z, Matrix4f matrix) { + private void renderSectionLayer(RenderType renderLayer, PoseStack matrices, double x, double y, double z, Matrix4f matrix) { RenderDevice.enterManagedCode(); try { @@ -113,7 +121,7 @@ private void renderLayer(RenderLayer renderLayer, MatrixStack matrices, double x * @author JellySquid */ @Overwrite - private void setupTerrain(Camera camera, Frustum frustum, boolean hasForcedFrustum, boolean spectator) { + private void setupRender(Camera camera, Frustum frustum, boolean hasForcedFrustum, boolean spectator) { var viewport = ((ViewportProvider) frustum).sodium$createViewport(); var updateChunksImmediately = FlawlessFrames.isActive(); @@ -132,7 +140,7 @@ private void setupTerrain(Camera camera, Frustum frustum, boolean hasForcedFrust * @author JellySquid */ @Overwrite - public void scheduleBlockRenders(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) { + public void setBlocksDirty(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) { this.renderer.scheduleRebuildForBlockArea(minX, minY, minZ, maxX, maxY, maxZ, false); } @@ -141,7 +149,7 @@ public void scheduleBlockRenders(int minX, int minY, int minZ, int maxX, int max * @author JellySquid */ @Overwrite - public void scheduleBlockRenders(int x, int y, int z) { + public void setSectionDirtyWithNeighbors(int x, int y, int z) { this.renderer.scheduleRebuildForChunks(x - 1, y - 1, z - 1, x + 1, y + 1, z + 1, false); } @@ -150,7 +158,7 @@ public void scheduleBlockRenders(int x, int y, int z) { * @author JellySquid */ @Overwrite - private void scheduleSectionRender(BlockPos pos, boolean important) { + private void setBlockDirty(BlockPos pos, boolean important) { this.renderer.scheduleRebuildForBlockArea(pos.getX() - 1, pos.getY() - 1, pos.getZ() - 1, pos.getX() + 1, pos.getY() + 1, pos.getZ() + 1, important); } @@ -159,7 +167,7 @@ private void scheduleSectionRender(BlockPos pos, boolean important) { * @author JellySquid */ @Overwrite - private void scheduleChunkRender(int x, int y, int z, boolean important) { + private void setSectionDirty(int x, int y, int z, boolean important) { this.renderer.scheduleRebuildForChunk(x, y, z, important); } @@ -168,11 +176,11 @@ private void scheduleChunkRender(int x, int y, int z, boolean important) { * @author JellySquid */ @Overwrite - public boolean isRenderingReady(BlockPos pos) { + public boolean isSectionCompiled(BlockPos pos) { return this.renderer.isSectionReady(pos.getX() >> 4, pos.getY() >> 4, pos.getZ() >> 4); } - @Inject(method = "reload()V", at = @At("RETURN")) + @Inject(method = "allChanged()V", at = @At("RETURN")) private void onReload(CallbackInfo ci) { RenderDevice.enterManagedCode(); @@ -183,9 +191,9 @@ private void onReload(CallbackInfo ci) { } } - @Inject(method = "render", at = @At(value = "FIELD", target = "Lnet/minecraft/client/render/WorldRenderer;noCullingBlockEntities:Ljava/util/Set;", shift = At.Shift.BEFORE, ordinal = 0)) - private void onRenderBlockEntities(MatrixStack matrices, float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightmapTextureManager lightmapTextureManager, Matrix4f positionMatrix, CallbackInfo ci) { - this.renderer.renderBlockEntities(matrices, this.bufferBuilders, this.blockBreakingProgressions, camera, this.world.getTickManager().isFrozen() ? 1.0F : tickDelta); + @Inject(method = "renderLevel", at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/LevelRenderer;globalBlockEntities:Ljava/util/Set;", shift = At.Shift.BEFORE, ordinal = 0)) + private void onRenderBlockEntities(PoseStack matrices, float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightTexture lightmapTextureManager, Matrix4f positionMatrix, CallbackInfo ci) { + this.renderer.renderBlockEntities(matrices, this.renderBuffers, this.destructionProgress, camera, this.level.tickRateManager().isFrozen() ? 1.0F : tickDelta); } /** @@ -193,7 +201,7 @@ private void onRenderBlockEntities(MatrixStack matrices, float tickDelta, long l * @author JellySquid */ @Overwrite - public String getChunksDebugString() { + public String getSectionStatistics() { return this.renderer.getChunksDebugString(); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/biome/ClientWorldMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/biome/ClientWorldMixin.java index 5ead646e12..eb8b47a1ef 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/biome/ClientWorldMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/biome/ClientWorldMixin.java @@ -1,14 +1,14 @@ package me.jellysquid.mods.sodium.mixin.core.world.biome; import me.jellysquid.mods.sodium.client.world.BiomeSeedProvider; -import net.minecraft.client.network.ClientPlayNetworkHandler; -import net.minecraft.client.render.WorldRenderer; -import net.minecraft.client.world.ClientWorld; -import net.minecraft.registry.RegistryKey; -import net.minecraft.registry.entry.RegistryEntry; -import net.minecraft.util.profiler.Profiler; -import net.minecraft.world.World; -import net.minecraft.world.dimension.DimensionType; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.multiplayer.ClientPacketListener; +import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.core.Holder; +import net.minecraft.resources.ResourceKey; +import net.minecraft.util.profiling.ProfilerFiller; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.dimension.DimensionType; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; @@ -17,20 +17,20 @@ import java.util.function.Supplier; -@Mixin(ClientWorld.class) +@Mixin(ClientLevel.class) public class ClientWorldMixin implements BiomeSeedProvider { @Unique private long biomeSeed; @Inject(method = "", at = @At("RETURN")) - private void captureSeed(ClientPlayNetworkHandler networkHandler, - ClientWorld.Properties properties, - RegistryKey registryRef, - RegistryEntry dimensionTypeEntry, + private void captureSeed(ClientPacketListener networkHandler, + ClientLevel.ClientLevelData properties, + ResourceKey registryRef, + Holder dimensionTypeEntry, int loadDistance, int simulationDistance, - Supplier profiler, - WorldRenderer worldRenderer, + Supplier profiler, + LevelRenderer worldRenderer, boolean debugWorld, long seed, CallbackInfo ci) { diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/chunk/EmptyPaletteStorageMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/chunk/EmptyPaletteStorageMixin.java index e82e6c1c4a..5eeca64b47 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/chunk/EmptyPaletteStorageMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/chunk/EmptyPaletteStorageMixin.java @@ -1,8 +1,8 @@ package me.jellysquid.mods.sodium.mixin.core.world.chunk; import me.jellysquid.mods.sodium.client.world.PaletteStorageExtended; -import net.minecraft.util.collection.EmptyPaletteStorage; -import net.minecraft.world.chunk.Palette; +import net.minecraft.util.ZeroBitStorage; +import net.minecraft.world.level.chunk.Palette; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -10,7 +10,7 @@ import java.util.Arrays; import java.util.Objects; -@Mixin(EmptyPaletteStorage.class) +@Mixin(ZeroBitStorage.class) public class EmptyPaletteStorageMixin implements PaletteStorageExtended { @Shadow @Final @@ -22,7 +22,7 @@ public class EmptyPaletteStorageMixin implements PaletteStorageExtended { throw new IllegalArgumentException("Array has mismatched size"); } - var defaultEntry = Objects.requireNonNull(palette.get(0), "Palette must have default entry"); + var defaultEntry = Objects.requireNonNull(palette.valueFor(0), "Palette must have default entry"); Arrays.fill(out, defaultEntry); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/chunk/PackedIntegerArrayMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/chunk/PackedIntegerArrayMixin.java index 193a5d6fb2..b942dbaeb2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/chunk/PackedIntegerArrayMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/chunk/PackedIntegerArrayMixin.java @@ -1,15 +1,15 @@ package me.jellysquid.mods.sodium.mixin.core.world.chunk; import me.jellysquid.mods.sodium.client.world.PaletteStorageExtended; -import net.minecraft.util.collection.PackedIntegerArray; -import net.minecraft.world.chunk.Palette; +import net.minecraft.util.SimpleBitStorage; +import net.minecraft.world.level.chunk.Palette; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import java.util.Objects; -@Mixin(PackedIntegerArray.class) +@Mixin(SimpleBitStorage.class) public class PackedIntegerArrayMixin implements PaletteStorageExtended { @Shadow @Final @@ -17,15 +17,15 @@ public class PackedIntegerArrayMixin implements PaletteStorageExtended { @Shadow @Final - private int elementsPerLong; + private int valuesPerLong; @Shadow @Final - private long maxValue; + private long mask; @Shadow @Final - private int elementBits; + private int bits; @Shadow @Final @@ -38,10 +38,10 @@ public class PackedIntegerArrayMixin implements PaletteStorageExtended { for (long word : this.data) { long l = word; - for (int j = 0; j < this.elementsPerLong; ++j) { - out[idx] = Objects.requireNonNull(palette.get((int) (l & this.maxValue)), + for (int j = 0; j < this.valuesPerLong; ++j) { + out[idx] = Objects.requireNonNull(palette.valueFor((int) (l & this.mask)), "Palette does not contain entry for value in storage"); - l >>= this.elementBits; + l >>= this.bits; if (++idx >= this.size) { return; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/chunk/PalettedContainerMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/chunk/PalettedContainerMixin.java index d805caeba4..b0af79ef27 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/chunk/PalettedContainerMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/chunk/PalettedContainerMixin.java @@ -2,8 +2,12 @@ import me.jellysquid.mods.sodium.client.world.PaletteStorageExtended; import me.jellysquid.mods.sodium.client.world.ReadableContainerExtended; -import net.minecraft.world.chunk.PalettedContainer; -import net.minecraft.world.chunk.ReadableContainer; +import net.minecraft.util.BitStorage; +import net.minecraft.world.level.chunk.Palette; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.PalettedContainer.Data; +import net.minecraft.world.level.chunk.PalettedContainer.Strategy; +import net.minecraft.world.level.chunk.PalettedContainerRO; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -18,16 +22,16 @@ public abstract class PalettedContainerMixin implements ReadableContainerExte @Shadow @Final - private PalettedContainer.PaletteProvider paletteProvider; + private PalettedContainer.Strategy strategy; @Shadow public abstract PalettedContainer copy(); @Override public void sodium$unpack(T[] values) { - var indexer = Objects.requireNonNull(this.paletteProvider); + var indexer = Objects.requireNonNull(this.strategy); - if (values.length != indexer.getContainerSize()) { + if (values.length != indexer.size()) { throw new IllegalArgumentException("Array is wrong size"); } @@ -39,9 +43,9 @@ public abstract class PalettedContainerMixin implements ReadableContainerExte @Override public void sodium$unpack(T[] values, int minX, int minY, int minZ, int maxX, int maxY, int maxZ) { - var indexer = Objects.requireNonNull(this.paletteProvider); + var indexer = Objects.requireNonNull(this.strategy); - if (values.length != indexer.getContainerSize()) { + if (values.length != indexer.size()) { throw new IllegalArgumentException("Array is wrong size"); } @@ -53,10 +57,10 @@ public abstract class PalettedContainerMixin implements ReadableContainerExte for (int y = minY; y <= maxY; y++) { for (int z = minZ; z <= maxZ; z++) { for (int x = minX; x <= maxX; x++) { - int localBlockIndex = indexer.computeIndex(x, y, z); + int localBlockIndex = indexer.getIndex(x, y, z); int paletteIndex = storage.get(localBlockIndex); - var paletteValue = palette.get(paletteIndex); + var paletteValue = palette.valueFor(paletteIndex); values[localBlockIndex] = paletteValue; } @@ -65,7 +69,7 @@ public abstract class PalettedContainerMixin implements ReadableContainerExte } @Override - public ReadableContainer sodium$copy() { + public PalettedContainerRO sodium$copy() { return this.copy(); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/map/ClientChunkManagerMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/map/ClientChunkManagerMixin.java index 88982fc00f..ce0749ff68 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/map/ClientChunkManagerMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/map/ClientChunkManagerMixin.java @@ -2,13 +2,13 @@ import me.jellysquid.mods.sodium.client.render.chunk.map.ChunkStatus; import me.jellysquid.mods.sodium.client.render.chunk.map.ChunkTrackerHolder; -import net.minecraft.client.world.ClientChunkManager; -import net.minecraft.client.world.ClientWorld; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.network.packet.s2c.play.ChunkData; -import net.minecraft.util.math.ChunkPos; -import net.minecraft.world.chunk.WorldChunk; +import net.minecraft.client.multiplayer.ClientChunkCache; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.chunk.LevelChunk; import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; @@ -20,35 +20,35 @@ import java.util.function.Consumer; -@Mixin(ClientChunkManager.class) +@Mixin(ClientChunkCache.class) public class ClientChunkManagerMixin { @Shadow @Final - ClientWorld world; + ClientLevel level; @Inject( - method = "unload", + method = "drop", at = @At( value = "INVOKE", - target = "Lnet/minecraft/client/world/ClientChunkManager$ClientChunkMap;compareAndSet(ILnet/minecraft/world/chunk/WorldChunk;Lnet/minecraft/world/chunk/WorldChunk;)Lnet/minecraft/world/chunk/WorldChunk;", + target = "Lnet/minecraft/client/multiplayer/ClientChunkCache$Storage;replace(ILnet/minecraft/world/level/chunk/LevelChunk;Lnet/minecraft/world/level/chunk/LevelChunk;)Lnet/minecraft/world/level/chunk/LevelChunk;", shift = At.Shift.AFTER ) ) private void onChunkUnloaded(ChunkPos pos, CallbackInfo ci) { - ChunkTrackerHolder.get(this.world) + ChunkTrackerHolder.get(this.level) .onChunkStatusRemoved(pos.x, pos.z, ChunkStatus.FLAG_HAS_BLOCK_DATA); } @Inject( - method = "loadChunkFromPacket", + method = "replaceWithPacketData", at = @At( value = "INVOKE", - target = "Lnet/minecraft/client/world/ClientWorld;resetChunkColor(Lnet/minecraft/util/math/ChunkPos;)V", + target = "Lnet/minecraft/client/multiplayer/ClientLevel;onChunkLoaded(Lnet/minecraft/world/level/ChunkPos;)V", shift = At.Shift.AFTER ) ) - private void onChunkLoaded(int chunkX, int chunkZ, PacketByteBuf buf, NbtCompound nbt, Consumer consumer, CallbackInfoReturnable<@Nullable WorldChunk> cir) { - ChunkTrackerHolder.get(this.world) + private void onChunkLoaded(int chunkX, int chunkZ, FriendlyByteBuf buf, CompoundTag nbt, Consumer consumer, CallbackInfoReturnable<@Nullable LevelChunk> cir) { + ChunkTrackerHolder.get(this.level) .onChunkStatusAdded(chunkX, chunkZ, ChunkStatus.FLAG_HAS_BLOCK_DATA); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/map/ClientPlayNetworkHandlerMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/map/ClientPlayNetworkHandlerMixin.java index f71dfefbf8..7599400a1a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/map/ClientPlayNetworkHandlerMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/map/ClientPlayNetworkHandlerMixin.java @@ -2,33 +2,33 @@ import me.jellysquid.mods.sodium.client.render.chunk.map.ChunkStatus; import me.jellysquid.mods.sodium.client.render.chunk.map.ChunkTrackerHolder; -import net.minecraft.client.network.ClientPlayNetworkHandler; -import net.minecraft.client.world.ClientWorld; -import net.minecraft.network.packet.s2c.play.LightData; -import net.minecraft.network.packet.s2c.play.UnloadChunkS2CPacket; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.multiplayer.ClientPacketListener; +import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket; +import net.minecraft.network.protocol.game.ClientboundLightUpdatePacketData; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -@Mixin(ClientPlayNetworkHandler.class) +@Mixin(ClientPacketListener.class) public class ClientPlayNetworkHandlerMixin { @Shadow - private ClientWorld world; + private ClientLevel level; @Inject( - method = "readLightData", + method = "applyLightData", at = @At("RETURN") ) - private void onLightDataReceived(int x, int z, LightData data, CallbackInfo ci) { - ChunkTrackerHolder.get(this.world) + private void onLightDataReceived(int x, int z, ClientboundLightUpdatePacketData data, CallbackInfo ci) { + ChunkTrackerHolder.get(this.level) .onChunkStatusAdded(x, z, ChunkStatus.FLAG_HAS_LIGHT_DATA); } - @Inject(method = "onUnloadChunk", at = @At("RETURN")) - private void onChunkUnloadPacket(UnloadChunkS2CPacket packet, CallbackInfo ci) { - ChunkTrackerHolder.get(this.world) + @Inject(method = "handleForgetLevelChunk", at = @At("RETURN")) + private void onChunkUnloadPacket(ClientboundForgetLevelChunkPacket packet, CallbackInfo ci) { + ChunkTrackerHolder.get(this.level) .onChunkStatusRemoved(packet.pos().x, packet.pos().z, ChunkStatus.FLAG_ALL); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/map/ClientWorldMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/map/ClientWorldMixin.java index fa914c1986..8d71cf6660 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/map/ClientWorldMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/map/ClientWorldMixin.java @@ -2,13 +2,13 @@ import me.jellysquid.mods.sodium.client.render.chunk.map.ChunkTracker; import me.jellysquid.mods.sodium.client.render.chunk.map.ChunkTrackerHolder; -import net.minecraft.client.world.ClientWorld; +import net.minecraft.client.multiplayer.ClientLevel; import org.apache.commons.lang3.Validate; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; -@Mixin(ClientWorld.class) +@Mixin(ClientLevel.class) public class ClientWorldMixin implements ChunkTrackerHolder { @Unique private final ChunkTracker chunkTracker = new ChunkTracker(); diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/AbstractTextureMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/AbstractTextureMixin.java index 8d7e7af5a5..b40c9d53c4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/AbstractTextureMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/AbstractTextureMixin.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.mixin.debug.checks; import me.jellysquid.mods.sodium.client.render.util.RenderAsserts; -import net.minecraft.client.texture.AbstractTexture; +import net.minecraft.client.renderer.texture.AbstractTexture; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; @@ -9,14 +9,14 @@ @Mixin(AbstractTexture.class) public class AbstractTextureMixin { @Redirect(method = { - "clearGlId" + "releaseId" }, at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;isOnRenderThread()Z")) private boolean validateCurrentThread$cleanup() { return RenderAsserts.validateCurrentThread(); } @Redirect(method = { - "bindTexture" + "bind" }, at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;isOnRenderThreadOrInit()Z")) private boolean validateCurrentThread$bind() { return RenderAsserts.validateCurrentThread(); diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/AsyncTextureMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/AsyncTextureMixin.java index cd09d2aaf1..e999772803 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/AsyncTextureMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/AsyncTextureMixin.java @@ -1,20 +1,20 @@ package me.jellysquid.mods.sodium.mixin.debug.checks; import me.jellysquid.mods.sodium.client.render.util.DeferredRenderTask; -import net.minecraft.client.texture.AsyncTexture; +import net.minecraft.client.renderer.texture.PreloadedTexture; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; import java.util.concurrent.Executor; -@Mixin(AsyncTexture.class) +@Mixin(PreloadedTexture.class) public class AsyncTextureMixin { /** * @author JellySquid * @reason Redirect asynchronous render commands to our helper */ @Overwrite - private static Executor createRenderThreadExecutor(Executor executor) { + private static Executor executor(Executor executor) { return DeferredRenderTask::schedule; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/BufferRendererMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/BufferRendererMixin.java index c8c2ff0f47..94f8534ef4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/BufferRendererMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/BufferRendererMixin.java @@ -1,14 +1,14 @@ package me.jellysquid.mods.sodium.mixin.debug.checks; +import com.mojang.blaze3d.vertex.BufferUploader; import me.jellysquid.mods.sodium.client.render.util.RenderAsserts; -import net.minecraft.client.render.BufferRenderer; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; -@Mixin(BufferRenderer.class) +@Mixin(BufferUploader.class) public class BufferRendererMixin { - @Redirect(method = "drawWithGlobalProgram", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;isOnRenderThreadOrInit()Z")) + @Redirect(method = "drawWithShader", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;isOnRenderThreadOrInit()Z")) private static boolean validateCurrentThread$draw() { return RenderAsserts.validateCurrentThread(); } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/FramebufferMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/FramebufferMixin.java index a83ebe9a84..ee42acc98f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/FramebufferMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/FramebufferMixin.java @@ -1,24 +1,24 @@ package me.jellysquid.mods.sodium.mixin.debug.checks; +import com.mojang.blaze3d.pipeline.RenderTarget; import me.jellysquid.mods.sodium.client.render.util.RenderAsserts; -import net.minecraft.client.gl.Framebuffer; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; -@Mixin(Framebuffer.class) +@Mixin(RenderTarget.class) public class FramebufferMixin { @Redirect(method = { "resize", - "beginWrite", - "endWrite", + "bindWrite", + "unbindWrite", }, at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;isOnRenderThread()Z")) private boolean validateCurrentThread$imageOperations() { return RenderAsserts.validateCurrentThread(); } @Redirect(method = { - "draw(IIZ)V", + "blitToScreen(IIZ)V", }, at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;isInInitPhase()Z")) private boolean validateCurrentThread$draw() { return RenderAsserts.validateCurrentThread(); diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/NativeImageBackedTextureMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/NativeImageBackedTextureMixin.java index 68325524f4..3349b66a7a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/NativeImageBackedTextureMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/NativeImageBackedTextureMixin.java @@ -1,14 +1,14 @@ package me.jellysquid.mods.sodium.mixin.debug.checks; import me.jellysquid.mods.sodium.client.render.util.RenderAsserts; -import net.minecraft.client.texture.NativeImageBackedTexture; +import net.minecraft.client.renderer.texture.DynamicTexture; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; -@Mixin(NativeImageBackedTexture.class) +@Mixin(DynamicTexture.class) public class NativeImageBackedTextureMixin { - @Redirect(method = "(Lnet/minecraft/client/texture/NativeImage;)V", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;isOnRenderThread()Z")) + @Redirect(method = "(Lcom/mojang/blaze3d/platform/NativeImage;)V", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;isOnRenderThread()Z")) private boolean validateCurrentThread$init() { return RenderAsserts.validateCurrentThread(); } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/NativeImageMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/NativeImageMixin.java index 059d3843c7..b2fce65cde 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/NativeImageMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/NativeImageMixin.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.mixin.debug.checks; +import com.mojang.blaze3d.platform.NativeImage; import me.jellysquid.mods.sodium.client.render.util.RenderAsserts; -import net.minecraft.client.texture.NativeImage; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/PlayerSkinTextureMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/PlayerSkinTextureMixin.java index d7701641fe..942106d51c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/PlayerSkinTextureMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/PlayerSkinTextureMixin.java @@ -1,27 +1,27 @@ package me.jellysquid.mods.sodium.mixin.debug.checks; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.texture.NativeImage; -import net.minecraft.client.texture.PlayerSkinTexture; +import com.mojang.blaze3d.platform.NativeImage; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.HttpTexture; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -@Mixin(PlayerSkinTexture.class) +@Mixin(HttpTexture.class) public abstract class PlayerSkinTextureMixin { @Shadow - private boolean loaded; + private boolean uploaded; @Shadow - protected abstract void uploadTexture(NativeImage image); + protected abstract void upload(NativeImage image); - @Inject(method = "onTextureLoaded", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MinecraftClient;execute(Ljava/lang/Runnable;)V", shift = At.Shift.BEFORE), cancellable = true) + @Inject(method = "loadCallback", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;execute(Ljava/lang/Runnable;)V", shift = At.Shift.BEFORE), cancellable = true) private void validateCurrentThread$loadTextureCallback(NativeImage image, CallbackInfo ci) { - MinecraftClient.getInstance().execute(() -> { - this.loaded = true; - this.uploadTexture(image); + Minecraft.getInstance().execute(() -> { + this.uploaded = true; + this.upload(image); }); ci.cancel(); diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/RenderSystemMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/RenderSystemMixin.java index 56b0aae3a2..aee88f7acb 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/RenderSystemMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/RenderSystemMixin.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.mixin.debug.checks; -import com.mojang.blaze3d.systems.RenderCall; +import com.mojang.blaze3d.pipeline.RenderCall; import com.mojang.blaze3d.systems.RenderSystem; import me.jellysquid.mods.sodium.client.render.util.DeferredRenderTask; import me.jellysquid.mods.sodium.client.render.util.RenderAsserts; @@ -33,7 +33,7 @@ private static void onReplayQueue(CallbackInfo ci) { "glGenBuffers", "glGenVertexArrays", "setShader", - "setShaderTexture(ILnet/minecraft/util/Identifier;)V", + "setShaderTexture(ILnet/minecraft/resources/ResourceLocation;)V", "setShaderTexture(II)V", "setProjectionMatrix", "setInverseViewRotationMatrix", diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/SpriteAtlasTextureMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/SpriteAtlasTextureMixin.java index fd1d91467d..e6f01b77b7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/SpriteAtlasTextureMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/SpriteAtlasTextureMixin.java @@ -1,12 +1,12 @@ package me.jellysquid.mods.sodium.mixin.debug.checks; import me.jellysquid.mods.sodium.client.render.util.RenderAsserts; -import net.minecraft.client.texture.SpriteAtlasTexture; +import net.minecraft.client.renderer.texture.TextureAtlas; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; -@Mixin(SpriteAtlasTexture.class) +@Mixin(TextureAtlas.class) public class SpriteAtlasTextureMixin { @Redirect(method = { "tick" diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/SpriteContentsAnimatorImplMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/SpriteContentsAnimatorImplMixin.java index de27505ccf..a5e0a97d21 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/SpriteContentsAnimatorImplMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/SpriteContentsAnimatorImplMixin.java @@ -1,15 +1,15 @@ package me.jellysquid.mods.sodium.mixin.debug.checks; import me.jellysquid.mods.sodium.client.render.util.RenderAsserts; -import net.minecraft.client.texture.SpriteContents; +import net.minecraft.client.renderer.texture.SpriteContents; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; -@Mixin(SpriteContents.AnimatorImpl.class) +@Mixin(SpriteContents.Ticker.class) public class SpriteContentsAnimatorImplMixin { @Redirect(method = { - "tick" + "tickAndUpload" }, at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;isOnRenderThread()Z")) private boolean validateCurrentThread$tick() { return RenderAsserts.validateCurrentThread(); diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/TextureManagerMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/TextureManagerMixin.java index 23f24d6ed5..136337719d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/TextureManagerMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/TextureManagerMixin.java @@ -2,7 +2,7 @@ import me.jellysquid.mods.sodium.client.render.util.DeferredRenderTask; import me.jellysquid.mods.sodium.client.render.util.RenderAsserts; -import net.minecraft.client.texture.TextureManager; +import net.minecraft.client.renderer.texture.TextureManager; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.injection.At; @@ -19,17 +19,17 @@ public class TextureManagerMixin { * @reason Use our own asynchronous executor for render commands */ @Overwrite - private static void runOnRenderThread(Runnable runnable) { + private static void execute(Runnable runnable) { DeferredRenderTask.schedule(runnable); } @Redirect(method = "reload", at = @At(value = "INVOKE", target = "Ljava/util/concurrent/CompletableFuture;thenAcceptAsync(Ljava/util/function/Consumer;Ljava/util/concurrent/Executor;)Ljava/util/concurrent/CompletableFuture;")) public CompletableFuture redirectReloadTask(CompletableFuture instance, Consumer consumer, Executor executor) { - return instance.thenAcceptAsync(consumer, TextureManagerMixin::runOnRenderThread); + return instance.thenAcceptAsync(consumer, TextureManagerMixin::execute); } @Redirect(method = { - "bindTexture" + "bindForSetup" }, at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;isOnRenderThread()Z")) private boolean validateCurrentThread$bindTexture() { return RenderAsserts.validateCurrentThread(); diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/VertexBufferMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/VertexBufferMixin.java index c3cc15cf64..cca9268649 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/VertexBufferMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/VertexBufferMixin.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.mixin.debug.checks; +import com.mojang.blaze3d.vertex.VertexBuffer; import me.jellysquid.mods.sodium.client.render.util.RenderAsserts; -import net.minecraft.client.gl.VertexBuffer; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; @@ -9,7 +9,7 @@ @Mixin(VertexBuffer.class) public class VertexBufferMixin { @Redirect(method = { - "draw(Lorg/joml/Matrix4f;Lorg/joml/Matrix4f;Lnet/minecraft/client/gl/ShaderProgram;)V", + "drawWithShader(Lorg/joml/Matrix4f;Lorg/joml/Matrix4f;Lnet/minecraft/client/renderer/ShaderInstance;)V", }, at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;isOnRenderThread()Z")) private boolean validateCurrentThread$draw() { return RenderAsserts.validateCurrentThread(); diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/VertexFormatMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/VertexFormatMixin.java index 10d07b738b..0e0d5405ac 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/VertexFormatMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/VertexFormatMixin.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.mixin.debug.checks; +import com.mojang.blaze3d.vertex.VertexFormat; import me.jellysquid.mods.sodium.client.render.util.RenderAsserts; -import net.minecraft.client.render.VertexFormat; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; @@ -9,8 +9,8 @@ @Mixin(VertexFormat.class) public class VertexFormatMixin { @Redirect(method = { - "setupState", - "clearState" + "setupBufferState", + "clearBufferState" }, at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;isOnRenderThread()Z")) private boolean validateCurrentThread$modifyState() { return RenderAsserts.validateCurrentThread(); diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/WindowFramebufferMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/WindowFramebufferMixin.java index 7269722b57..48c66f09f3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/WindowFramebufferMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/WindowFramebufferMixin.java @@ -1,12 +1,12 @@ package me.jellysquid.mods.sodium.mixin.debug.checks; +import com.mojang.blaze3d.pipeline.MainTarget; import me.jellysquid.mods.sodium.client.render.util.RenderAsserts; -import net.minecraft.client.gl.WindowFramebuffer; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; -@Mixin(WindowFramebuffer.class) +@Mixin(MainTarget.class) public class WindowFramebufferMixin { @Redirect(method = { "" diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/hooks/console/GameRendererMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/hooks/console/GameRendererMixin.java index e17aa85160..7c876acd87 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/hooks/console/GameRendererMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/hooks/console/GameRendererMixin.java @@ -2,10 +2,10 @@ import me.jellysquid.mods.sodium.client.gui.console.ConsoleHooks; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.render.BufferBuilderStorage; -import net.minecraft.client.render.GameRenderer; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.renderer.RenderBuffers; import org.lwjgl.glfw.GLFW; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; @@ -19,35 +19,35 @@ public class GameRendererMixin { @Shadow @Final - MinecraftClient client; + Minecraft minecraft; @Shadow @Final - private BufferBuilderStorage buffers; + private RenderBuffers renderBuffers; @Unique private static boolean HAS_RENDERED_OVERLAY_ONCE = false; - @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;draw()V", shift = At.Shift.AFTER)) + @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiGraphics;flush()V", shift = At.Shift.AFTER)) private void onRender(float tickDelta, long startTime, boolean tick, CallbackInfo ci) { // Do not start updating the console overlay until the font renderer is ready // This prevents the console from using tofu boxes for everything during early startup - if (MinecraftClient.getInstance().getOverlay() != null) { + if (Minecraft.getInstance().getOverlay() != null) { if (!HAS_RENDERED_OVERLAY_ONCE) { return; } } - this.client.getProfiler() + this.minecraft.getProfiler() .push("sodium_console_overlay"); - DrawContext drawContext = new DrawContext(this.client, this.buffers.getEntityVertexConsumers()); + GuiGraphics drawContext = new GuiGraphics(this.minecraft, this.renderBuffers.bufferSource()); ConsoleHooks.render(drawContext, GLFW.glfwGetTime()); - drawContext.draw(); + drawContext.flush(); - this.client.getProfiler() + this.minecraft.getProfiler() .pop(); HAS_RENDERED_OVERLAY_ONCE = true; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/hooks/debug/DebugHudMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/hooks/debug/DebugHudMixin.java index 82d36706b3..583a1de70e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/hooks/debug/DebugHudMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/hooks/debug/DebugHudMixin.java @@ -5,8 +5,8 @@ import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; import me.jellysquid.mods.sodium.client.util.MathUtil; import me.jellysquid.mods.sodium.client.util.NativeBuffer; -import net.minecraft.client.gui.hud.DebugHud; -import net.minecraft.util.Formatting; +import net.minecraft.ChatFormatting; +import net.minecraft.client.gui.components.DebugScreenOverlay; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; @@ -15,9 +15,9 @@ import java.lang.management.ManagementFactory; import java.util.ArrayList; -@Mixin(DebugHud.class) +@Mixin(DebugScreenOverlay.class) public abstract class DebugHudMixin { - @Redirect(method = "getRightText", at = @At(value = "INVOKE", target = "Lcom/google/common/collect/Lists;newArrayList([Ljava/lang/Object;)Ljava/util/ArrayList;", remap = false)) + @Redirect(method = "getSystemInformation", at = @At(value = "INVOKE", target = "Lcom/google/common/collect/Lists;newArrayList([Ljava/lang/Object;)Ljava/util/ArrayList;", remap = false)) private ArrayList redirectRightTextEarly(Object[] elements) { ArrayList strings = Lists.newArrayList((String[]) elements); strings.add(""); @@ -43,16 +43,16 @@ private ArrayList redirectRightTextEarly(Object[] elements) { } @Unique - private static Formatting getVersionColor() { + private static ChatFormatting getVersionColor() { String version = SodiumClientMod.getVersion(); - Formatting color; + ChatFormatting color; if (version.contains("-local")) { - color = Formatting.RED; + color = ChatFormatting.RED; } else if (version.contains("-snapshot")) { - color = Formatting.LIGHT_PURPLE; + color = ChatFormatting.LIGHT_PURPLE; } else { - color = Formatting.GREEN; + color = ChatFormatting.GREEN; } return color; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/hooks/settings/OptionsScreenMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/hooks/settings/OptionsScreenMixin.java index 330c06b9b1..19aa44f88e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/hooks/settings/OptionsScreenMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/hooks/settings/OptionsScreenMixin.java @@ -1,9 +1,9 @@ package me.jellysquid.mods.sodium.mixin.features.gui.hooks.settings; import me.jellysquid.mods.sodium.client.gui.SodiumOptionsGUI; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.gui.screen.option.OptionsScreen; -import net.minecraft.text.Text; +import net.minecraft.client.gui.screens.OptionsScreen; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; import org.spongepowered.asm.mixin.Dynamic; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -12,7 +12,7 @@ @Mixin(OptionsScreen.class) public class OptionsScreenMixin extends Screen { - protected OptionsScreenMixin(Text title) { + protected OptionsScreenMixin(Component title) { super(title); } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/screen/LevelLoadingScreenMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/screen/LevelLoadingScreenMixin.java index f6751f1853..fb22afe3ee 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/screen/LevelLoadingScreenMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/screen/LevelLoadingScreenMixin.java @@ -1,18 +1,21 @@ package me.jellysquid.mods.sodium.mixin.features.gui.screen; import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.Tesselator; +import com.mojang.blaze3d.vertex.VertexFormat; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap; import net.caffeinemc.mods.sodium.api.vertex.format.common.ColorVertex; import net.caffeinemc.mods.sodium.api.vertex.buffer.VertexBufferWriter; import net.caffeinemc.mods.sodium.api.util.ColorABGR; import net.caffeinemc.mods.sodium.api.util.ColorARGB; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.screen.world.LevelLoadingScreen; -import net.minecraft.client.render.*; - -import net.minecraft.server.WorldGenerationProgressTracker; -import net.minecraft.world.chunk.ChunkStatus; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.LevelLoadingScreen; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.server.level.progress.StoringChunkProgressListener; +import net.minecraft.world.level.chunk.ChunkStatus; import org.joml.Matrix4f; import org.lwjgl.system.MemoryStack; import org.spongepowered.asm.mixin.*; @@ -26,7 +29,7 @@ public class LevelLoadingScreenMixin { @Mutable @Shadow @Final - private static Object2IntMap STATUS_TO_COLOR; + private static Object2IntMap COLORS; @Unique private static Reference2IntOpenHashMap STATUS_TO_COLOR_FAST; @@ -47,30 +50,30 @@ public class LevelLoadingScreenMixin { * @author JellySquid */ @Overwrite - public static void drawChunkMap(DrawContext drawContext, WorldGenerationProgressTracker tracker, int mapX, int mapY, int mapScale, int mapPadding) { + public static void renderChunks(GuiGraphics drawContext, StoringChunkProgressListener tracker, int mapX, int mapY, int mapScale, int mapPadding) { if (STATUS_TO_COLOR_FAST == null) { - STATUS_TO_COLOR_FAST = new Reference2IntOpenHashMap<>(STATUS_TO_COLOR.size()); + STATUS_TO_COLOR_FAST = new Reference2IntOpenHashMap<>(COLORS.size()); STATUS_TO_COLOR_FAST.put(null, NULL_STATUS_COLOR); - STATUS_TO_COLOR.object2IntEntrySet() + COLORS.object2IntEntrySet() .forEach(entry -> STATUS_TO_COLOR_FAST.put(entry.getKey(), ColorARGB.toABGR(entry.getIntValue(), 0xFF))); } - RenderSystem.setShader(GameRenderer::getPositionColorProgram); + RenderSystem.setShader(GameRenderer::getPositionColorShader); - Matrix4f matrix = drawContext.getMatrices().peek().getPositionMatrix(); + Matrix4f matrix = drawContext.pose().last().pose(); - Tessellator tessellator = Tessellator.getInstance(); + Tesselator tessellator = Tesselator.getInstance(); RenderSystem.enableBlend(); RenderSystem.defaultBlendFunc(); - BufferBuilder bufferBuilder = tessellator.getBuffer(); - bufferBuilder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR); + BufferBuilder bufferBuilder = tessellator.getBuilder(); + bufferBuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); var writer = VertexBufferWriter.of(bufferBuilder); - int centerSize = tracker.getCenterSize(); - int size = tracker.getSize(); + int centerSize = tracker.getFullDiameter(); + int size = tracker.getDiameter(); int tileSize = mapScale + mapPadding; @@ -97,7 +100,7 @@ public static void drawChunkMap(DrawContext drawContext, WorldGenerationProgress for (int z = 0; z < size; ++z) { int tileY = mapStartY + z * tileSize; - ChunkStatus status = tracker.getChunkStatus(x, z); + ChunkStatus status = tracker.getStatus(x, z); int color; if (prevStatus == status) { @@ -113,7 +116,7 @@ public static void drawChunkMap(DrawContext drawContext, WorldGenerationProgress } } - tessellator.draw(); + tessellator.end(); RenderSystem.disableBlend(); } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/model/MultipartBakedModelMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/model/MultipartBakedModelMixin.java index d047e7110c..6c6906cc26 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/model/MultipartBakedModelMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/model/MultipartBakedModelMixin.java @@ -1,20 +1,20 @@ package me.jellysquid.mods.sodium.mixin.features.model; import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; -import net.minecraft.block.BlockState; -import net.minecraft.client.render.model.BakedModel; -import net.minecraft.client.render.model.BakedQuad; -import net.minecraft.client.render.model.MultipartBakedModel; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.random.Random; import org.apache.commons.lang3.tuple.Pair; import org.spongepowered.asm.mixin.*; import java.util.*; import java.util.concurrent.locks.StampedLock; import java.util.function.Predicate; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.MultiPartBakedModel; +import net.minecraft.core.Direction; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.block.state.BlockState; -@Mixin(MultipartBakedModel.class) +@Mixin(MultiPartBakedModel.class) public class MultipartBakedModelMixin { @Unique private final Map stateCacheFast = new Reference2ReferenceOpenHashMap<>(); @@ -23,14 +23,14 @@ public class MultipartBakedModelMixin { @Shadow @Final - private List, BakedModel>> components; + private List, BakedModel>> selectors; /** * @author JellySquid * @reason Avoid expensive allocations and replace bitfield indirection */ @Overwrite - public List getQuads(BlockState state, Direction face, Random random) { + public List getQuads(BlockState state, Direction face, RandomSource random) { if (state == null) { return Collections.emptyList(); } @@ -47,9 +47,9 @@ public List getQuads(BlockState state, Direction face, Random random) if (models == null) { long writeStamp = this.lock.writeLock(); try { - List modelList = new ArrayList<>(this.components.size()); + List modelList = new ArrayList<>(this.selectors.size()); - for (Pair, BakedModel> pair : this.components) { + for (Pair, BakedModel> pair : this.selectors) { if (pair.getLeft().test(state)) { modelList.add(pair.getRight()); } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/model/WeightedBakedModelMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/model/WeightedBakedModelMixin.java index 031d3752cf..6b9a55fa46 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/model/WeightedBakedModelMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/model/WeightedBakedModelMixin.java @@ -1,22 +1,22 @@ package me.jellysquid.mods.sodium.mixin.features.model; -import net.minecraft.block.BlockState; -import net.minecraft.client.render.model.BakedModel; -import net.minecraft.client.render.model.BakedQuad; -import net.minecraft.client.render.model.WeightedBakedModel; -import net.minecraft.util.collection.Weighted; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.random.Random; import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.*; import java.util.*; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.WeightedBakedModel; +import net.minecraft.core.Direction; +import net.minecraft.util.RandomSource; +import net.minecraft.util.random.WeightedEntry; +import net.minecraft.world.level.block.state.BlockState; @Mixin(WeightedBakedModel.class) public class WeightedBakedModelMixin { @Shadow @Final - private List> models; + private List> list; @Shadow @Final @@ -27,8 +27,8 @@ public class WeightedBakedModelMixin { * @reason Avoid excessive object allocations */ @Overwrite - public List getQuads(@Nullable BlockState state, @Nullable Direction face, Random random) { - Weighted.Present quad = getAt(this.models, Math.abs((int) random.nextLong()) % this.totalWeight); + public List getQuads(@Nullable BlockState state, @Nullable Direction face, RandomSource random) { + WeightedEntry.Wrapper quad = getAt(this.list, Math.abs((int) random.nextLong()) % this.totalWeight); if (quad != null) { return quad.getData() @@ -39,7 +39,7 @@ public List getQuads(@Nullable BlockState state, @Nullable Direction } @Unique - private static T getAt(List pool, int totalWeight) { + private static T getAt(List pool, int totalWeight) { int i = 0; int len = pool.size(); @@ -51,7 +51,7 @@ private static T getAt(List pool, int totalWeight) { } weighted = pool.get(i++); - totalWeight -= weighted.getWeight().getValue(); + totalWeight -= weighted.getWeight().asInt(); } while (totalWeight >= 0); return weighted; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/overlays/InGameHudMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/overlays/InGameHudMixin.java index 1e05760123..f854c08dcf 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/overlays/InGameHudMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/overlays/InGameHudMixin.java @@ -1,14 +1,14 @@ package me.jellysquid.mods.sodium.mixin.features.options.overlays; import me.jellysquid.mods.sodium.client.SodiumClientMod; -import net.minecraft.client.gui.hud.InGameHud; +import net.minecraft.client.gui.Gui; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; -@Mixin(InGameHud.class) +@Mixin(Gui.class) public class InGameHudMixin { - @Redirect(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MinecraftClient;isFancyGraphicsOrBetter()Z")) + @Redirect(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;useFancyGraphics()Z")) private boolean redirectFancyGraphicsVignette() { return SodiumClientMod.options().quality.enableVignette; } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/render_layers/LeavesBlockMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/render_layers/LeavesBlockMixin.java index ba16a15a4e..e508b48278 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/render_layers/LeavesBlockMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/render_layers/LeavesBlockMixin.java @@ -1,24 +1,27 @@ package me.jellysquid.mods.sodium.mixin.features.options.render_layers; import me.jellysquid.mods.sodium.client.SodiumClientMod; -import net.minecraft.block.*; -import net.minecraft.client.MinecraftClient; -import net.minecraft.util.math.Direction; +import net.minecraft.client.Minecraft; +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.LeavesBlock; +import net.minecraft.world.level.block.state.BlockState; import org.spongepowered.asm.mixin.Mixin; @Mixin(LeavesBlock.class) public class LeavesBlockMixin extends Block { public LeavesBlockMixin() { - super(Settings.copy(Blocks.AIR)); + super(Properties.ofFullCopy(Blocks.AIR)); throw new AssertionError("Mixin constructor called!"); } @Override - public boolean isSideInvisible(BlockState state, BlockState stateFrom, Direction direction) { - if (SodiumClientMod.options().quality.leavesQuality.isFancy(MinecraftClient.getInstance().options.getGraphicsMode().getValue())) { - return super.isSideInvisible(state, stateFrom, direction); + public boolean skipRendering(BlockState state, BlockState stateFrom, Direction direction) { + if (SodiumClientMod.options().quality.leavesQuality.isFancy(Minecraft.getInstance().options.graphicsMode().get())) { + return super.skipRendering(state, stateFrom, direction); } else { - return stateFrom.getBlock() instanceof LeavesBlock || super.isSideInvisible(state, stateFrom, direction); + return stateFrom.getBlock() instanceof LeavesBlock || super.skipRendering(state, stateFrom, direction); } } } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/render_layers/RenderLayersMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/render_layers/RenderLayersMixin.java index 59248cce1b..07d76d4eff 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/render_layers/RenderLayersMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/render_layers/RenderLayersMixin.java @@ -1,8 +1,8 @@ package me.jellysquid.mods.sodium.mixin.features.options.render_layers; import me.jellysquid.mods.sodium.client.SodiumClientMod; -import net.minecraft.client.option.GraphicsMode; -import net.minecraft.client.render.RenderLayers; +import net.minecraft.client.GraphicsStatus; +import net.minecraft.client.renderer.ItemBlockRenderTypes; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; @@ -10,20 +10,20 @@ import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -@Mixin(RenderLayers.class) +@Mixin(ItemBlockRenderTypes.class) public class RenderLayersMixin { @Unique private static boolean leavesFancy; @Redirect( - method = { "getBlockLayer", "getMovingBlockLayer" }, - at = @At(value = "FIELD", target = "Lnet/minecraft/client/render/RenderLayers;fancyGraphicsOrBetter:Z")) + method = { "getChunkRenderType", "getMovingBlockRenderType" }, + at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/ItemBlockRenderTypes;renderCutout:Z")) private static boolean redirectLeavesShouldBeFancy() { return leavesFancy; } - @Inject(method = "setFancyGraphicsOrBetter", at = @At("RETURN")) + @Inject(method = "setFancy", at = @At("RETURN")) private static void onSetFancyGraphicsOrBetter(boolean fancyGraphicsOrBetter, CallbackInfo ci) { - leavesFancy = SodiumClientMod.options().quality.leavesQuality.isFancy(fancyGraphicsOrBetter ? GraphicsMode.FANCY : GraphicsMode.FAST); + leavesFancy = SodiumClientMod.options().quality.leavesQuality.isFancy(fancyGraphicsOrBetter ? GraphicsStatus.FANCY : GraphicsStatus.FAST); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/weather/WorldRendererMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/weather/WorldRendererMixin.java index 4b828b66d0..8225cb9962 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/weather/WorldRendererMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/weather/WorldRendererMixin.java @@ -1,16 +1,16 @@ package me.jellysquid.mods.sodium.mixin.features.options.weather; import me.jellysquid.mods.sodium.client.SodiumClientMod; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.render.WorldRenderer; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.LevelRenderer; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; -@Mixin(WorldRenderer.class) +@Mixin(LevelRenderer.class) public class WorldRendererMixin { - @Redirect(method = "renderWeather", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MinecraftClient;isFancyGraphicsOrBetter()Z")) + @Redirect(method = "renderSnowAndRain", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;useFancyGraphics()Z")) private boolean redirectGetFancyWeather() { - return SodiumClientMod.options().quality.weatherQuality.isFancy(MinecraftClient.getInstance().options.getGraphicsMode().getValue()); + return SodiumClientMod.options().quality.weatherQuality.isFancy(Minecraft.getInstance().options.graphicsMode().get()); } } \ No newline at end of file diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/entity/CuboidMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/entity/CuboidMixin.java index 8eaf19d06e..982099afdd 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/entity/CuboidMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/entity/CuboidMixin.java @@ -2,8 +2,8 @@ import me.jellysquid.mods.sodium.client.model.ModelCuboidAccessor; import me.jellysquid.mods.sodium.client.render.immediate.model.ModelCuboid; -import net.minecraft.client.model.ModelPart; -import net.minecraft.util.math.Direction; +import net.minecraft.client.model.geom.ModelPart; +import net.minecraft.core.Direction; import org.objectweb.asm.Opcodes; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; @@ -13,13 +13,13 @@ import java.util.Set; -@Mixin(ModelPart.Cuboid.class) +@Mixin(ModelPart.Cube.class) public class CuboidMixin implements ModelCuboidAccessor { @Unique private ModelCuboid sodium$cuboid; // Inject at the start of the function, so we don't capture modified locals - @Inject(method = "", at = @At(value = "FIELD", opcode = Opcodes.PUTFIELD, target = "Lnet/minecraft/client/model/ModelPart$Cuboid;sides:[Lnet/minecraft/client/model/ModelPart$Quad;", ordinal = 0)) + @Inject(method = "", at = @At(value = "FIELD", opcode = Opcodes.PUTFIELD, target = "Lnet/minecraft/client/model/geom/ModelPart$Cube;polygons:[Lnet/minecraft/client/model/geom/ModelPart$Polygon;", ordinal = 0)) private void onInit(int u, int v, float x, float y, float z, float sizeX, float sizeY, float sizeZ, float extraX, float extraY, float extraZ, boolean mirror, float textureWidth, float textureHeight, Set renderDirections, CallbackInfo ci) { this.sodium$cuboid = new ModelCuboid(u, v, x, y, z, sizeX, sizeY, sizeZ, extraX, extraY, extraZ, mirror, textureWidth, textureHeight, renderDirections); } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/entity/ModelPartMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/entity/ModelPartMixin.java index f14eb8ee6c..ebba2d11c1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/entity/ModelPartMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/entity/ModelPartMixin.java @@ -8,14 +8,13 @@ import net.caffeinemc.mods.sodium.api.math.MatrixHelper; import net.caffeinemc.mods.sodium.api.util.ColorABGR; import net.caffeinemc.mods.sodium.api.vertex.buffer.VertexBufferWriter; -import net.minecraft.client.model.ModelPart; -import net.minecraft.client.render.VertexConsumer; -import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.model.geom.ModelPart; import org.spongepowered.asm.mixin.*; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; import java.util.Collections; import java.util.List; import java.util.Map; @@ -23,11 +22,11 @@ @Mixin(ModelPart.class) public class ModelPartMixin implements ModelPartData { @Shadow - public float pivotX; + public float x; @Shadow - public float pivotY; + public float y; @Shadow - public float pivotZ; + public float z; @Shadow public float xScale; @@ -37,21 +36,21 @@ public class ModelPartMixin implements ModelPartData { public float zScale; @Shadow - public float yaw; + public float yRot; @Shadow - public float pitch; + public float xRot; @Shadow - public float roll; + public float zRot; @Shadow public boolean visible; @Shadow - public boolean hidden; + public boolean skipDraw; @Mutable @Shadow @Final - private List cuboids; + private List cubes; @Mutable @Shadow @@ -65,7 +64,7 @@ public class ModelPartMixin implements ModelPartData { private ModelCuboid[] sodium$cuboids; @Inject(method = "", at = @At("RETURN")) - private void onInit(List cuboids, Map children, CallbackInfo ci) { + private void onInit(List cuboids, Map children, CallbackInfo ci) { var copies = new ModelCuboid[cuboids.size()]; for (int i = 0; i < cuboids.size(); i++) { @@ -78,12 +77,12 @@ private void onInit(List cuboids, Map child .toArray(ModelPart[]::new); // Try to catch errors caused by mods touching the collections after we've copied everything. - this.cuboids = Collections.unmodifiableList(this.cuboids); + this.cubes = Collections.unmodifiableList(this.cubes); this.children = Collections.unmodifiableMap(this.children); } - @Inject(method = "render(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumer;IIFFFF)V", at = @At("HEAD"), cancellable = true) - private void onRender(MatrixStack matrices, VertexConsumer vertices, int light, int overlay, float red, float green, float blue, float alpha, CallbackInfo ci) { + @Inject(method = "render(Lcom/mojang/blaze3d/vertex/PoseStack;Lcom/mojang/blaze3d/vertex/VertexConsumer;IIFFFF)V", at = @At("HEAD"), cancellable = true) + private void onRender(PoseStack matrices, VertexConsumer vertices, int light, int overlay, float red, float green, float blue, float alpha, CallbackInfo ci) { VertexBufferWriter writer = VertexConsumerUtils.convertOrLog(vertices); if (writer == null) { @@ -100,13 +99,13 @@ private void onRender(MatrixStack matrices, VertexConsumer vertices, int light, * @reason Apply transform more quickly */ @Overwrite - public void rotate(MatrixStack matrixStack) { - if (this.pivotX != 0.0F || this.pivotY != 0.0F || this.pivotZ != 0.0F) { - matrixStack.translate(this.pivotX * (1.0f / 16.0f), this.pivotY * (1.0f / 16.0f), this.pivotZ * (1.0f / 16.0f)); + public void translateAndRotate(PoseStack matrixStack) { + if (this.x != 0.0F || this.y != 0.0F || this.z != 0.0F) { + matrixStack.translate(this.x * (1.0f / 16.0f), this.y * (1.0f / 16.0f), this.z * (1.0f / 16.0f)); } - if (this.pitch != 0.0F || this.yaw != 0.0F || this.roll != 0.0F) { - MatrixHelper.rotateZYX(matrixStack.peek(), this.roll, this.yaw, this.pitch); + if (this.xRot != 0.0F || this.yRot != 0.0F || this.zRot != 0.0F) { + MatrixHelper.rotateZYX(matrixStack.last(), this.zRot, this.yRot, this.xRot); } if (this.xScale != 1.0F || this.yScale != 1.0F || this.zScale != 1.0F) { @@ -126,7 +125,7 @@ public boolean isVisible() { @Override public boolean isHidden() { - return this.hidden; + return this.skipDraw; } @Override diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/entity/cull/EntityRendererMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/entity/cull/EntityRendererMixin.java index b600ddfd51..4c900bbb42 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/entity/cull/EntityRendererMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/entity/cull/EntityRendererMixin.java @@ -1,9 +1,9 @@ package me.jellysquid.mods.sodium.mixin.features.render.entity.cull; import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; -import net.minecraft.client.render.Frustum; -import net.minecraft.client.render.entity.EntityRenderer; -import net.minecraft.entity.Entity; +import net.minecraft.client.renderer.culling.Frustum; +import net.minecraft.client.renderer.entity.EntityRenderer; +import net.minecraft.world.entity.Entity; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -11,7 +11,7 @@ @Mixin(EntityRenderer.class) public abstract class EntityRendererMixin { - @Inject(method = "shouldRender", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/Frustum;isVisible(Lnet/minecraft/util/math/Box;)Z", shift = At.Shift.AFTER), cancellable = true) + @Inject(method = "shouldRender", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/culling/Frustum;isVisible(Lnet/minecraft/world/phys/AABB;)Z", shift = At.Shift.AFTER), cancellable = true) private void preShouldRender(T entity, Frustum frustum, double x, double y, double z, CallbackInfoReturnable cir) { var renderer = SodiumWorldRenderer.instanceNullable(); diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/entity/shadows/EntityRenderDispatcherMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/entity/shadows/EntityRenderDispatcherMixin.java index 4ae373b8f8..130a1c2e8d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/entity/shadows/EntityRenderDispatcherMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/entity/shadows/EntityRenderDispatcherMixin.java @@ -1,23 +1,24 @@ package me.jellysquid.mods.sodium.mixin.features.render.entity.shadows; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; import me.jellysquid.mods.sodium.client.render.vertex.VertexConsumerUtils; import net.caffeinemc.mods.sodium.api.vertex.buffer.VertexBufferWriter; import net.caffeinemc.mods.sodium.api.vertex.format.common.ModelVertex; +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.client.renderer.entity.EntityRenderDispatcher; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.RenderShape; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.shapes.VoxelShape; import net.caffeinemc.mods.sodium.api.util.ColorABGR; import net.caffeinemc.mods.sodium.api.math.MatrixHelper; -import net.minecraft.block.BlockRenderType; -import net.minecraft.block.BlockState; -import net.minecraft.client.render.LightmapTextureManager; -import net.minecraft.client.render.OverlayTexture; -import net.minecraft.client.render.VertexConsumer; -import net.minecraft.client.render.entity.EntityRenderDispatcher; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Box; -import net.minecraft.util.math.Direction; -import net.minecraft.util.shape.VoxelShape; -import net.minecraft.world.WorldView; -import net.minecraft.world.chunk.Chunk; +import org.joml.Matrix3f; import org.joml.Matrix4f; import org.lwjgl.system.MemoryStack; import org.spongepowered.asm.mixin.Mixin; @@ -35,8 +36,8 @@ public class EntityRenderDispatcherMixin { * @author JellySquid * @reason Reduce vertex assembly overhead for shadow rendering */ - @Inject(method = "renderShadowPart", at = @At("HEAD"), cancellable = true) - private static void renderShadowPartFast(MatrixStack.Entry entry, VertexConsumer vertices, Chunk chunk, WorldView world, BlockPos pos, double x, double y, double z, float radius, float opacity, CallbackInfo ci) { + @Inject(method = "renderBlockShadow", at = @At("HEAD"), cancellable = true) + private static void renderShadowPartFast(PoseStack.Pose entry, VertexConsumer vertices, ChunkAccess chunk, LevelReader world, BlockPos pos, double x, double y, double z, float radius, float opacity, CallbackInfo ci) { var writer = VertexConsumerUtils.convertOrLog(vertices); if (writer == null) { @@ -45,26 +46,26 @@ private static void renderShadowPartFast(MatrixStack.Entry entry, VertexConsumer ci.cancel(); - BlockPos blockPos = pos.down(); + BlockPos blockPos = pos.below(); BlockState blockState = world.getBlockState(blockPos); - if (blockState.getRenderType() == BlockRenderType.INVISIBLE || !blockState.isFullCube(world, blockPos)) { + if (blockState.getRenderShape() == RenderShape.INVISIBLE || !blockState.isCollisionShapeFullBlock(world, blockPos)) { return; } - var light = world.getLightLevel(pos); + var light = world.getMaxLocalRawBrightness(pos); if (light <= 3) { return; } - VoxelShape voxelShape = blockState.getOutlineShape(world, blockPos); + VoxelShape voxelShape = blockState.getShape(world, blockPos); if (voxelShape.isEmpty()) { return; } - float brightness = LightmapTextureManager.getBrightness(world.getDimension(), light); + float brightness = LightTexture.getBrightness(world.dimensionType(), light); float alpha = (float) (((double) opacity - ((y - (double) pos.getY()) / 2.0)) * 0.5 * (double) brightness); if (alpha >= 0.0F) { @@ -72,7 +73,7 @@ private static void renderShadowPartFast(MatrixStack.Entry entry, VertexConsumer alpha = 1.0F; } - Box box = voxelShape.getBoundingBox(); + AABB box = voxelShape.bounds(); float minX = (float) ((pos.getX() + box.minX) - x); float maxX = (float) ((pos.getX() + box.maxX) - x); @@ -87,7 +88,7 @@ private static void renderShadowPartFast(MatrixStack.Entry entry, VertexConsumer } @Unique - private static void renderShadowPart(MatrixStack.Entry matrices, VertexBufferWriter writer, float radius, float alpha, float minX, float maxX, float minY, float minZ, float maxZ) { + private static void renderShadowPart(PoseStack.Pose matrices, VertexBufferWriter writer, float radius, float alpha, float minX, float maxX, float minY, float minZ, float maxZ) { float size = 0.5F * (1.0F / radius); float u1 = (-minX * size) + 0.5F; @@ -96,8 +97,8 @@ private static void renderShadowPart(MatrixStack.Entry matrices, VertexBufferWri float v1 = (-minZ * size) + 0.5F; float v2 = (-maxZ * size) + 0.5F; - var matNormal = matrices.getNormalMatrix(); - var matPosition = matrices.getPositionMatrix(); + var matNormal = matrices.normal(); + var matPosition = matrices.pose(); var color = ColorABGR.withAlpha(SHADOW_COLOR, alpha); var normal = MatrixHelper.transformNormal(matNormal, Direction.UP); @@ -129,6 +130,6 @@ private static void writeShadowVertex(long ptr, Matrix4f matPosition, float x, f float yt = MatrixHelper.transformPositionY(matPosition, x, y, z); float zt = MatrixHelper.transformPositionZ(matPosition, x, y, z); - ModelVertex.write(ptr, xt, yt, zt, color, u, v, LightmapTextureManager.MAX_LIGHT_COORDINATE, OverlayTexture.DEFAULT_UV, normal); + ModelVertex.write(ptr, xt, yt, zt, color, u, v, LightTexture.FULL_BRIGHT, OverlayTexture.NO_OVERLAY, normal); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/gui/font/GlyphRendererMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/gui/font/GlyphRendererMixin.java index f1dadb429e..c681a40e1c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/gui/font/GlyphRendererMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/gui/font/GlyphRendererMixin.java @@ -1,12 +1,12 @@ package me.jellysquid.mods.sodium.mixin.features.render.gui.font; +import com.mojang.blaze3d.vertex.VertexConsumer; import me.jellysquid.mods.sodium.client.render.vertex.VertexConsumerUtils; import net.caffeinemc.mods.sodium.api.vertex.format.common.GlyphVertex; +import net.minecraft.client.gui.font.glyphs.BakedGlyph; import net.caffeinemc.mods.sodium.api.vertex.buffer.VertexBufferWriter; import net.caffeinemc.mods.sodium.api.util.ColorABGR; import net.caffeinemc.mods.sodium.api.math.MatrixHelper; -import net.minecraft.client.font.GlyphRenderer; -import net.minecraft.client.render.VertexConsumer; import org.joml.Matrix4f; import org.lwjgl.system.MemoryStack; import org.spongepowered.asm.mixin.*; @@ -14,45 +14,45 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -@Mixin(GlyphRenderer.class) +@Mixin(BakedGlyph.class) public class GlyphRendererMixin { @Shadow @Final - private float minX; + private float left; @Shadow @Final - private float maxX; + private float right; @Shadow @Final - private float minY; + private float up; @Shadow @Final - private float maxY; + private float down; @Shadow @Final - private float minU; + private float u0; @Shadow @Final - private float minV; + private float v0; @Shadow @Final - private float maxV; + private float v1; @Shadow @Final - private float maxU; + private float u1; /** * @reason Use intrinsics * @author JellySquid */ - @Inject(method = "draw", at = @At("HEAD"), cancellable = true) + @Inject(method = "render", at = @At("HEAD"), cancellable = true) private void drawFast(boolean italic, float x, float y, Matrix4f matrix, VertexConsumer vertexConsumer, float red, float green, float blue, float alpha, int light, CallbackInfo ci) { var writer = VertexConsumerUtils.convertOrLog(vertexConsumer); @@ -62,10 +62,10 @@ private void drawFast(boolean italic, float x, float y, Matrix4f matrix, VertexC ci.cancel(); - float x1 = x + this.minX; - float x2 = x + this.maxX; - float y1 = this.minY - 3.0F; - float y2 = this.maxY - 3.0F; + float x1 = x + this.left; + float x2 = x + this.right; + float y1 = this.up - 3.0F; + float y2 = this.down - 3.0F; float h1 = y + y1; float h2 = y + y2; float w1 = italic ? 1.0F - 0.25F * y1 : 0.0F; @@ -77,16 +77,16 @@ private void drawFast(boolean italic, float x, float y, Matrix4f matrix, VertexC long buffer = stack.nmalloc(4 * GlyphVertex.STRIDE); long ptr = buffer; - write(ptr, matrix, x1 + w1, h1, 0.0F, color, this.minU, this.minV, light); + write(ptr, matrix, x1 + w1, h1, 0.0F, color, this.u0, this.v0, light); ptr += GlyphVertex.STRIDE; - write(ptr, matrix, x1 + w2, h2, 0.0F, color, this.minU, this.maxV, light); + write(ptr, matrix, x1 + w2, h2, 0.0F, color, this.u0, this.v1, light); ptr += GlyphVertex.STRIDE; - write(ptr, matrix, x2 + w2, h2, 0.0F, color, this.maxU, this.maxV, light); + write(ptr, matrix, x2 + w2, h2, 0.0F, color, this.u1, this.v1, light); ptr += GlyphVertex.STRIDE; - write(ptr, matrix, x2 + w1, h1, 0.0F, color, this.maxU, this.minV, light); + write(ptr, matrix, x2 + w1, h1, 0.0F, color, this.u1, this.v0, light); ptr += GlyphVertex.STRIDE; writer.push(stack, buffer, 4, GlyphVertex.FORMAT); diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/gui/outlines/WorldRendererMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/gui/outlines/WorldRendererMixin.java index 5734ae8f5f..b3fd807527 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/gui/outlines/WorldRendererMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/gui/outlines/WorldRendererMixin.java @@ -1,14 +1,13 @@ package me.jellysquid.mods.sodium.mixin.features.render.gui.outlines; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; import me.jellysquid.mods.sodium.client.render.vertex.VertexConsumerUtils; import net.caffeinemc.mods.sodium.api.vertex.format.common.LineVertex; +import net.minecraft.client.renderer.LevelRenderer; import net.caffeinemc.mods.sodium.api.vertex.buffer.VertexBufferWriter; import net.caffeinemc.mods.sodium.api.util.NormI8; import net.caffeinemc.mods.sodium.api.util.ColorABGR; -import net.minecraft.client.render.VertexConsumer; -import net.minecraft.client.render.WorldRenderer; -import net.minecraft.client.util.math.MatrixStack; - import org.joml.Math; import org.joml.Matrix3f; import org.joml.Matrix4f; @@ -20,14 +19,14 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -@Mixin(WorldRenderer.class) +@Mixin(LevelRenderer.class) public class WorldRendererMixin { /** * @author JellySquid * @reason Use intrinsics where possible to speed up vertex writing */ - @Inject(method = "drawBox(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumer;DDDDDDFFFFFFF)V", at = @At("HEAD"), cancellable = true) - private static void drawBoxFast(MatrixStack matrices, VertexConsumer vertexConsumer, double x1, double y1, double z1, + @Inject(method = "renderLineBox(Lcom/mojang/blaze3d/vertex/PoseStack;Lcom/mojang/blaze3d/vertex/VertexConsumer;DDDDDDFFFFFFF)V", at = @At("HEAD"), cancellable = true) + private static void drawBoxFast(PoseStack matrices, VertexConsumer vertexConsumer, double x1, double y1, double z1, double x2, double y2, double z2, float red, float green, float blue, float alpha, float xAxisRed, float yAxisGreen, float zAxisBlue, CallbackInfo ci) { var writer = VertexConsumerUtils.convertOrLog(vertexConsumer); @@ -38,8 +37,8 @@ private static void drawBoxFast(MatrixStack matrices, VertexConsumer vertexConsu ci.cancel(); - Matrix4f position = matrices.peek().getPositionMatrix(); - Matrix3f normal = matrices.peek().getNormalMatrix(); + Matrix4f position = matrices.last().pose(); + Matrix3f normal = matrices.last().normal(); float x1f = (float) x1; float y1f = (float) y1; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/DirectionMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/DirectionMixin.java index 5d05122d1a..50b950cc84 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/DirectionMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/DirectionMixin.java @@ -1,11 +1,11 @@ package me.jellysquid.mods.sodium.mixin.features.render.immediate; +import com.mojang.blaze3d.vertex.SheetedDecalTextureGenerator; import me.jellysquid.mods.sodium.mixin.core.render.immediate.consumer.OverlayVertexConsumerMixin; -import net.minecraft.client.render.OverlayVertexConsumer; -import net.minecraft.client.render.model.BakedQuadFactory; -import net.minecraft.client.render.model.json.JsonUnbakedModel; -import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.math.Direction; +import net.minecraft.client.renderer.block.model.BlockModel; +import net.minecraft.client.renderer.block.model.FaceBakery; +import net.minecraft.core.Direction; +import net.minecraft.world.phys.BlockHitResult; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; @@ -19,8 +19,8 @@ public class DirectionMixin { * * Used by: *
    - *
  • {@link OverlayVertexConsumer}
  • - *
  • UV-locked faces and cullfaces in {@link JsonUnbakedModel} and {@link BakedQuadFactory}
  • + *
  • {@link SheetedDecalTextureGenerator}
  • + *
  • UV-locked faces and cullfaces in {@link BlockModel} and {@link FaceBakery}
  • *
  • Raycasts, when creating the {@link BlockHitResult}
  • *
* @@ -29,7 +29,7 @@ public class DirectionMixin { */ @SuppressWarnings({ "StatementWithEmptyBody", "JavadocReference" }) @Overwrite - public static Direction getFacing(float x, float y, float z) { + public static Direction getNearest(float x, float y, float z) { // Vanilla quirk: return NORTH if all coordinates are zero if (x == 0 && y == 0 && z == 0) return Direction.NORTH; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/buffer_builder/intrinsics/BufferBuilderMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/buffer_builder/intrinsics/BufferBuilderMixin.java index 44cf4cab63..d36dadd954 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/buffer_builder/intrinsics/BufferBuilderMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/buffer_builder/intrinsics/BufferBuilderMixin.java @@ -1,38 +1,38 @@ package me.jellysquid.mods.sodium.mixin.features.render.immediate.buffer_builder.intrinsics; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.DefaultedVertexConsumer; +import com.mojang.blaze3d.vertex.PoseStack; import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; import me.jellysquid.mods.sodium.client.render.immediate.model.BakedModelEncoder; import me.jellysquid.mods.sodium.client.render.texture.SpriteUtil; import net.caffeinemc.mods.sodium.api.util.ColorABGR; import net.caffeinemc.mods.sodium.api.vertex.buffer.VertexBufferWriter; -import net.minecraft.client.render.BufferBuilder; -import net.minecraft.client.render.FixedColorVertexConsumer; -import net.minecraft.client.render.model.BakedQuad; -import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.renderer.block.model.BakedQuad; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @SuppressWarnings({ "SameParameterValue" }) @Mixin(BufferBuilder.class) -public abstract class BufferBuilderMixin extends FixedColorVertexConsumer { +public abstract class BufferBuilderMixin extends DefaultedVertexConsumer { @Shadow - private boolean canSkipElementChecks; + private boolean fastFormat; @Override - public void quad(MatrixStack.Entry matrices, BakedQuad bakedQuad, float r, float g, float b, int light, int overlay) { - if (!this.canSkipElementChecks) { - super.quad(matrices, bakedQuad, r, g, b, light, overlay); + public void putBulkData(PoseStack.Pose matrices, BakedQuad bakedQuad, float r, float g, float b, int light, int overlay) { + if (!this.fastFormat) { + super.putBulkData(matrices, bakedQuad, r, g, b, light, overlay); SpriteUtil.markSpriteActive(bakedQuad.getSprite()); return; } - if (this.colorFixed) { + if (this.defaultColorSet) { throw new IllegalStateException(); } - if (bakedQuad.getVertexData().length < 32) { + if (bakedQuad.getVertices().length < 32) { return; // we do not accept quads with less than 4 properly sized vertices } @@ -47,20 +47,20 @@ public void quad(MatrixStack.Entry matrices, BakedQuad bakedQuad, float r, float } @Override - public void quad(MatrixStack.Entry matrices, BakedQuad bakedQuad, float[] brightnessTable, float r, float g, float b, int[] light, int overlay, boolean colorize) { - if (!this.canSkipElementChecks) { - super.quad(matrices, bakedQuad, brightnessTable, r, g, b, light, overlay, colorize); + public void putBulkData(PoseStack.Pose matrices, BakedQuad bakedQuad, float[] brightnessTable, float r, float g, float b, int[] light, int overlay, boolean colorize) { + if (!this.fastFormat) { + super.putBulkData(matrices, bakedQuad, brightnessTable, r, g, b, light, overlay, colorize); SpriteUtil.markSpriteActive(bakedQuad.getSprite()); return; } - if (this.colorFixed) { + if (this.defaultColorSet) { throw new IllegalStateException(); } - if (bakedQuad.getVertexData().length < 32) { + if (bakedQuad.getVertices().length < 32) { return; // we do not accept quads with less than 4 properly sized vertices } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/buffer_builder/sorting/BufferBuilderMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/buffer_builder/sorting/BufferBuilderMixin.java index ee3bf0ff4e..d23c35fa72 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/buffer_builder/sorting/BufferBuilderMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/buffer_builder/sorting/BufferBuilderMixin.java @@ -1,9 +1,6 @@ package me.jellysquid.mods.sodium.mixin.features.render.immediate.buffer_builder.sorting; -import com.mojang.blaze3d.systems.VertexSorter; -import net.minecraft.client.render.BufferBuilder; -import net.minecraft.client.render.VertexFormat; import org.jetbrains.annotations.Nullable; import org.joml.Vector3f; import org.lwjgl.system.MemoryUtil; @@ -11,7 +8,9 @@ import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; - +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.VertexFormat; +import com.mojang.blaze3d.vertex.VertexSorting; import java.nio.ByteBuffer; @Mixin(BufferBuilder.class) @@ -20,39 +19,39 @@ public abstract class BufferBuilderMixin { private ByteBuffer buffer; @Shadow - private int elementOffset; + private int nextElementByte; @Shadow @Nullable - private Vector3f[] sortingPrimitiveCenters; + private Vector3f[] sortingPoints; @Shadow - private int vertexCount; + private int vertices; @Shadow private VertexFormat format; @Shadow - private int batchOffset; + private int renderedBufferPointer; @Shadow @Nullable - private VertexSorter sorter; + private VertexSorting sorting; /** * @author JellySquid * @reason Avoid slow memory accesses */ @Overwrite - private Vector3f[] buildPrimitiveCenters() { - int vertexStride = this.format.getVertexSizeByte(); - int primitiveCount = this.vertexCount / 4; + private Vector3f[] makeQuadSortingPoints() { + int vertexStride = this.format.getVertexSize(); + int primitiveCount = this.vertices / 4; Vector3f[] centers = new Vector3f[primitiveCount]; for (int index = 0; index < primitiveCount; ++index) { - long v1 = MemoryUtil.memAddress(this.buffer, this.batchOffset + (((index * 4) + 0) * vertexStride)); - long v2 = MemoryUtil.memAddress(this.buffer, this.batchOffset + (((index * 4) + 2) * vertexStride)); + long v1 = MemoryUtil.memAddress(this.buffer, this.renderedBufferPointer + (((index * 4) + 0) * vertexStride)); + long v2 = MemoryUtil.memAddress(this.buffer, this.renderedBufferPointer + (((index * 4) + 2) * vertexStride)); float x1 = MemoryUtil.memGetFloat(v1 + 0); float y1 = MemoryUtil.memGetFloat(v1 + 4); @@ -73,9 +72,9 @@ private Vector3f[] buildPrimitiveCenters() { * @reason Use direct memory access, avoid indirection */ @Overwrite - private void writeSortedIndices(VertexFormat.IndexType indexType) { - if (this.sorter != null) { - int[] indices = this.sorter.sort(this.sortingPrimitiveCenters); + private void putSortedQuadIndices(VertexFormat.IndexType indexType) { + if (this.sorting != null) { + int[] indices = this.sorting.sort(this.sortingPoints); this.writePrimitiveIndices(indexType, indices); } } @@ -85,9 +84,9 @@ private void writeSortedIndices(VertexFormat.IndexType indexType) { @Unique private void writePrimitiveIndices(VertexFormat.IndexType indexType, int[] indices) { - long ptr = MemoryUtil.memAddress(this.buffer, this.elementOffset); + long ptr = MemoryUtil.memAddress(this.buffer, this.nextElementByte); - switch (indexType.size) { + switch (indexType.bytes) { case 2 -> { // SHORT for (int index : indices) { int start = index * 4; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/buffer_builder/sorting/VertexSorterMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/buffer_builder/sorting/VertexSorterMixin.java index c3a9ff1ffa..86621396cb 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/buffer_builder/sorting/VertexSorterMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/buffer_builder/sorting/VertexSorterMixin.java @@ -1,19 +1,19 @@ package me.jellysquid.mods.sodium.mixin.features.render.immediate.buffer_builder.sorting; -import com.mojang.blaze3d.systems.VertexSorter; +import com.mojang.blaze3d.vertex.VertexSorting; import me.jellysquid.mods.sodium.client.util.sorting.VertexSorters; import org.joml.Vector3f; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; -@Mixin(VertexSorter.class) +@Mixin(VertexSorting.class) public interface VertexSorterMixin { /** * @author JellySquid * @reason Optimize vertex sorting */ @Overwrite - static VertexSorter byDistance(float x, float y, float z) { + static VertexSorting byDistance(float x, float y, float z) { return VertexSorters.sortByDistance(new Vector3f(x, y, z)); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/matrix_stack/MatrixStackMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/matrix_stack/MatrixStackMixin.java index 9f289cbc1e..9149a9fde9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/matrix_stack/MatrixStackMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/matrix_stack/MatrixStackMixin.java @@ -1,21 +1,21 @@ package me.jellysquid.mods.sodium.mixin.features.render.immediate.matrix_stack; -import net.minecraft.client.util.math.MatrixStack; import org.joml.Matrix3f; import org.joml.Matrix4f; import org.spongepowered.asm.mixin.*; - +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.PoseStack.Pose; import java.util.ArrayDeque; import java.util.Deque; -@Mixin(MatrixStack.class) +@Mixin(PoseStack.class) public abstract class MatrixStackMixin { @Shadow @Final - private Deque stack; + private Deque poseStack; @Unique - private final Deque cache = new ArrayDeque<>(); + private final Deque cache = new ArrayDeque<>(); /** @@ -23,22 +23,22 @@ public abstract class MatrixStackMixin { * @reason Re-use entries when possible */ @Overwrite - public void push() { - var prev = this.stack.getLast(); + public void pushPose() { + var prev = this.poseStack.getLast(); - MatrixStack.Entry entry; + PoseStack.Pose entry; if (!this.cache.isEmpty()) { entry = this.cache.removeLast(); - entry.getPositionMatrix() - .set(prev.getPositionMatrix()); - entry.getNormalMatrix() - .set(prev.getNormalMatrix()); + entry.pose() + .set(prev.pose()); + entry.normal() + .set(prev.normal()); } else { - entry = new MatrixStack.Entry(new Matrix4f(prev.getPositionMatrix()), new Matrix3f(prev.getNormalMatrix())); + entry = new PoseStack.Pose(new Matrix4f(prev.pose()), new Matrix3f(prev.normal())); } - this.stack.addLast(entry); + this.poseStack.addLast(entry); } /** @@ -46,7 +46,7 @@ public void push() { * @reason Re-use entries when possible */ @Overwrite - public void pop() { - this.cache.addLast(this.stack.removeLast()); + public void popPose() { + this.cache.addLast(this.poseStack.removeLast()); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/matrix_stack/VertexConsumerMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/matrix_stack/VertexConsumerMixin.java index b255904d23..8e648f14b1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/matrix_stack/VertexConsumerMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/matrix_stack/VertexConsumerMixin.java @@ -1,8 +1,7 @@ package me.jellysquid.mods.sodium.mixin.features.render.immediate.matrix_stack; +import com.mojang.blaze3d.vertex.VertexConsumer; import net.caffeinemc.mods.sodium.api.math.MatrixHelper; -import net.minecraft.client.render.VertexConsumer; - import org.joml.Matrix3f; import org.joml.Matrix4f; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/model/RenderLayersMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/model/RenderLayersMixin.java index 5e23fa932f..239f6445e7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/model/RenderLayersMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/model/RenderLayersMixin.java @@ -1,32 +1,32 @@ package me.jellysquid.mods.sodium.mixin.features.render.model; import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; -import net.minecraft.block.Block; -import net.minecraft.client.render.RenderLayer; -import net.minecraft.client.render.RenderLayers; -import net.minecraft.fluid.Fluid; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mutable; import org.spongepowered.asm.mixin.Shadow; import java.util.Map; +import net.minecraft.client.renderer.ItemBlockRenderTypes; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.material.Fluid; -@Mixin(RenderLayers.class) +@Mixin(ItemBlockRenderTypes.class) public class RenderLayersMixin { @Mutable @Shadow @Final - private static Map BLOCKS; + private static Map TYPE_BY_BLOCK; @Mutable @Shadow @Final - private static Map FLUIDS; + private static Map TYPE_BY_FLUID; static { // Replace the backing collection types with something a bit faster, since this is a hot spot in chunk rendering. - BLOCKS = new Reference2ReferenceOpenHashMap<>(BLOCKS); - FLUIDS = new Reference2ReferenceOpenHashMap<>(FLUIDS); + TYPE_BY_BLOCK = new Reference2ReferenceOpenHashMap<>(TYPE_BY_BLOCK); + TYPE_BY_FLUID = new Reference2ReferenceOpenHashMap<>(TYPE_BY_FLUID); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/model/block/BlockModelRendererMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/model/block/BlockModelRendererMixin.java index 4f790ad2a5..900f446e3b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/model/block/BlockModelRendererMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/model/block/BlockModelRendererMixin.java @@ -7,35 +7,34 @@ import me.jellysquid.mods.sodium.client.util.DirectionUtil; import net.caffeinemc.mods.sodium.api.util.ColorABGR; import net.caffeinemc.mods.sodium.api.vertex.buffer.VertexBufferWriter; -import net.minecraft.block.BlockState; -import net.minecraft.client.render.VertexConsumer; -import net.minecraft.client.render.block.BlockModelRenderer; -import net.minecraft.client.render.model.BakedModel; -import net.minecraft.client.render.model.BakedQuad; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.random.LocalRandom; -import net.minecraft.util.math.random.Random; +import net.minecraft.client.renderer.block.ModelBlockRenderer; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.Direction; +import net.minecraft.util.Mth; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.levelgen.SingleThreadedRandomSource; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; import java.util.List; -@Mixin(BlockModelRenderer.class) +@Mixin(ModelBlockRenderer.class) public class BlockModelRendererMixin { @Unique - private final Random random = new LocalRandom(42L); + private final RandomSource random = new SingleThreadedRandomSource(42L); /** * @reason Use optimized vertex writer intrinsics, avoid allocations * @author JellySquid */ - @Inject(method = "render(Lnet/minecraft/client/util/math/MatrixStack$Entry;Lnet/minecraft/client/render/VertexConsumer;Lnet/minecraft/block/BlockState;Lnet/minecraft/client/render/model/BakedModel;FFFII)V", at = @At("HEAD"), cancellable = true) - private void renderFast(MatrixStack.Entry entry, VertexConsumer vertexConsumer, BlockState blockState, BakedModel bakedModel, float red, float green, float blue, int light, int overlay, CallbackInfo ci) { + @Inject(method = "renderModel(Lcom/mojang/blaze3d/vertex/PoseStack$Pose;Lcom/mojang/blaze3d/vertex/VertexConsumer;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/client/resources/model/BakedModel;FFFII)V", at = @At("HEAD"), cancellable = true) + private void renderFast(PoseStack.Pose entry, VertexConsumer vertexConsumer, BlockState blockState, BakedModel bakedModel, float red, float green, float blue, int light, int overlay, CallbackInfo ci) { var writer = VertexConsumerUtils.convertOrLog(vertexConsumer); if(writer == null) { return; @@ -43,12 +42,12 @@ private void renderFast(MatrixStack.Entry entry, VertexConsumer vertexConsumer, ci.cancel(); - Random random = this.random; + RandomSource random = this.random; // Clamp color ranges - red = MathHelper.clamp(red, 0.0F, 1.0F); - green = MathHelper.clamp(green, 0.0F, 1.0F); - blue = MathHelper.clamp(blue, 0.0F, 1.0F); + red = Mth.clamp(red, 0.0F, 1.0F); + green = Mth.clamp(green, 0.0F, 1.0F); + blue = Mth.clamp(blue, 0.0F, 1.0F); int defaultColor = ColorABGR.pack(red, green, blue, 1.0F); @@ -71,11 +70,11 @@ private void renderFast(MatrixStack.Entry entry, VertexConsumer vertexConsumer, @Unique @SuppressWarnings("ForLoopReplaceableByForEach") - private static void renderQuads(MatrixStack.Entry matrices, VertexBufferWriter writer, int defaultColor, List quads, int light, int overlay) { + private static void renderQuads(PoseStack.Pose matrices, VertexBufferWriter writer, int defaultColor, List quads, int light, int overlay) { for (int i = 0; i < quads.size(); i++) { BakedQuad bakedQuad = quads.get(i); - if (bakedQuad.getVertexData().length < 32) { + if (bakedQuad.getVertices().length < 32) { continue; // ignore bad quads } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/model/item/ItemRendererMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/model/item/ItemRendererMixin.java index 196d4af0ab..f26f964e18 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/model/item/ItemRendererMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/model/item/ItemRendererMixin.java @@ -8,39 +8,38 @@ import me.jellysquid.mods.sodium.client.util.DirectionUtil; import net.caffeinemc.mods.sodium.api.util.ColorARGB; import net.caffeinemc.mods.sodium.api.vertex.buffer.VertexBufferWriter; -import net.minecraft.client.color.item.ItemColorProvider; +import net.minecraft.client.color.item.ItemColor; import net.minecraft.client.color.item.ItemColors; -import net.minecraft.client.render.VertexConsumer; -import net.minecraft.client.render.item.ItemRenderer; -import net.minecraft.client.render.model.BakedModel; -import net.minecraft.client.render.model.BakedQuad; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.item.ItemStack; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.random.LocalRandom; -import net.minecraft.util.math.random.Random; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.entity.ItemRenderer; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.Direction; +import net.minecraft.util.RandomSource; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.levelgen.SingleThreadedRandomSource; import org.spongepowered.asm.mixin.*; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; import java.util.List; @Mixin(ItemRenderer.class) public class ItemRendererMixin { @Unique - private final Random random = new LocalRandom(42L); + private final RandomSource random = new SingleThreadedRandomSource(42L); @Shadow @Final - private ItemColors colors; + private ItemColors itemColors; /** * @reason Avoid allocations * @author JellySquid */ - @Inject(method = "renderBakedItemModel", at = @At("HEAD"), cancellable = true) - private void renderModelFast(BakedModel model, ItemStack itemStack, int light, int overlay, MatrixStack matrixStack, VertexConsumer vertexConsumer, CallbackInfo ci) { + @Inject(method = "renderModelLists", at = @At("HEAD"), cancellable = true) + private void renderModelFast(BakedModel model, ItemStack itemStack, int light, int overlay, PoseStack matrixStack, VertexConsumer vertexConsumer, CallbackInfo ci) { var writer = VertexConsumerUtils.convertOrLog(vertexConsumer); if (writer == null) { @@ -49,13 +48,13 @@ private void renderModelFast(BakedModel model, ItemStack itemStack, int light, i ci.cancel(); - Random random = this.random; - MatrixStack.Entry matrices = matrixStack.peek(); + RandomSource random = this.random; + PoseStack.Pose matrices = matrixStack.last(); - ItemColorProvider colorProvider = null; + ItemColor colorProvider = null; if (!itemStack.isEmpty()) { - colorProvider = ((ItemColorsExtended) this.colors).sodium$getColorProvider(itemStack); + colorProvider = ((ItemColorsExtended) this.itemColors).sodium$getColorProvider(itemStack); } for (Direction direction : DirectionUtil.ALL_DIRECTIONS) { @@ -77,11 +76,11 @@ private void renderModelFast(BakedModel model, ItemStack itemStack, int light, i @Unique @SuppressWarnings("ForLoopReplaceableByForEach") - private void renderBakedItemQuads(MatrixStack.Entry matrices, VertexBufferWriter writer, List quads, ItemStack itemStack, ItemColorProvider colorProvider, int light, int overlay) { + private void renderBakedItemQuads(PoseStack.Pose matrices, VertexBufferWriter writer, List quads, ItemStack itemStack, ItemColor colorProvider, int light, int overlay) { for (int i = 0; i < quads.size(); i++) { BakedQuad bakedQuad = quads.get(i); - if (bakedQuad.getVertexData().length < 32) { + if (bakedQuad.getVertices().length < 32) { continue; // ignore bad quads } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/particle/BillboardParticleMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/particle/BillboardParticleMixin.java index 9e3d4bfff1..3b6f2de0d8 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/particle/BillboardParticleMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/particle/BillboardParticleMixin.java @@ -2,14 +2,14 @@ import net.caffeinemc.mods.sodium.api.vertex.format.common.ParticleVertex; import net.caffeinemc.mods.sodium.api.vertex.buffer.VertexBufferWriter; +import com.mojang.blaze3d.vertex.VertexConsumer; import net.caffeinemc.mods.sodium.api.util.ColorABGR; -import net.minecraft.client.particle.BillboardParticle; +import net.minecraft.client.Camera; +import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.particle.Particle; -import net.minecraft.client.render.Camera; -import net.minecraft.client.render.VertexConsumer; -import net.minecraft.client.world.ClientWorld; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.Vec3d; +import net.minecraft.client.particle.SingleQuadParticle; +import net.minecraft.util.Mth; +import net.minecraft.world.phys.Vec3; import org.joml.Quaternionf; import org.lwjgl.system.MemoryStack; import org.spongepowered.asm.mixin.Mixin; @@ -17,24 +17,24 @@ import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; -@Mixin(BillboardParticle.class) +@Mixin(SingleQuadParticle.class) public abstract class BillboardParticleMixin extends Particle { @Shadow - public abstract float getSize(float tickDelta); + public abstract float getQuadSize(float tickDelta); @Shadow - protected abstract float getMinU(); + protected abstract float getU0(); @Shadow - protected abstract float getMaxU(); + protected abstract float getU1(); @Shadow - protected abstract float getMinV(); + protected abstract float getV0(); @Shadow - protected abstract float getMaxV(); + protected abstract float getV1(); - protected BillboardParticleMixin(ClientWorld world, double x, double y, double z) { + protected BillboardParticleMixin(ClientLevel world, double x, double y, double z) { super(world, x, y, z); } @@ -43,33 +43,33 @@ protected BillboardParticleMixin(ClientWorld world, double x, double y, double z * @author JellySquid */ @Overwrite - public void buildGeometry(VertexConsumer vertexConsumer, Camera camera, float tickDelta) { - Vec3d vec3d = camera.getPos(); + public void render(VertexConsumer vertexConsumer, Camera camera, float tickDelta) { + Vec3 vec3d = camera.getPosition(); - float x = (float) (MathHelper.lerp(tickDelta, this.prevPosX, this.x) - vec3d.getX()); - float y = (float) (MathHelper.lerp(tickDelta, this.prevPosY, this.y) - vec3d.getY()); - float z = (float) (MathHelper.lerp(tickDelta, this.prevPosZ, this.z) - vec3d.getZ()); + float x = (float) (Mth.lerp(tickDelta, this.xo, this.x) - vec3d.x()); + float y = (float) (Mth.lerp(tickDelta, this.yo, this.y) - vec3d.y()); + float z = (float) (Mth.lerp(tickDelta, this.zo, this.z) - vec3d.z()); Quaternionf quaternion; - if (this.angle == 0.0F) { - quaternion = camera.getRotation(); + if (this.roll == 0.0F) { + quaternion = camera.rotation(); } else { - float angle = MathHelper.lerp(tickDelta, this.prevAngle, this.angle); + float angle = Mth.lerp(tickDelta, this.oRoll, this.roll); - quaternion = new Quaternionf(camera.getRotation()); + quaternion = new Quaternionf(camera.rotation()); quaternion.rotateZ(angle); } - float size = this.getSize(tickDelta); - int light = this.getBrightness(tickDelta); + float size = this.getQuadSize(tickDelta); + int light = this.getLightColor(tickDelta); - float minU = this.getMinU(); - float maxU = this.getMaxU(); - float minV = this.getMinV(); - float maxV = this.getMaxV(); + float minU = this.getU0(); + float maxU = this.getU1(); + float minV = this.getV0(); + float maxV = this.getV1(); - int color = ColorABGR.pack(this.red , this.green, this.blue, this.alpha); + int color = ColorABGR.pack(this.rCol , this.gCol, this.bCol, this.alpha); var writer = VertexBufferWriter.of(vertexConsumer); diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/world/clouds/WorldRendererMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/world/clouds/WorldRendererMixin.java index d85a4be056..6d5462e3c4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/world/clouds/WorldRendererMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/world/clouds/WorldRendererMixin.java @@ -1,11 +1,11 @@ package me.jellysquid.mods.sodium.mixin.features.render.world.clouds; +import com.mojang.blaze3d.vertex.PoseStack; import me.jellysquid.mods.sodium.client.render.immediate.CloudRenderer; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.render.WorldRenderer; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.client.world.ClientWorld; -import net.minecraft.resource.ResourceManager; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.server.packs.resources.ResourceManager; import org.jetbrains.annotations.Nullable; import org.joml.Matrix4f; import org.spongepowered.asm.mixin.*; @@ -13,16 +13,16 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -@Mixin(WorldRenderer.class) +@Mixin(LevelRenderer.class) public class WorldRendererMixin { @Shadow - private @Nullable ClientWorld world; + private @Nullable ClientLevel level; @Shadow private int ticks; @Shadow @Final - private MinecraftClient client; + private Minecraft minecraft; @Unique private CloudRenderer cloudRenderer; @@ -32,22 +32,22 @@ public class WorldRendererMixin { * @reason Optimize cloud rendering */ @Overwrite - public void renderClouds(MatrixStack matrices, Matrix4f projectionMatrix, float tickDelta, double x, double y, double z) { + public void renderClouds(PoseStack matrices, Matrix4f projectionMatrix, float tickDelta, double x, double y, double z) { if (this.cloudRenderer == null) { - this.cloudRenderer = new CloudRenderer(this.client.getResourceManager()); + this.cloudRenderer = new CloudRenderer(this.minecraft.getResourceManager()); } - this.cloudRenderer.render(this.world, this.client.player, matrices, projectionMatrix, this.ticks, tickDelta, x, y, z); + this.cloudRenderer.render(this.level, this.minecraft.player, matrices, projectionMatrix, this.ticks, tickDelta, x, y, z); } - @Inject(method = "reload(Lnet/minecraft/resource/ResourceManager;)V", at = @At("RETURN")) + @Inject(method = "onResourceManagerReload(Lnet/minecraft/server/packs/resources/ResourceManager;)V", at = @At("RETURN")) private void onReload(ResourceManager manager, CallbackInfo ci) { if (this.cloudRenderer != null) { this.cloudRenderer.reloadTextures(manager); } } - @Inject(method = "reload()V", at = @At("RETURN")) + @Inject(method = "allChanged()V", at = @At("RETURN")) private void onReload(CallbackInfo ci) { // will be re-allocated on next use if (this.cloudRenderer != null) { diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/world/sky/BackgroundRendererMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/world/sky/BackgroundRendererMixin.java index 9e40253d62..4b8e03e2e4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/world/sky/BackgroundRendererMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/world/sky/BackgroundRendererMixin.java @@ -1,24 +1,24 @@ package me.jellysquid.mods.sodium.mixin.features.render.world.sky; import me.jellysquid.mods.sodium.client.util.color.FastCubicSampler; -import net.minecraft.client.render.BackgroundRenderer; -import net.minecraft.client.render.Camera; -import net.minecraft.client.world.ClientWorld; +import net.minecraft.client.Camera; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.renderer.FogRenderer; import net.minecraft.util.CubicSampler; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.Mth; +import net.minecraft.world.phys.Vec3; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; -@Mixin(BackgroundRenderer.class) +@Mixin(FogRenderer.class) public class BackgroundRendererMixin { - @Redirect(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/CubicSampler;sampleColor(Lnet/minecraft/util/math/Vec3d;Lnet/minecraft/util/CubicSampler$RgbFetcher;)Lnet/minecraft/util/math/Vec3d;")) - private static Vec3d redirectSampleColor(Vec3d pos, CubicSampler.RgbFetcher rgbFetcher, Camera camera, float tickDelta, ClientWorld world, int i, float f) { - float u = MathHelper.clamp(MathHelper.cos(world.getSkyAngle(tickDelta) * 6.2831855F) * 2.0F + 0.5F, 0.0F, 1.0F); + @Redirect(method = "setupColor", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/CubicSampler;gaussianSampleVec3(Lnet/minecraft/world/phys/Vec3;Lnet/minecraft/util/CubicSampler$Vec3Fetcher;)Lnet/minecraft/world/phys/Vec3;")) + private static Vec3 redirectSampleColor(Vec3 pos, CubicSampler.Vec3Fetcher rgbFetcher, Camera camera, float tickDelta, ClientLevel world, int i, float f) { + float u = Mth.clamp(Mth.cos(world.getTimeOfDay(tickDelta) * 6.2831855F) * 2.0F + 0.5F, 0.0F, 1.0F); return FastCubicSampler.sampleColor(pos, - (x, y, z) -> world.getBiomeAccess().getBiomeForNoiseGen(x, y, z).value().getFogColor(), - (v) -> world.getDimensionEffects().adjustFogColor(v, u)); + (x, y, z) -> world.getBiomeManager().getNoiseBiomeAtQuart(x, y, z).value().getFogColor(), + (v) -> world.effects().getBrightnessDependentFogColor(v, u)); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/world/sky/ClientWorldMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/world/sky/ClientWorldMixin.java index 77113fd063..fa914a1d05 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/world/sky/ClientWorldMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/world/sky/ClientWorldMixin.java @@ -1,22 +1,22 @@ package me.jellysquid.mods.sodium.mixin.features.render.world.sky; import me.jellysquid.mods.sodium.client.util.color.FastCubicSampler; -import net.minecraft.client.world.ClientWorld; +import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.util.CubicSampler; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.World; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; import java.util.function.Function; -@Mixin(ClientWorld.class) +@Mixin(ClientLevel.class) public class ClientWorldMixin { - @Redirect(method = "getSkyColor", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/CubicSampler;sampleColor(Lnet/minecraft/util/math/Vec3d;Lnet/minecraft/util/CubicSampler$RgbFetcher;)Lnet/minecraft/util/math/Vec3d;")) - private Vec3d redirectSampleColor(Vec3d pos, CubicSampler.RgbFetcher rgbFetcher) { - World world = (World) (Object) this; + @Redirect(method = "getSkyColor", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/CubicSampler;gaussianSampleVec3(Lnet/minecraft/world/phys/Vec3;Lnet/minecraft/util/CubicSampler$Vec3Fetcher;)Lnet/minecraft/world/phys/Vec3;")) + private Vec3 redirectSampleColor(Vec3 pos, CubicSampler.Vec3Fetcher rgbFetcher) { + Level world = (Level) (Object) this; - return FastCubicSampler.sampleColor(pos, (x, y, z) -> world.getBiomeForNoiseGen(x, y, z).value().getSkyColor(), Function.identity()); + return FastCubicSampler.sampleColor(pos, (x, y, z) -> world.getNoiseBiome(x, y, z).value().getSkyColor(), Function.identity()); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/world/sky/WorldRendererMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/world/sky/WorldRendererMixin.java index e6e12b6187..65574f6ba6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/world/sky/WorldRendererMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/world/sky/WorldRendererMixin.java @@ -1,17 +1,17 @@ package me.jellysquid.mods.sodium.mixin.features.render.world.sky; +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.Camera; +import net.minecraft.client.renderer.FogRenderer; +import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.world.level.material.FogType; import org.joml.Matrix4f; 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.callback.CallbackInfo; -import net.minecraft.client.render.BackgroundRenderer; -import net.minecraft.client.render.Camera; -import net.minecraft.client.render.CameraSubmersionType; -import net.minecraft.client.render.WorldRenderer; -import net.minecraft.client.util.math.MatrixStack; -@Mixin(WorldRenderer.class) +@Mixin(LevelRenderer.class) public class WorldRendererMixin { /** *

Prevents the sky layer from rendering when the fog distance is reduced @@ -28,15 +28,15 @@ public class WorldRendererMixin { * outside of water, so the fog should also be covering the sun and sky.

* *

When updating Sodium to new releases of the game, please check for new - * ways the fog can be reduced in {@link BackgroundRenderer#applyFog(Camera, BackgroundRenderer.FogType, float, boolean, float)} ()}.

+ * ways the fog can be reduced in {@link FogRenderer#setupFog(Camera, FogRenderer.FogMode, float, boolean, float)} ()}.

*/ - @Inject(method = "renderSky(Lnet/minecraft/client/util/math/MatrixStack;Lorg/joml/Matrix4f;FLnet/minecraft/client/render/Camera;ZLjava/lang/Runnable;)V", at = @At("HEAD"), cancellable = true) - private void preRenderSky(MatrixStack matrices, Matrix4f projectionMatrix, float tickDelta, Camera camera, boolean bl, Runnable runnable, CallbackInfo ci) { + @Inject(method = "renderSky(Lcom/mojang/blaze3d/vertex/PoseStack;Lorg/joml/Matrix4f;FLnet/minecraft/client/Camera;ZLjava/lang/Runnable;)V", at = @At("HEAD"), cancellable = true) + private void preRenderSky(PoseStack matrices, Matrix4f projectionMatrix, float tickDelta, Camera camera, boolean bl, Runnable runnable, CallbackInfo ci) { // Cancels sky rendering when the camera is submersed underwater. // This prevents the sky from being visible through chunks culled by Sodium's fog occlusion. // Fixes https://bugs.mojang.com/browse/MC-152504. // Credit to bytzo for noticing the change in 1.18.2. - if (camera.getSubmersionType() == CameraSubmersionType.WATER) { + if (camera.getFluidInCamera() == FogType.WATER) { ci.cancel(); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/shader/uniform/ShaderProgramMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/shader/uniform/ShaderProgramMixin.java index d2a4812fb4..e37efc6527 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/shader/uniform/ShaderProgramMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/shader/uniform/ShaderProgramMixin.java @@ -1,11 +1,9 @@ package me.jellysquid.mods.sodium.mixin.features.shader.uniform; +import com.mojang.blaze3d.shaders.Uniform; +import com.mojang.blaze3d.vertex.VertexFormat; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; -import net.minecraft.client.gl.GlUniform; -import net.minecraft.client.gl.ShaderProgram; -import net.minecraft.client.render.VertexFormat; -import net.minecraft.resource.ResourceFactory; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -16,13 +14,15 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import java.util.List; +import net.minecraft.client.renderer.ShaderInstance; +import net.minecraft.server.packs.resources.ResourceProvider; /** * On the NVIDIA drivers (and maybe some others), the OpenGL submission thread requires expensive state synchronization * to happen when glGetUniformLocation and glGetInteger are called. In our case, this is rather unnecessary, since * these uniform locations can be trivially cached. */ -@Mixin(ShaderProgram.class) +@Mixin(ShaderInstance.class) public class ShaderProgramMixin { @Shadow @Final @@ -30,18 +30,18 @@ public class ShaderProgramMixin { @Shadow @Final - private int glRef; + private int programId; @Unique private Object2IntMap uniformCache; @Inject(method = "", at = @At("RETURN")) - private void initCache(ResourceFactory factory, String name, VertexFormat format, CallbackInfo ci) { + private void initCache(ResourceProvider factory, String name, VertexFormat format, CallbackInfo ci) { this.uniformCache = new Object2IntOpenHashMap<>(); this.uniformCache.defaultReturnValue(-1); for (var samplerName : this.samplerNames) { - var location = GlUniform.getUniformLocation(this.glRef, samplerName); + var location = Uniform.glGetUniformLocation(this.programId, samplerName); if (location == -1) { throw new IllegalStateException("Failed to find uniform '%s' during shader init".formatted(samplerName)); @@ -51,7 +51,7 @@ private void initCache(ResourceFactory factory, String name, VertexFormat format } } - @Redirect(method = "bind", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gl/GlUniform;getUniformLocation(ILjava/lang/CharSequence;)I")) + @Redirect(method = "apply", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/shaders/Uniform;glGetUniformLocation(ILjava/lang/CharSequence;)I")) private int redirectGetUniformLocation(int program, CharSequence name) { var location = this.uniformCache.getInt(name); diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/NativeImageAccessor.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/NativeImageAccessor.java index f6d5a03714..8a0c60401a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/NativeImageAccessor.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/NativeImageAccessor.java @@ -1,11 +1,11 @@ package me.jellysquid.mods.sodium.mixin.features.textures; -import net.minecraft.client.texture.NativeImage; +import com.mojang.blaze3d.platform.NativeImage; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; @Mixin(NativeImage.class) public interface NativeImageAccessor { @Accessor - long getPointer(); + long getPixels(); } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/SpriteContentsInvoker.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/SpriteContentsInvoker.java index 92f2cc49fd..af96061856 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/SpriteContentsInvoker.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/SpriteContentsInvoker.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.mixin.features.textures; -import net.minecraft.client.texture.NativeImage; -import net.minecraft.client.texture.SpriteContents; +import com.mojang.blaze3d.platform.NativeImage; +import net.minecraft.client.renderer.texture.SpriteContents; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Invoker; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/BlockModelRendererMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/BlockModelRendererMixin.java index 06f287b01f..6b8fc13aa3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/BlockModelRendererMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/BlockModelRendererMixin.java @@ -1,27 +1,27 @@ package me.jellysquid.mods.sodium.mixin.features.textures.animations.tracking; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; import me.jellysquid.mods.sodium.client.render.texture.SpriteUtil; -import net.minecraft.block.BlockState; -import net.minecraft.client.render.VertexConsumer; -import net.minecraft.client.render.block.BlockModelRenderer; -import net.minecraft.client.render.model.BakedQuad; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.BlockRenderView; +import net.minecraft.client.renderer.block.ModelBlockRenderer; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.state.BlockState; 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.callback.CallbackInfo; -@Mixin(BlockModelRenderer.class) +@Mixin(ModelBlockRenderer.class) public class BlockModelRendererMixin { /** * @reason Ensure sprites rendered through renderSmooth/renderFlat in immediate-mode are marked as active. * This doesn't affect vanilla to my knowledge, but mods can trigger it. * @author embeddedt */ - @Inject(method = "renderQuad", at = @At("HEAD")) - private void preRenderQuad(BlockRenderView world, BlockState state, BlockPos pos, VertexConsumer vertexConsumer, MatrixStack.Entry matrixEntry, BakedQuad quad, float brightness0, float brightness1, float brightness2, float brightness3, int light0, int light1, int light2, int light3, int overlay, CallbackInfo ci) { + @Inject(method = "putQuadData", at = @At("HEAD")) + private void preRenderQuad(BlockAndTintGetter world, BlockState state, BlockPos pos, VertexConsumer vertexConsumer, PoseStack.Pose matrixEntry, BakedQuad quad, float brightness0, float brightness1, float brightness2, float brightness3, int light0, int light1, int light2, int light3, int overlay, CallbackInfo ci) { SpriteUtil.markSpriteActive(quad.getSprite()); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/DrawContextMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/DrawContextMixin.java index 86b95bfd4e..72dae5af4d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/DrawContextMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/DrawContextMixin.java @@ -1,28 +1,28 @@ package me.jellysquid.mods.sodium.mixin.features.textures.animations.tracking; import me.jellysquid.mods.sodium.client.render.texture.SpriteUtil; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.texture.Sprite; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; 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.callback.CallbackInfo; -@Mixin(DrawContext.class) +@Mixin(GuiGraphics.class) public class DrawContextMixin { - @Inject(method = "drawSprite(IIIIILnet/minecraft/client/texture/Sprite;)V", at = @At("HEAD")) + @Inject(method = "blit(IIIIILnet/minecraft/client/renderer/texture/TextureAtlasSprite;)V", at = @At("HEAD")) private void preDrawSprite(int x, int y, int z, int width, int height, - Sprite sprite, + TextureAtlasSprite sprite, CallbackInfo ci) { SpriteUtil.markSpriteActive(sprite); } - @Inject(method = "drawSprite(IIIIILnet/minecraft/client/texture/Sprite;FFFF)V", at = @At("HEAD")) + @Inject(method = "blit(IIIIILnet/minecraft/client/renderer/texture/TextureAtlasSprite;FFFF)V", at = @At("HEAD")) private void preDrawSprite(int x, int y, int z, int width, int height, - Sprite sprite, + TextureAtlasSprite sprite, float red, float green, float blue, float alpha, CallbackInfo ci) { diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteAtlasTextureMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteAtlasTextureMixin.java index dbd91ac057..cca072563b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteAtlasTextureMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteAtlasTextureMixin.java @@ -1,18 +1,18 @@ package me.jellysquid.mods.sodium.mixin.features.textures.animations.tracking; import me.jellysquid.mods.sodium.client.render.texture.SpriteUtil; -import net.minecraft.client.texture.Sprite; -import net.minecraft.client.texture.SpriteAtlasTexture; +import net.minecraft.client.renderer.texture.TextureAtlas; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; 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.callback.CallbackInfoReturnable; -@Mixin(SpriteAtlasTexture.class) +@Mixin(TextureAtlas.class) public class SpriteAtlasTextureMixin { @Inject(method = "getSprite", at = @At("RETURN")) - private void preReturnSprite(CallbackInfoReturnable cir) { - Sprite sprite = cir.getReturnValue(); + private void preReturnSprite(CallbackInfoReturnable cir) { + TextureAtlasSprite sprite = cir.getReturnValue(); if (sprite != null) { SpriteUtil.markSpriteActive(sprite); diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteBillboardParticleMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteBillboardParticleMixin.java index 3c0c1ffa21..de54c58797 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteBillboardParticleMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteBillboardParticleMixin.java @@ -1,12 +1,12 @@ package me.jellysquid.mods.sodium.mixin.features.textures.animations.tracking; +import com.mojang.blaze3d.vertex.VertexConsumer; import me.jellysquid.mods.sodium.client.render.texture.SpriteUtil; -import net.minecraft.client.particle.BillboardParticle; -import net.minecraft.client.particle.SpriteBillboardParticle; -import net.minecraft.client.render.Camera; -import net.minecraft.client.render.VertexConsumer; -import net.minecraft.client.texture.Sprite; -import net.minecraft.client.world.ClientWorld; +import net.minecraft.client.Camera; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.particle.SingleQuadParticle; +import net.minecraft.client.particle.TextureSheetParticle; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @@ -14,29 +14,29 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -@Mixin(SpriteBillboardParticle.class) -public abstract class SpriteBillboardParticleMixin extends BillboardParticle { +@Mixin(TextureSheetParticle.class) +public abstract class SpriteBillboardParticleMixin extends SingleQuadParticle { @Shadow - protected Sprite sprite; + protected TextureAtlasSprite sprite; @Unique private boolean shouldTickSprite; - protected SpriteBillboardParticleMixin(ClientWorld world, double x, double y, double z) { + protected SpriteBillboardParticleMixin(ClientLevel world, double x, double y, double z) { super(world, x, y, z); } - @Inject(method = "setSprite(Lnet/minecraft/client/texture/Sprite;)V", at = @At("RETURN")) - private void afterSetSprite(Sprite sprite, CallbackInfo ci) { + @Inject(method = "setSprite(Lnet/minecraft/client/renderer/texture/TextureAtlasSprite;)V", at = @At("RETURN")) + private void afterSetSprite(TextureAtlasSprite sprite, CallbackInfo ci) { this.shouldTickSprite = sprite != null && SpriteUtil.hasAnimation(sprite); } @Override - public void buildGeometry(VertexConsumer vertexConsumer, Camera camera, float tickDelta) { + public void render(VertexConsumer vertexConsumer, Camera camera, float tickDelta) { if (this.shouldTickSprite) { SpriteUtil.markSpriteActive(this.sprite); } - super.buildGeometry(vertexConsumer, camera, tickDelta); + super.render(vertexConsumer, camera, tickDelta); } } \ No newline at end of file diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsAnimationAccessor.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsAnimationAccessor.java index 450f484578..7e63653e78 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsAnimationAccessor.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsAnimationAccessor.java @@ -1,13 +1,13 @@ package me.jellysquid.mods.sodium.mixin.features.textures.animations.tracking; -import net.minecraft.client.texture.SpriteContents; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; import java.util.List; +import net.minecraft.client.renderer.texture.SpriteContents; -@Mixin(SpriteContents.Animation.class) +@Mixin(SpriteContents.AnimatedTexture.class) public interface SpriteContentsAnimationAccessor { @Accessor("frames") - List getFrames(); + List getFrames(); } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsAnimationFrameAccessor.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsAnimationFrameAccessor.java index 1aa198a70b..de8a9bcc21 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsAnimationFrameAccessor.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsAnimationFrameAccessor.java @@ -1,10 +1,10 @@ package me.jellysquid.mods.sodium.mixin.features.textures.animations.tracking; -import net.minecraft.client.texture.SpriteContents; +import net.minecraft.client.renderer.texture.SpriteContents; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; -@Mixin(SpriteContents.AnimationFrame.class) +@Mixin(SpriteContents.FrameInfo.class) public interface SpriteContentsAnimationFrameAccessor { @Accessor("time") int getTime(); diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsAnimatorImplMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsAnimatorImplMixin.java index c877261676..5b8b40f926 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsAnimatorImplMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsAnimatorImplMixin.java @@ -2,7 +2,7 @@ import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.render.texture.SpriteContentsExtended; -import net.minecraft.client.texture.SpriteContents; +import net.minecraft.client.renderer.texture.SpriteContents; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -13,13 +13,13 @@ import java.util.List; -@Mixin(SpriteContents.AnimatorImpl.class) +@Mixin(SpriteContents.Ticker.class) public class SpriteContentsAnimatorImplMixin { @Shadow - int currentTime; + int subFrame; @Shadow @Final - SpriteContents.Animation animation; + SpriteContents.AnimatedTexture animationInfo; @Shadow int frame; @@ -31,28 +31,28 @@ public class SpriteContentsAnimatorImplMixin { * @reason Replace fragile Shadow */ @Inject(method = "", at = @At("RETURN")) - public void assignParent(SpriteContents spriteContents, SpriteContents.Animation animation, SpriteContents.Interpolation interpolation, CallbackInfo ci) { + public void assignParent(SpriteContents spriteContents, SpriteContents.AnimatedTexture animation, SpriteContents.InterpolationData interpolation, CallbackInfo ci) { this.parent = spriteContents; } - @Inject(method = "tick", at = @At("HEAD"), cancellable = true) + @Inject(method = "tickAndUpload", at = @At("HEAD"), cancellable = true) private void preTick(CallbackInfo ci) { SpriteContentsExtended parent = (SpriteContentsExtended) this.parent; boolean onDemand = SodiumClientMod.options().performance.animateOnlyVisibleTextures; if (onDemand && !parent.sodium$isActive()) { - this.currentTime++; - List frames = ((SpriteContentsAnimationAccessor)this.animation).getFrames(); - if (this.currentTime >= ((SpriteContentsAnimationFrameAccessor)frames.get(this.frame)).getTime()) { + this.subFrame++; + List frames = ((SpriteContentsAnimationAccessor)this.animationInfo).getFrames(); + if (this.subFrame >= ((SpriteContentsAnimationFrameAccessor)frames.get(this.frame)).getTime()) { this.frame = (this.frame + 1) % frames.size(); - this.currentTime = 0; + this.subFrame = 0; } ci.cancel(); } } - @Inject(method = "tick", at = @At("TAIL")) + @Inject(method = "tickAndUpload", at = @At("TAIL")) private void postTick(CallbackInfo ci) { SpriteContentsExtended parent = (SpriteContentsExtended) this.parent; parent.sodium$setActive(false); diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsMixin.java index fc8300127b..1d9d306a28 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsMixin.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.mixin.features.textures.animations.tracking; import me.jellysquid.mods.sodium.client.render.texture.SpriteContentsExtended; -import net.minecraft.client.texture.SpriteContents; +import net.minecraft.client.renderer.texture.SpriteContents; import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; @@ -13,7 +13,7 @@ public abstract class SpriteContentsMixin implements SpriteContentsExtended { @Shadow @Final @Nullable - private SpriteContents.Animation animation; + private SpriteContents.AnimatedTexture animatedTexture; @Unique private boolean active; @@ -25,7 +25,7 @@ public abstract class SpriteContentsMixin implements SpriteContentsExtended { @Override public boolean sodium$hasAnimation() { - return this.animation != null; + return this.animatedTexture != null; } @Override diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAccessor.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAccessor.java index b766e4a066..662ba1bec2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAccessor.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAccessor.java @@ -1,12 +1,12 @@ package me.jellysquid.mods.sodium.mixin.features.textures.animations.upload; -import net.minecraft.client.texture.NativeImage; -import net.minecraft.client.texture.SpriteContents; +import com.mojang.blaze3d.platform.NativeImage; +import net.minecraft.client.renderer.texture.SpriteContents; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; @Mixin(SpriteContents.class) public interface SpriteContentsAccessor { - @Accessor("mipmapLevelsImages") + @Accessor("byMipLevel") NativeImage[] getImages(); } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAnimationAccessor.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAnimationAccessor.java index 6ecabf0684..cbe0eecd20 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAnimationAccessor.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAnimationAccessor.java @@ -1,16 +1,16 @@ package me.jellysquid.mods.sodium.mixin.features.textures.animations.upload; -import net.minecraft.client.texture.SpriteContents; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; import java.util.List; +import net.minecraft.client.renderer.texture.SpriteContents; -@Mixin(SpriteContents.Animation.class) +@Mixin(SpriteContents.AnimatedTexture.class) public interface SpriteContentsAnimationAccessor { @Accessor - List getFrames(); + List getFrames(); @Accessor - int getFrameCount(); + int getFrameRowSize(); } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAnimationFrameAccessor.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAnimationFrameAccessor.java index f120c156e6..6f2c0801e0 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAnimationFrameAccessor.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAnimationFrameAccessor.java @@ -1,10 +1,10 @@ package me.jellysquid.mods.sodium.mixin.features.textures.animations.upload; -import net.minecraft.client.texture.SpriteContents; +import net.minecraft.client.renderer.texture.SpriteContents; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; -@Mixin(SpriteContents.AnimationFrame.class) +@Mixin(SpriteContents.FrameInfo.class) public interface SpriteContentsAnimationFrameAccessor { @Accessor int getIndex(); diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAnimatorImplAccessor.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAnimatorImplAccessor.java index 6b15ab87dd..b1e773ee59 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAnimatorImplAccessor.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAnimatorImplAccessor.java @@ -1,17 +1,17 @@ package me.jellysquid.mods.sodium.mixin.features.textures.animations.upload; -import net.minecraft.client.texture.SpriteContents; +import net.minecraft.client.renderer.texture.SpriteContents; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; -@Mixin(SpriteContents.AnimatorImpl.class) +@Mixin(SpriteContents.Ticker.class) public interface SpriteContentsAnimatorImplAccessor { @Accessor - SpriteContents.Animation getAnimation(); + SpriteContents.AnimatedTexture getAnimationInfo(); @Accessor("frame") int getFrameIndex(); - @Accessor("currentTime") + @Accessor("subFrame") int getFrameTicks(); } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsInterpolationMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsInterpolationMixin.java index e7d582e605..d4496e5794 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsInterpolationMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsInterpolationMixin.java @@ -3,21 +3,20 @@ import me.jellysquid.mods.sodium.client.util.NativeImageHelper; import me.jellysquid.mods.sodium.mixin.features.textures.SpriteContentsInvoker; import net.caffeinemc.mods.sodium.api.util.ColorMixer; -import net.minecraft.client.texture.NativeImage; -import net.minecraft.client.texture.SpriteContents; +import net.minecraft.client.renderer.texture.SpriteContents; import org.lwjgl.system.MemoryUtil; import org.spongepowered.asm.mixin.*; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - +import com.mojang.blaze3d.platform.NativeImage; import java.util.List; -@Mixin(SpriteContents.Interpolation.class) +@Mixin(SpriteContents.InterpolationData.class) public class SpriteContentsInterpolationMixin { @Shadow @Final - private NativeImage[] images; + private NativeImage[] activeFrame; @Unique private SpriteContents parent; @@ -39,10 +38,10 @@ public void assignParent(SpriteContents parent, CallbackInfo ci) { * @reason Drastic optimizations */ @Overwrite - void apply(int x, int y, SpriteContents.AnimatorImpl arg) { - SpriteContents.Animation animation = ((SpriteContentsAnimatorImplAccessor) arg).getAnimation(); - SpriteContentsAnimationAccessor animation2 = (SpriteContentsAnimationAccessor) ((SpriteContentsAnimatorImplAccessor) arg).getAnimation(); - List frames = ((SpriteContentsAnimationAccessor) animation).getFrames(); + void uploadInterpolatedFrame(int x, int y, SpriteContents.Ticker arg) { + SpriteContents.AnimatedTexture animation = ((SpriteContentsAnimatorImplAccessor) arg).getAnimationInfo(); + SpriteContentsAnimationAccessor animation2 = (SpriteContentsAnimationAccessor) ((SpriteContentsAnimatorImplAccessor) arg).getAnimationInfo(); + List frames = ((SpriteContentsAnimationAccessor) animation).getFrames(); SpriteContentsAnimatorImplAccessor accessor = (SpriteContentsAnimatorImplAccessor) arg; SpriteContentsAnimationFrameAccessor animationFrame = (SpriteContentsAnimationFrameAccessor) frames.get(accessor.getFrameIndex()); @@ -56,18 +55,18 @@ void apply(int x, int y, SpriteContents.AnimatorImpl arg) { // The mix factor between the current and next frame float mix = 1.0F - (float) accessor.getFrameTicks() / (float) animationFrame.getTime(); - for (int layer = 0; layer < this.images.length; layer++) { - int width = this.parent.getWidth() >> layer; - int height = this.parent.getHeight() >> layer; + for (int layer = 0; layer < this.activeFrame.length; layer++) { + int width = this.parent.width() >> layer; + int height = this.parent.height() >> layer; - int curX = ((curIndex % animation2.getFrameCount()) * width); - int curY = ((curIndex / animation2.getFrameCount()) * height); + int curX = ((curIndex % animation2.getFrameRowSize()) * width); + int curY = ((curIndex / animation2.getFrameRowSize()) * height); - int nextX = ((nextIndex % animation2.getFrameCount()) * width); - int nextY = ((nextIndex / animation2.getFrameCount()) * height); + int nextX = ((nextIndex % animation2.getFrameRowSize()) * width); + int nextY = ((nextIndex / animation2.getFrameRowSize()) * height); NativeImage src = ((SpriteContentsAccessor) this.parent).getImages()[layer]; - NativeImage dst = this.images[layer]; + NativeImage dst = this.activeFrame[layer]; long ppSrcPixel = NativeImageHelper.getPointerRGBA(src); long ppDstPixel = NativeImageHelper.getPointerRGBA(dst); @@ -98,6 +97,6 @@ void apply(int x, int y, SpriteContents.AnimatorImpl arg) { } } - ((SpriteContentsInvoker) this.parent).invokeUpload(x, y, 0, 0, this.images); + ((SpriteContentsInvoker) this.parent).invokeUpload(x, y, 0, 0, this.activeFrame); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/mipmaps/MipmapHelperMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/mipmaps/MipmapHelperMixin.java index 032ddd25eb..658a3eef1a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/mipmaps/MipmapHelperMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/mipmaps/MipmapHelperMixin.java @@ -1,8 +1,8 @@ package me.jellysquid.mods.sodium.mixin.features.textures.mipmaps; import me.jellysquid.mods.sodium.client.util.color.ColorSRGB; -import net.minecraft.client.texture.MipmapHelper; -import net.minecraft.util.math.ColorHelper; +import net.minecraft.client.renderer.texture.MipmapGenerator; +import net.minecraft.util.FastColor; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.Unique; @@ -26,14 +26,14 @@ * * This Mixin is ported from Iris at MixinMipmapGenerator. */ -@Mixin(MipmapHelper.class) +@Mixin(MipmapGenerator.class) public class MipmapHelperMixin { /** * @author coderbot * @reason replace the vanilla blending function with our improved function */ @Overwrite - private static int blend(int one, int two, int three, int four, boolean checkAlpha) { + private static int alphaBlend(int one, int two, int three, int four, boolean checkAlpha) { // First blend horizontally, then blend vertically. // // This works well for the case where our change is the most impactful (grass side overlays) @@ -42,8 +42,8 @@ private static int blend(int one, int two, int three, int four, boolean checkAlp @Unique private static int weightedAverageColor(int one, int two) { - int alphaOne = ColorHelper.Abgr.getAlpha(one); - int alphaTwo = ColorHelper.Abgr.getAlpha(two); + int alphaOne = FastColor.ABGR32.alpha(one); + int alphaTwo = FastColor.ABGR32.alpha(two); // In the case where the alpha values of the same, we can get by with an unweighted average. if (alphaOne == alphaTwo) { @@ -68,13 +68,13 @@ private static int weightedAverageColor(int one, int two) { float relativeWeightTwo = alphaTwo * scale; // Convert the color components into linear space, then multiply the corresponding weight. - float oneR = ColorSRGB.srgbToLinear(ColorHelper.Abgr.getRed(one)) * relativeWeightOne; - float oneG = ColorSRGB.srgbToLinear(ColorHelper.Abgr.getGreen(one)) * relativeWeightOne; - float oneB = ColorSRGB.srgbToLinear(ColorHelper.Abgr.getBlue(one)) * relativeWeightOne; + float oneR = ColorSRGB.srgbToLinear(FastColor.ABGR32.red(one)) * relativeWeightOne; + float oneG = ColorSRGB.srgbToLinear(FastColor.ABGR32.green(one)) * relativeWeightOne; + float oneB = ColorSRGB.srgbToLinear(FastColor.ABGR32.blue(one)) * relativeWeightOne; - float twoR = ColorSRGB.srgbToLinear(ColorHelper.Abgr.getRed(two)) * relativeWeightTwo; - float twoG = ColorSRGB.srgbToLinear(ColorHelper.Abgr.getGreen(two)) * relativeWeightTwo; - float twoB = ColorSRGB.srgbToLinear(ColorHelper.Abgr.getBlue(two)) * relativeWeightTwo; + float twoR = ColorSRGB.srgbToLinear(FastColor.ABGR32.red(two)) * relativeWeightTwo; + float twoG = ColorSRGB.srgbToLinear(FastColor.ABGR32.green(two)) * relativeWeightTwo; + float twoB = ColorSRGB.srgbToLinear(FastColor.ABGR32.blue(two)) * relativeWeightTwo; // Combine the color components of each color float linearR = oneR + twoR; @@ -91,13 +91,13 @@ private static int weightedAverageColor(int one, int two) { // Computes a non-weighted average of the two sRGB colors in linear space, avoiding brightness losses. @Unique private static int averageRgb(int a, int b, int alpha) { - float ar = ColorSRGB.srgbToLinear(ColorHelper.Abgr.getRed(a)); - float ag = ColorSRGB.srgbToLinear(ColorHelper.Abgr.getGreen(a)); - float ab = ColorSRGB.srgbToLinear(ColorHelper.Abgr.getBlue(a)); + float ar = ColorSRGB.srgbToLinear(FastColor.ABGR32.red(a)); + float ag = ColorSRGB.srgbToLinear(FastColor.ABGR32.green(a)); + float ab = ColorSRGB.srgbToLinear(FastColor.ABGR32.blue(a)); - float br = ColorSRGB.srgbToLinear(ColorHelper.Abgr.getRed(b)); - float bg = ColorSRGB.srgbToLinear(ColorHelper.Abgr.getGreen(b)); - float bb = ColorSRGB.srgbToLinear(ColorHelper.Abgr.getBlue(b)); + float br = ColorSRGB.srgbToLinear(FastColor.ABGR32.red(b)); + float bg = ColorSRGB.srgbToLinear(FastColor.ABGR32.green(b)); + float bb = ColorSRGB.srgbToLinear(FastColor.ABGR32.blue(b)); return ColorSRGB.linearToSrgb((ar + br) * 0.5f, (ag + bg) * 0.5f, (ab + bb) * 0.5f, alpha); } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/mipmaps/SpriteContentsMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/mipmaps/SpriteContentsMixin.java index 3f4768aba5..96d967b5c7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/mipmaps/SpriteContentsMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/mipmaps/SpriteContentsMixin.java @@ -1,11 +1,11 @@ package me.jellysquid.mods.sodium.mixin.features.textures.mipmaps; +import com.mojang.blaze3d.platform.NativeImage; import me.jellysquid.mods.sodium.client.util.NativeImageHelper; import me.jellysquid.mods.sodium.client.util.color.ColorSRGB; -import net.minecraft.client.texture.NativeImage; -import net.minecraft.client.texture.SpriteContents; -import net.minecraft.util.Identifier; -import net.minecraft.util.math.ColorHelper; +import net.minecraft.client.renderer.texture.SpriteContents; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.FastColor; import org.lwjgl.system.MemoryUtil; import org.objectweb.asm.Opcodes; import org.spongepowered.asm.mixin.Final; @@ -24,7 +24,7 @@ public class SpriteContentsMixin { @Mutable @Shadow @Final - private NativeImage image; + private NativeImage originalImage; // While Fabric allows us to @Inject into the constructor here, that's just a specific detail of FabricMC's mixin // fork. Upstream Mixin doesn't allow arbitrary @Inject usage in constructor. However, we can use @ModifyVariable @@ -34,12 +34,12 @@ public class SpriteContentsMixin { // support Forge, since this works well on Fabric too, it's fine to ensure that the diff between Fabric and Forge // can remain minimal. Being less dependent on specific details of Fabric is good, since it means we can be more // cross-platform. - @Redirect(method = "", at = @At(value = "FIELD", target = "Lnet/minecraft/client/texture/SpriteContents;image:Lnet/minecraft/client/texture/NativeImage;", opcode = Opcodes.PUTFIELD)) - private void sodium$beforeGenerateMipLevels(SpriteContents instance, NativeImage nativeImage, Identifier identifier) { + @Redirect(method = "", at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/texture/SpriteContents;originalImage:Lcom/mojang/blaze3d/platform/NativeImage;", opcode = Opcodes.PUTFIELD)) + private void sodium$beforeGenerateMipLevels(SpriteContents instance, NativeImage nativeImage, ResourceLocation identifier) { // We're injecting after the "info" field has been set, so this is safe even though we're in a constructor. sodium$fillInTransparentPixelColors(nativeImage); - this.image = nativeImage; + this.originalImage = nativeImage; } /** @@ -67,16 +67,16 @@ public class SpriteContentsMixin { long pPixel = ppPixel + (pixelIndex * 4); int color = MemoryUtil.memGetInt(pPixel); - int alpha = ColorHelper.Abgr.getAlpha(color); + int alpha = FastColor.ABGR32.alpha(color); // Ignore all fully-transparent pixels for the purposes of computing an average color. if (alpha != 0) { float weight = (float) alpha; // Make sure to convert to linear space so that we don't lose brightness. - r += ColorSRGB.srgbToLinear(ColorHelper.Abgr.getRed(color)) * weight; - g += ColorSRGB.srgbToLinear(ColorHelper.Abgr.getGreen(color)) * weight; - b += ColorSRGB.srgbToLinear(ColorHelper.Abgr.getBlue(color)) * weight; + r += ColorSRGB.srgbToLinear(FastColor.ABGR32.red(color)) * weight; + g += ColorSRGB.srgbToLinear(FastColor.ABGR32.green(color)) * weight; + b += ColorSRGB.srgbToLinear(FastColor.ABGR32.blue(color)) * weight; totalWeight += weight; } @@ -99,7 +99,7 @@ public class SpriteContentsMixin { long pPixel = ppPixel + (pixelIndex * 4); int color = MemoryUtil.memGetInt(pPixel); - int alpha = ColorHelper.Abgr.getAlpha(color); + int alpha = FastColor.ABGR32.alpha(color); // Replace the color values of pixels which are fully transparent, since they have no color data. if (alpha == 0) { diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/world/biome/BiomeMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/world/biome/BiomeMixin.java index cf6170cf98..12ab3ea0bb 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/world/biome/BiomeMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/world/biome/BiomeMixin.java @@ -1,9 +1,11 @@ package me.jellysquid.mods.sodium.mixin.features.world.biome; +import java.util.Optional; import me.jellysquid.mods.sodium.client.world.biome.BiomeColorMaps; -import net.minecraft.util.math.MathHelper; -import net.minecraft.world.biome.Biome; -import net.minecraft.world.biome.BiomeEffects; +import net.minecraft.util.Mth; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.BiomeSpecialEffects; +import net.minecraft.world.level.biome.BiomeSpecialEffects.GrassColorModifier; import org.spongepowered.asm.mixin.*; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -13,11 +15,11 @@ public abstract class BiomeMixin { @Shadow @Final - private BiomeEffects effects; + private BiomeSpecialEffects specialEffects; @Shadow @Final - private Biome.Weather weather; + private Biome.ClimateSettings climateSettings; @Unique private boolean hasCustomGrassColor; @@ -36,14 +38,14 @@ public abstract class BiomeMixin { @Inject(method = "", at = @At("RETURN")) private void setupColors(CallbackInfo ci) { - var grassColor = this.effects.getGrassColor(); + var grassColor = this.specialEffects.getGrassColorOverride(); if (grassColor.isPresent()) { this.hasCustomGrassColor = true; this.customGrassColor = grassColor.get(); } - var foliageColor = this.effects.getFoliageColor(); + var foliageColor = this.specialEffects.getFoliageColorOverride(); if (foliageColor.isPresent()) { this.hasCustomFoliageColor = true; @@ -58,7 +60,7 @@ private void setupColors(CallbackInfo ci) { * @reason Avoid unnecessary pointer de-references and allocations */ @Overwrite - public int getGrassColorAt(double x, double z) { + public int getGrassColor(double x, double z) { int color; if (this.hasCustomGrassColor) { @@ -67,10 +69,10 @@ public int getGrassColorAt(double x, double z) { color = BiomeColorMaps.getGrassColor(this.defaultColorIndex); } - var modifier = this.effects.getGrassColorModifier(); + var modifier = this.specialEffects.getGrassColorModifier(); - if (modifier != BiomeEffects.GrassColorModifier.NONE) { - color = modifier.getModifiedGrassColor(x, z, color); + if (modifier != BiomeSpecialEffects.GrassColorModifier.NONE) { + color = modifier.modifyColor(x, z, color); } return color; @@ -95,8 +97,8 @@ public int getFoliageColor() { @Unique private int getDefaultColorIndex() { - double temperature = MathHelper.clamp(this.weather.temperature(), 0.0F, 1.0F); - double humidity = MathHelper.clamp(this.weather.downfall(), 0.0F, 1.0F); + double temperature = Mth.clamp(this.climateSettings.temperature(), 0.0F, 1.0F); + double humidity = Mth.clamp(this.climateSettings.downfall(), 0.0F, 1.0F); return BiomeColorMaps.getIndex(temperature, humidity); } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/world/storage/ClientChunkMapMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/world/storage/ClientChunkMapMixin.java index 5aec63e9ec..7449ed72e4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/world/storage/ClientChunkMapMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/world/storage/ClientChunkMapMixin.java @@ -1,48 +1,48 @@ package me.jellysquid.mods.sodium.mixin.features.world.storage; -import net.minecraft.client.world.ClientChunkManager; -import net.minecraft.util.math.MathHelper; -import net.minecraft.world.chunk.WorldChunk; import org.spongepowered.asm.mixin.*; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import java.util.concurrent.atomic.AtomicReferenceArray; +import net.minecraft.client.multiplayer.ClientChunkCache; +import net.minecraft.util.Mth; +import net.minecraft.world.level.chunk.LevelChunk; -@Mixin(targets = "net/minecraft/client/world/ClientChunkManager$ClientChunkMap") +@Mixin(targets = "net/minecraft/client/multiplayer/ClientChunkCache$Storage") public class ClientChunkMapMixin { @Mutable @Shadow @Final - AtomicReferenceArray chunks; + AtomicReferenceArray chunks; @Mutable @Shadow @Final - private int diameter; + private int viewRange; @Mutable @Shadow @Final - int radius; + int chunkRadius; @Unique private int factor; @Inject(method = "", at = @At("RETURN")) - private void reinit(ClientChunkManager outer, int loadDistance, CallbackInfo ci) { + private void reinit(ClientChunkCache outer, int loadDistance, CallbackInfo ci) { // This re-initialization is a bit expensive on memory, but it only happens when either the world is // switched or the render distance is changed; - this.radius = loadDistance; + this.chunkRadius = loadDistance; // Make the diameter a power-of-two so we can exploit bit-wise math when computing indices - this.diameter = MathHelper.smallestEncompassingPowerOfTwo(loadDistance * 2 + 1); + this.viewRange = Mth.smallestEncompassingPowerOfTwo(loadDistance * 2 + 1); // The factor is used as a bit mask to replace the modulo in getIndex - this.factor = this.diameter - 1; + this.factor = this.viewRange - 1; - this.chunks = new AtomicReferenceArray<>(this.diameter * this.diameter); + this.chunks = new AtomicReferenceArray<>(this.viewRange * this.viewRange); } /** @@ -51,6 +51,6 @@ private void reinit(ClientChunkManager outer, int loadDistance, CallbackInfo ci) */ @Overwrite int getIndex(int chunkX, int chunkZ) { - return (chunkZ & this.factor) * this.diameter + (chunkX & this.factor); + return (chunkZ & this.factor) * this.viewRange + (chunkX & this.factor); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/workarounds/context_creation/WindowMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/workarounds/context_creation/WindowMixin.java index 614ea54230..49f30b325e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/workarounds/context_creation/WindowMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/workarounds/context_creation/WindowMixin.java @@ -1,14 +1,14 @@ package me.jellysquid.mods.sodium.mixin.workarounds.context_creation; import me.jellysquid.mods.sodium.client.compatibility.checks.ModuleScanner; +import com.mojang.blaze3d.platform.DisplayData; +import com.mojang.blaze3d.platform.ScreenManager; +import com.mojang.blaze3d.platform.Window; +import com.mojang.blaze3d.platform.WindowEventHandler; import me.jellysquid.mods.sodium.client.compatibility.checks.LateDriverScanner; import me.jellysquid.mods.sodium.client.compatibility.workarounds.Workarounds; import me.jellysquid.mods.sodium.client.compatibility.workarounds.nvidia.NvidiaWorkarounds; -import net.minecraft.client.WindowEventHandler; -import net.minecraft.client.WindowSettings; -import net.minecraft.client.util.MonitorTracker; -import net.minecraft.client.util.Window; -import net.minecraft.util.Util; +import net.minecraft.Util; import org.lwjgl.glfw.GLFW; import org.lwjgl.opengl.WGL; import org.lwjgl.system.MemoryUtil; @@ -50,9 +50,9 @@ private long wrapGlfwCreateWindow(int width, int height, CharSequence title, lon } @Inject(method = "", at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL;createCapabilities()Lorg/lwjgl/opengl/GLCapabilities;", shift = At.Shift.AFTER)) - private void postWindowCreated(WindowEventHandler eventHandler, MonitorTracker monitorTracker, WindowSettings settings, String videoMode, String title, CallbackInfo ci) { + private void postWindowCreated(WindowEventHandler eventHandler, ScreenManager monitorTracker, DisplayData settings, String videoMode, String title, CallbackInfo ci) { // Capture the current WGL context so that we can detect it being replaced later. - if (Util.getOperatingSystem() == Util.OperatingSystem.WINDOWS) { + if (Util.getPlatform() == Util.OS.WINDOWS) { this.wglPrevContext = WGL.wglGetCurrentContext(); } else { this.wglPrevContext = MemoryUtil.NULL; @@ -62,7 +62,7 @@ private void postWindowCreated(WindowEventHandler eventHandler, MonitorTracker m ModuleScanner.checkModules(); } - @Inject(method = "swapBuffers", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;flipFrame(J)V", shift = At.Shift.AFTER)) + @Inject(method = "updateDisplay", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;flipFrame(J)V", shift = At.Shift.AFTER)) private void preSwapBuffers(CallbackInfo ci) { if (this.wglPrevContext == MemoryUtil.NULL) { // There is no prior recorded context. diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/workarounds/event_loop/RenderSystemMixin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/workarounds/event_loop/RenderSystemMixin.java index ab959f5133..ffd669ae2e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/workarounds/event_loop/RenderSystemMixin.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/workarounds/event_loop/RenderSystemMixin.java @@ -7,7 +7,7 @@ @Mixin(RenderSystem.class) public class RenderSystemMixin { - @Redirect(method = "flipFrame", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;pollEvents()V", ordinal = 0)) + @Redirect(method = "flipFrame", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;pollEvents()V", ordinal = 0), remap = false) private static void removeFirstPoll() { // noop // should fix some bugs with minecraft polling events twice for some reason (why does it do that in the first place?) diff --git a/src/main/resources/sodium.accesswidener b/src/main/resources/sodium.accesswidener index 6f69cf9242..5d0d3e24d5 100644 --- a/src/main/resources/sodium.accesswidener +++ b/src/main/resources/sodium.accesswidener @@ -1,21 +1,21 @@ accessWidener v1 named -accessible class net/minecraft/client/model/ModelPart$Vertex -accessible class net/minecraft/client/model/ModelPart$Quad -accessible class net/minecraft/client/texture/SpriteContents$Interpolation -accessible class net/minecraft/client/texture/SpriteContents$Animation -accessible class net/minecraft/client/texture/SpriteContents$AnimationFrame -accessible class net/minecraft/client/texture/SpriteContents$AnimatorImpl -accessible class net/minecraft/world/chunk/PalettedContainer$Data -accessible class net/minecraft/world/chunk/PalettedContainer$DataProvider -accessible class net/minecraft/client/render/BackgroundRenderer$FogData -accessible class net/minecraft/client/render/BackgroundRenderer$StatusEffectFogModifier -accessible class net/minecraft/client/texture/TextureStitcher$Holder -accessible class net/minecraft/world/biome/Biome$Weather -accessible method net/minecraft/client/render/chunk/BlockBufferBuilderPool (Ljava/util/List;)V +accessible class net/minecraft/client/model/geom/ModelPart$Vertex +accessible class net/minecraft/client/model/geom/ModelPart$Polygon +accessible class net/minecraft/client/renderer/texture/SpriteContents$InterpolationData +accessible class net/minecraft/client/renderer/texture/SpriteContents$AnimatedTexture +accessible class net/minecraft/client/renderer/texture/SpriteContents$FrameInfo +accessible class net/minecraft/client/renderer/texture/SpriteContents$Ticker +accessible class net/minecraft/world/level/chunk/PalettedContainer$Data +accessible class net/minecraft/world/level/chunk/PalettedContainer$Configuration +accessible class net/minecraft/client/renderer/FogRenderer$FogData +accessible class net/minecraft/client/renderer/FogRenderer$MobEffectFogFunction +accessible class net/minecraft/client/renderer/texture/Stitcher$Holder +accessible class net/minecraft/world/level/biome/Biome$ClimateSettings +accessible method net/minecraft/client/renderer/SectionBufferBuilderPool (Ljava/util/List;)V -accessible method net/minecraft/client/util/math/MatrixStack$Entry (Lorg/joml/Matrix4f;Lorg/joml/Matrix3f;)V +accessible method com/mojang/blaze3d/vertex/PoseStack$Pose (Lorg/joml/Matrix4f;Lorg/joml/Matrix3f;)V -accessible field net/minecraft/client/color/world/GrassColors colorMap [I -accessible field net/minecraft/client/color/world/FoliageColors colorMap [I -accessible method net/minecraft/client/render/BackgroundRenderer getFogModifier (Lnet/minecraft/entity/Entity;F)Lnet/minecraft/client/render/BackgroundRenderer$StatusEffectFogModifier; +accessible field net/minecraft/world/level/GrassColor pixels [I +accessible field net/minecraft/world/level/FoliageColor pixels [I +accessible method net/minecraft/client/renderer/FogRenderer getPriorityFogFunction (Lnet/minecraft/world/entity/Entity;F)Lnet/minecraft/client/renderer/FogRenderer$MobEffectFogFunction; \ No newline at end of file From a0b7b17893db79e8daf5ea8d8153496f8c6a7414 Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 9 Feb 2024 02:11:23 +0100 Subject: [PATCH 248/256] fix INorm8.isOpposite being super wrong --- .../caffeinemc/mods/sodium/api/util/NormI8.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/api/java/net/caffeinemc/mods/sodium/api/util/NormI8.java b/src/api/java/net/caffeinemc/mods/sodium/api/util/NormI8.java index 43c6ae8924..7dc0b68c34 100644 --- a/src/api/java/net/caffeinemc/mods/sodium/api/util/NormI8.java +++ b/src/api/java/net/caffeinemc/mods/sodium/api/util/NormI8.java @@ -103,13 +103,14 @@ public static int flipPacked(int norm) { * @param normB The second packed normal */ public static boolean isOpposite(int normA, int normB) { - int normAX = (normA >> X_COMPONENT_OFFSET) & 0xFF; - int normAY = (normA >> Y_COMPONENT_OFFSET) & 0xFF; - int normAZ = (normA >> Z_COMPONENT_OFFSET) & 0xFF; - - int normBX = (normB >> X_COMPONENT_OFFSET) & 0xFF; - int normBY = (normB >> Y_COMPONENT_OFFSET) & 0xFF; - int normBZ = (normB >> Z_COMPONENT_OFFSET) & 0xFF; + // use byte to automatically sign extend the components + byte normAX = (byte) (normA >> X_COMPONENT_OFFSET); + byte normAY = (byte) (normA >> Y_COMPONENT_OFFSET); + byte normAZ = (byte) (normA >> Z_COMPONENT_OFFSET); + + byte normBX = (byte) (normB >> X_COMPONENT_OFFSET); + byte normBY = (byte) (normB >> Y_COMPONENT_OFFSET); + byte normBZ = (byte) (normB >> Z_COMPONENT_OFFSET); return normAX == -normBX && normAY == -normBY && normAZ == -normBZ; } From 69995bfd1fe0ad1efccfedfbacecd6a46f91587e Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 9 Feb 2024 04:03:27 +0100 Subject: [PATCH 249/256] change handling of intersecting geometry, avoid some cases of UNASSIGNED geometry in the fluid renderer, fix use of fallback paths where not necessary, change the partition node's intersecting geometry handler and just fall back to other sorting methods for better results, add heuristic to better deal with intersecting geometry in topo sort (WIP: this together with static topo sort within partition node would probably fix all outstanding problems with waterlogged glass panes) --- .../quad/properties/ModelQuadFacing.java | 24 ++-- .../chunk/compile/pipeline/FluidRenderer.java | 18 +-- .../chunk/translucent_sorting/TQuad.java | 69 +++++++----- .../TranslucentGeometryCollector.java | 13 +-- .../translucent_sorting/bsp_tree/BSPNode.java | 16 +-- .../bsp_tree/InnerBinaryPartitionBSPNode.java | 8 +- .../bsp_tree/InnerPartitionBSPNode.java | 100 +++++++---------- .../data/TopoGraphSorting.java | 103 ++++++++++-------- .../data/TopoSortDynamicData.java | 3 +- .../trigger/GeometryPlanes.java | 2 +- 10 files changed, 174 insertions(+), 182 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java index ea390095e6..9c736e65b7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java @@ -4,6 +4,7 @@ import net.caffeinemc.mods.sodium.api.util.NormI8; import net.minecraft.core.Direction; import net.minecraft.util.Mth; +import org.joml.Math; import org.joml.Vector3f; import org.joml.Vector3fc; @@ -101,33 +102,22 @@ public int getPackedAlignedNormal() { return PACKED_ALIGNED_NORMALS[this.ordinal()]; } - public static ModelQuadFacing fromPackedNormal(float x, float y, float z) { - Vector3f normal = new Vector3f(x, y, z); - - if (!normal.isFinite()) { + public static ModelQuadFacing fromNormal(float x, float y, float z) { + if (!(Math.isFinite(x) && Math.isFinite(y) && Math.isFinite(z))) { return ModelQuadFacing.UNASSIGNED; } - float maxDot = 0; - Direction closestFace = null; - for (Direction face : DirectionUtil.ALL_DIRECTIONS) { - float dot = normal.dot(face.step()); - - if (dot > maxDot) { - maxDot = dot; - closestFace = face; + var step = face.step(); + if (Mth.equal(Math.fma(x, step.x(), Math.fma(y, step.y(), z * step.z())), 1.0f)) { + return ModelQuadFacing.fromDirection(face); } } - if (closestFace != null && Mth.equal(maxDot, 1.0f)) { - return ModelQuadFacing.fromDirection(closestFace); - } - return ModelQuadFacing.UNASSIGNED; } public static ModelQuadFacing fromPackedNormal(int normal) { - return fromPackedNormal(NormI8.unpackX(normal), NormI8.unpackY(normal), NormI8.unpackZ(normal)); + return fromNormal(NormI8.unpackX(normal), NormI8.unpackY(normal), NormI8.unpackZ(normal)); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java index 5b80419c41..45291c7b38 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java @@ -50,6 +50,7 @@ public class FluidRenderer { // TODO: allow this to be changed by vertex format, WARNING: make sure TranslucentGeometryCollector knows about EPSILON // TODO: move fluid rendering to a separate render pass and control glPolygonOffset and glDepthFunc to fix this properly public static final float EPSILON = 0.001f; + private static final float ALIGNED_EQUALS_EPSILON = 0.011f; private final BlockPos.MutableBlockPos scratchPos = new BlockPos.MutableBlockPos(); private final MutableFloat scratchHeight = new MutableFloat(0); @@ -179,13 +180,11 @@ public void render(WorldSlice world, FluidState fluidState, BlockPos blockPos, B Vec3 velocity = fluidState.getFlow(world, blockPos); TextureAtlasSprite sprite; - ModelQuadFacing facing; float u1, u2, u3, u4; float v1, v2, v3, v4; if (velocity.x == 0.0D && velocity.z == 0.0D) { sprite = sprites[0]; - facing = ModelQuadFacing.POS_Y; u1 = sprite.getU(0.0f); v1 = sprite.getV(0.0f); u2 = u1; @@ -196,7 +195,6 @@ public void render(WorldSlice world, FluidState fluidState, BlockPos blockPos, B v4 = v1; } else { sprite = sprites[1]; - facing = ModelQuadFacing.UNASSIGNED; float dir = (float) Mth.atan2(velocity.z, velocity.x) - (1.5707964f); float sin = Mth.sin(dir) * 0.25F; float cos = Mth.cos(dir) * 0.25F; @@ -230,12 +228,14 @@ public void render(WorldSlice world, FluidState fluidState, BlockPos blockPos, B setVertex(quad, 2, 1.0F, southEastHeight, 1.0F, u3, v3); setVertex(quad, 3, 1.0F, northEastHeight, 0.0f, u4, v4); - boolean aligned = northEastHeight == northWestHeight - && northWestHeight == southEastHeight - && southEastHeight == southWestHeight; + // top surface alignedness is calculated with a more relaxed epsilon + boolean aligned = isAlignedEquals(northEastHeight, northWestHeight) + && isAlignedEquals(northWestHeight, southEastHeight) + && isAlignedEquals(southEastHeight, southWestHeight) + && isAlignedEquals(southWestHeight, northEastHeight); this.updateQuad(quad, world, blockPos, lighter, Direction.UP, 1.0F, colorProvider, fluidState); - this.writeQuad(meshBuilder, collector, material, offset, quad, aligned ? facing : ModelQuadFacing.UNASSIGNED, false); + this.writeQuad(meshBuilder, collector, material, offset, quad, aligned ? ModelQuadFacing.POS_Y : ModelQuadFacing.UNASSIGNED, false); if (fluidState.shouldRenderBackwardUpFace(world, this.scratchPos.set(posX, posY + 1, posZ))) { this.writeQuad(meshBuilder, collector, material, offset, quad, @@ -371,6 +371,10 @@ public void render(WorldSlice world, FluidState fluidState, BlockPos blockPos, B } } + private static boolean isAlignedEquals(float a, float b) { + return Math.abs(a - b) <= ALIGNED_EQUALS_EPSILON; + } + private ColorProvider getColorProvider(Fluid fluid, FluidRenderHandler handler) { var override = this.colorProviderRegistry.getColorProvider(fluid); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java index d9d53a4335..d5dd6b23c7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java @@ -23,10 +23,10 @@ public class TQuad { */ private static final int QUANTIZATION_FACTOR = 4; - private final ModelQuadFacing facing; + private ModelQuadFacing facing; private final float[] extents; private final int packedNormal; - private final float dotProduct; + private float dotProduct; private Vector3fc center; // null on aligned quads private Vector3fc quantizedNormal; @@ -37,7 +37,7 @@ private TQuad(ModelQuadFacing facing, float[] extents, Vector3fc center, int pac this.packedNormal = packedNormal; if (this.facing.isAligned()) { - this.dotProduct = this.extents[this.facing.ordinal()] * this.facing.getSign(); + this.dotProduct = getAlignedDotProduct(this.facing, this.extents); } else { float normX = NormI8.unpackX(this.packedNormal); float normY = NormI8.unpackY(this.packedNormal); @@ -46,6 +46,10 @@ private TQuad(ModelQuadFacing facing, float[] extents, Vector3fc center, int pac } } + private static float getAlignedDotProduct(ModelQuadFacing facing, float[] extents) { + return extents[facing.ordinal()] * facing.getSign(); + } + static TQuad fromAligned(ModelQuadFacing facing, float[] extents) { return new TQuad(facing, extents, null, ModelQuadFacing.PACKED_ALIGNED_NORMALS[facing.ordinal()]); } @@ -58,6 +62,24 @@ public ModelQuadFacing getFacing() { return this.facing; } + /** + * Calculates the facing of the quad based on the quantized normal. This updates the dot product to be consistent with the new facing. Since this method computed and allocates the quantized normal, it should be used sparingly and only when the quantized normal is calculated anyway. Additionally, it can modify the facing and not product of the quad which the caller should be aware of. + * + * @return the (potentially changed) facing of the quad + */ + public ModelQuadFacing useQuantizedFacing() { + if (!this.facing.isAligned()) { + // quantize the normal, get the new facing and get fix the dot product to match + this.getQuantizedNormal(); + this.facing = ModelQuadFacing.fromNormal(this.quantizedNormal.x(), this.quantizedNormal.y(), this.quantizedNormal.z()); + if (this.facing.isAligned()) { + this.dotProduct = getAlignedDotProduct(this.facing, this.extents); + } + } + + return this.facing; + } + public float[] getExtents() { return this.extents; } @@ -81,10 +103,6 @@ public int getPackedNormal() { return this.packedNormal; } - public static boolean isOpposite(int normA, int normB) { - return NormI8.isOpposite(normA, normB); - } - public Vector3fc getQuantizedNormal() { if (this.quantizedNormal == null) { if (this.facing.isAligned()) { @@ -134,27 +152,6 @@ int getQuadHash() { return result; } - public float getAlignedSurfaceArea() { - if (!this.facing.isAligned()) { - return 100; - } - - var dX = this.extents[3] - this.extents[0]; - var dY = this.extents[4] - this.extents[1]; - var dZ = this.extents[5] - this.extents[2]; - - if (dX == 0) { - return dY * dZ; - } else if (dY == 0) { - return dX * dZ; - } else if (dZ == 0) { - return dX * dY; - } else { - // non-flat aligned quad, weird edge case - return 90; - } - } - public boolean extentsEqual(float[] other) { return extentsEqual(this.extents, other); } @@ -167,4 +164,20 @@ public static boolean extentsEqual(float[] a, float[] b) { } return true; } + + public static boolean extentsIntersect(float[] extentsA, float[] extentsB) { + for (int axis = 0; axis < 3; axis++) { + var opposite = axis + 3; + + if (extentsA[axis] <= extentsB[opposite] + || extentsB[axis] <= extentsA[opposite]) { + return false; + } + } + return true; + } + + public static boolean extentsIntersect(TQuad a, TQuad b) { + return extentsIntersect(a.extents, b.extents); + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java index 54be478ec9..961baa0214 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java @@ -58,7 +58,6 @@ * received by the main thread. */ public class TranslucentGeometryCollector { - private static final Logger LOGGER = LogManager.getLogger(TranslucentGeometryCollector.class); private final SectionPos sectionPos; @@ -482,10 +481,10 @@ private TranslucentData makeNewTranslucentData(BuiltSectionMeshParts translucent // (no backface culling) and all vertices are in the UNASSIGNED direction. NativeBuffer buffer = PresentTranslucentData.nativeBufferForQuads(this.quads); if (this.sortType == SortType.STATIC_TOPO) { - var result = StaticTopoAcyclicData.fromMesh(translucentMesh, this.quads, this.sectionPos, buffer); - if (result != null) { - return result; - } +// var result = StaticTopoAcyclicData.fromMesh(translucentMesh, this.quads, this.sectionPos, buffer); +// if (result != null) { +// return result; +// } this.sortType = SortType.DYNAMIC; } @@ -502,10 +501,6 @@ private TranslucentData makeNewTranslucentData(BuiltSectionMeshParts translucent translucentMesh, cameraPos, this.quads, this.sectionPos, buffer, oldData); } catch (BSPBuildFailureException e) { - // TODO: investigate existing BSP build failures, then remove this logging - LOGGER.warn( - "BSP build failure at {}. Please report this to douira for evaluation alongside with some way of reproducing the geometry in this section. (coordinates and world file or seed)", - this.sectionPos); var geometryPlanes = GeometryPlanes.fromQuadLists(this.sectionPos, this.quads); return TopoSortDynamicData.fromMesh( translucentMesh, cameraPos, this.quads, this.sectionPos, diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java index 83ce7d5ba8..0e02a41846 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java @@ -63,11 +63,9 @@ private static boolean doubleLeafPossible(TQuad quadA, TQuad quadB) { var packedNormalA = quadA.getPackedNormal(); var packedNormalB = quadB.getPackedNormal(); // opposite normal (distance irrelevant) - if (NormI8.isOpposite(packedNormalA, packedNormalB) + return NormI8.isOpposite(packedNormalA, packedNormalB) // same normal and same distance - || packedNormalA == packedNormalB && quadA.getDotProduct() == quadB.getDotProduct()) { - return true; - } + || packedNormalA == packedNormalB && quadA.getDotProduct() == quadB.getDotProduct(); } // coplanar aligned @@ -75,18 +73,16 @@ else if (quadA.getExtents()[facingA.ordinal()] == quadB.getExtents()[facingB.ord return true; } - // aligned facing away from eachother + // aligned facing away from each other else if (facingA == facingB.getOpposite()) { return true; } // aligned otherwise mutually invisible - else if (!TopoGraphSorting.orthogonalQuadVisibleThrough(quadA, quadB) - && !TopoGraphSorting.orthogonalQuadVisibleThrough(quadB, quadA)) { - return true; + else { + return !TopoGraphSorting.orthogonalQuadVisibleThrough(quadA, quadB) + && !TopoGraphSorting.orthogonalQuadVisibleThrough(quadB, quadA); } - - return false; } static BSPNode build(BSPWorkspace workspace, IntArrayList indexes, int depth, BSPNode oldNode) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java index 898f49a9a6..5345b4f225 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java @@ -30,11 +30,11 @@ void addPartitionPlanes(BSPWorkspace workspace) { workspace.addAlignedPartitionPlane(this.axis, this.planeDistance); // also add the planes of the children - if (this.inside instanceof InnerPartitionBSPNode inside) { - inside.addPartitionPlanes(workspace); + if (this.inside instanceof InnerPartitionBSPNode insideChild) { + insideChild.addPartitionPlanes(workspace); } - if (this.outside instanceof InnerPartitionBSPNode outside) { - outside.addPartitionPlanes(workspace); + if (this.outside instanceof InnerPartitionBSPNode outsideChild) { + outsideChild.addPartitionPlanes(workspace); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java index 99c837e1c2..394105e182 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java @@ -1,19 +1,21 @@ package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; -import java.util.Arrays; - -import org.joml.Vector3fc; - import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntConsumer; import it.unimi.dsi.fastutil.longs.LongArrayList; import it.unimi.dsi.fastutil.objects.ReferenceArrayList; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.joml.Vector3fc; + +import java.util.Arrays; /** * Performs aligned BSP partitioning of many nodes and constructs appropriate * BSP nodes based on the result. - * + *

* Implementation notes: * - Presorting the points in block-sized buckets doesn't help. It seems the * sort algorithm is just fast enough to handle this. @@ -25,14 +27,14 @@ * - A simple attempt at lazily writing index data to the buffer didn't yield a * performance improvement. Maybe applying it to the multi partition node would * be more effective (but also much more complex and slower). - * + *

* The encoding doesn't currently support negative distances (nor does such * support appear to be required). Their ordering is wrong when sorting them by * their binary representation. To fix this: "XOR all positive numbers with * 0x8000... and negative numbers with 0xffff... This should flip the sign bit * on both (so negative numbers go first), and then reverse the ordering on - * negative numbers." from https://stackoverflow.com/q/43299299 - * + * negative numbers." from StackOverflow + *

* When aligned partitioning fails the geometry is checked for intersection. If * there is intersection it means the section is unsortable and an approximation * is used instead. When it doesn't intersect but is not aligned partitionable, @@ -42,7 +44,9 @@ * reasonable and common use case (I haven't been able to determine that it is). */ abstract class InnerPartitionBSPNode extends BSPNode { - private static int NODE_REUSE_THRESHOLD = 30; + private static final Logger LOGGER = LogManager.getLogger(InnerPartitionBSPNode.class); + + private static final int NODE_REUSE_THRESHOLD = 30; final Vector3fc planeNormal; final int axis; @@ -54,11 +58,11 @@ abstract class InnerPartitionBSPNode extends BSPNode { /** * Stores data required for testing if the node can be re-used. This data is * only generated for select candidate nodes. - * + *

* It only stores the set of indexes that this node was constructed from and * their extents since the BSP construction only cares about the "opaque" quad * geometry and not the normal or facing. - * + *

* Since the indexes might be compressed, the count needs to be stored * separately from before compression. */ @@ -114,8 +118,8 @@ private static class IndexRemapper implements IntConsumer { @Override public void accept(int oldIndex) { - var newIndex = newIndexes.getInt(this.index); - indexMap[oldIndex] = newIndex; + var newIndex = this.newIndexes.getInt(this.index); + this.indexMap[oldIndex] = newIndex; var newOffset = newIndex - oldIndex; if (this.index == 0) { this.firstOffset = newOffset; @@ -130,8 +134,7 @@ boolean hasFixedOffset() { } } - static InnerPartitionBSPNode attemptNodeReuse(BSPWorkspace workspace, IntArrayList newIndexes, int depth, - InnerPartitionBSPNode oldNode) { + static InnerPartitionBSPNode attemptNodeReuse(BSPWorkspace workspace, IntArrayList newIndexes, InnerPartitionBSPNode oldNode) { if (oldNode == null) { return null; } @@ -179,15 +182,15 @@ private static long encodeIntervalPoint(float distance, int quadIndex, int type) return ((long) Float.floatToRawIntBits(distance) << 32) | ((long) type << 30) | quadIndex; } - private static float decodeIntervalPointDistance(long encoded) { + private static float decodeDistance(long encoded) { return Float.intBitsToFloat((int) (encoded >>> 32)); } - private static int decodeIntervalPointQuadIndex(long encoded) { + private static int decodeQuadIndex(long encoded) { return (int) (encoded & 0x3FFFFFFF); } - private static int decodeIntervalPointType(long encoded) { + private static int decodeType(long encoded) { return (int) (encoded >>> 30) & 0b11; } @@ -214,7 +217,7 @@ public static void validateQuadCount(int quadCount) { static BSPNode build(BSPWorkspace workspace, IntArrayList indexes, int depth, BSPNode oldNode) { // attempt reuse of the old node if possible if (oldNode instanceof InnerPartitionBSPNode oldInnerNode) { - var reusedNode = InnerPartitionBSPNode.attemptNodeReuse(workspace, indexes, depth, oldInnerNode); + var reusedNode = InnerPartitionBSPNode.attemptNodeReuse(workspace, indexes, oldInnerNode); if (reusedNode != null) { return reusedNode; } @@ -254,7 +257,7 @@ static BSPNode build(BSPWorkspace workspace, IntArrayList indexes, int depth, BS IntArrayList quadsOn = null; int thickness = 0; for (long point : points) { - switch (decodeIntervalPointType(point)) { + switch (decodeType(point)) { case INTERVAL_START -> { // unless at the start, flush if there's a gap if (thickness == 0 && (quadsBefore != null || quadsOn != null)) { @@ -274,24 +277,23 @@ static BSPNode build(BSPWorkspace workspace, IntArrayList indexes, int depth, BS partitions.add(new Partition(distance, quadsBefore, quadsOn)); distance = -1; quadsOn = null; - quadsOn = null; } if (quadsBefore == null) { quadsBefore = new IntArrayList(); } - quadsBefore.add(decodeIntervalPointQuadIndex(point)); + quadsBefore.add(decodeQuadIndex(point)); } case INTERVAL_END -> { thickness--; if (quadsOn == null) { - distance = decodeIntervalPointDistance(point); + distance = decodeDistance(point); } } case INTERVAL_SIDE -> { // if this point in a gap, it can be put on the plane itself - int pointQuadIndex = decodeIntervalPointQuadIndex(point); + int pointQuadIndex = decodeQuadIndex(point); if (thickness == 0) { - float pointDistance = decodeIntervalPointDistance(point); + float pointDistance = decodeDistance(point); if (quadsOn == null) { // no partition end created yet, set here quadsOn = new IntArrayList(); @@ -310,7 +312,7 @@ static BSPNode build(BSPWorkspace workspace, IntArrayList indexes, int depth, BS } quadsBefore.add(pointQuadIndex); if (quadsOn == null) { - distance = decodeIntervalPointDistance(point); + distance = decodeDistance(point); } } } @@ -323,7 +325,7 @@ static BSPNode build(BSPWorkspace workspace, IntArrayList indexes, int depth, BS continue; } - // check if there's a trailing plane. Otherwise the last plane has distance -1 + // check if there's a trailing plane. Otherwise, the last plane has distance -1 // since it just holds the trailing quads boolean endsWithPlane = quadsOn != null; @@ -350,12 +352,8 @@ static BSPNode build(BSPWorkspace workspace, IntArrayList indexes, int depth, BS partitions, axis, endsWithPlane); } - // test if the geometry intersects with itself. - // if there is self-intersection, return a multi leaf node to just give up - // sorting this geometry. Intersecting geometry is rare but when it does happen, - // it should simply be accepted and rendered as-is. Whatever artifacts this - // causes are considered "ok". - int testsRemaining = 10000; + // test if there is intersecting geometry to avoid logging an error when it's not necessary. It just uses teh fallback for the rare cases of intersecting geometry. + int testsRemaining = 100; for (int quadAIndex = 0; quadAIndex < indexes.size(); quadAIndex++) { var quadA = workspace.quads[indexes.getInt(quadAIndex)]; @@ -363,30 +361,12 @@ static BSPNode build(BSPWorkspace workspace, IntArrayList indexes, int depth, BS var quadB = workspace.quads[indexes.getInt(quadBIndex)]; // aligned quads intersect if their bounding boxes intersect - boolean intersects = true; - for (int axis = 0; axis < 3; axis++) { - var opposite = axis + 3; - var extentsA = quadA.getExtents(); - var extentsB = quadB.getExtents(); - - if (extentsA[axis] <= extentsB[opposite] - || extentsB[axis] <= extentsA[opposite]) { - intersects = false; - break; - } - } - - if (intersects) { - // sort quads by size ascending - indexes.sort((a, b) -> { - var quadX = workspace.quads[a]; - var quadY = workspace.quads[b]; - return Float.compare(quadX.getAlignedSurfaceArea(), quadY.getAlignedSurfaceArea()); - }); - return new LeafMultiBSPNode(BSPSortState.compressIndexes(indexes)); + if (TQuad.extentsIntersect(quadA, quadB)) { + // TODO: use topo sort to better resolve intersecting geometry. When this falls back to topo sorting the entire thing it fails on non-intersecting but unsortable geometry (edge-orthogonal quads) that it can't deal with since it can't generate its own separators. However it can deal with intersecting geometry pretty well with the intersection edge heuristic. + throw new BSPBuildFailureException("Geometry is self-intersecting"); } - if (--testsRemaining == 0) { + if (--testsRemaining <= 0) { break; } } @@ -401,11 +381,15 @@ static BSPNode build(BSPWorkspace workspace, IntArrayList indexes, int depth, BS // geometry is unpartitionable with free cuts (partitions that don't fragment // geometry) or it required unaligned partitioning. Unaligned partitioning is a // hard problem and solving it here isn't really necessary. Fully aligned - // unpartitonable constructions exist but not in normal Minecraft and also not - // likely in any other normal scenario. + // unpartitonable constructions exist but not in normal Minecraft and are also + // not likely in any other normal scenario. // Throwing this exception will cause the entire section to be either topo // sorted or the distance sorting fallback to be used. - throw new BSPBuildFailureException("no partition found"); + // TODO: investigate BSP build failures if they happen, then remove this logging + LOGGER.warn( + "BSP build failure at {}. Please report this to douira for evaluation alongside with some way of reproducing the geometry in this section. (coordinates, and world file or seed)", + workspace.sectionPos); + throw new BSPBuildFailureException("No partition found"); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoGraphSorting.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoGraphSorting.java index 61212fb533..2c5e6763bb 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoGraphSorting.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoGraphSorting.java @@ -32,7 +32,7 @@ private TopoGraphSorting() { * @param planeNormal the normal of the plane * @param point the point to test */ - private static boolean pointOutsideHalfspace(float planeDistance, Vector3fc planeNormal, Vector3fc point) { + private static boolean pointOutsideHalfSpace(float planeDistance, Vector3fc planeNormal, Vector3fc point) { return planeNormal.dot(point) > planeDistance; } @@ -40,17 +40,27 @@ private static boolean pointInsideHalfSpace(float planeDistance, Vector3fc plane return planeNormal.dot(point) < planeDistance; } - public static boolean orthogonalQuadVisibleThrough(TQuad halfspace, TQuad otherQuad) { - var hd = halfspace.getFacing().ordinal(); - var hdOpposite = halfspace.getFacing().getOpposite().ordinal(); - var od = otherQuad.getFacing().ordinal(); - var hSign = halfspace.getFacing().getSign(); - var otherSign = otherQuad.getFacing().getSign(); - - // A: test that the other quad has an extent within this quad's halfspace - return hSign * halfspace.getExtents()[hd] > hSign * otherQuad.getExtents()[hdOpposite] - // B: test that this quad is not fully within the other quad's halfspace - && !(otherSign * otherQuad.getExtents()[od] >= otherSign * halfspace.getExtents()[od]); + public static boolean orthogonalQuadVisibleThrough(TQuad quadA, TQuad quadB) { + var aDirection = quadA.getFacing().ordinal(); + var aOpposite = quadA.getFacing().getOpposite().ordinal(); + var bDirection = quadB.getFacing().ordinal(); + var aSign = quadA.getFacing().getSign(); + var bSign = quadB.getFacing().getSign(); + + var aExtents = quadA.getExtents(); + var bExtents = quadB.getExtents(); + + // test that B has an extent within A's half space and that A is not fully within B's half space + float BIntoADescent = aSign * aExtents[aDirection] - aSign * bExtents[aOpposite]; + float AOutsideBAscent = bSign * aExtents[bDirection] - bSign * bExtents[bDirection]; + + var vis = BIntoADescent > 0 && AOutsideBAscent > 0; + + // if they're visible and their bounding boxes intersect and apply a heuristic to resolve + if (vis && TQuad.extentsIntersect(aExtents, bExtents)) { + return BIntoADescent + AOutsideBAscent > 1; + } + return vis; } private static boolean testSeparatorRange(Object2ReferenceOpenHashMap distancesByNormal, @@ -75,7 +85,7 @@ private static boolean visibilityWithSeparator(TQuad quadA, TQuad quadB, // sign makes the > work in the other direction which is necessary since the // facing turns the whole space around. The start and end are ordered along the // < relation as is the normal. The normal always points in the direction of - // greater values, even if all of the geometry has negative values. + // greater values, even if all the geometry has negative values. var separatorRangeStart = sign * quadB.getExtents()[direction]; var separatorRangeEnd = sign * quadA.getExtents()[oppositeDirection]; if (separatorRangeStart > separatorRangeEnd) { @@ -91,7 +101,7 @@ private static boolean visibilityWithSeparator(TQuad quadA, TQuad quadB, // use camera distance as the start because even if there's no geometry that // generates such separator plane itself, if there's any plane that triggers the - // section before the camera can see B through A this is enough. The separator + // section before the camera can see B through A, this is enough. The separator // doesn't need to be between B and A if the camera will cross another separator // before any separator that could be between B and A. separatorRangeStart = cameraDistance; @@ -107,8 +117,7 @@ private static boolean visibilityWithSeparator(TQuad quadA, TQuad quadB, } // NOTE: unaligned normals for separators are not checked because doing so is a - // hard - // problem and this is an approximation. The fully correct topo sort would need + // hard problem and this is an approximation. The fully correct topo sort would need // to be much more complicated. // visibility not disproven @@ -124,7 +133,7 @@ private static boolean visibilityWithSeparator(TQuad quadA, TQuad quadB, * @param other the quad being tested * @param distancesByNormal a map of normals to sorted arrays of face plane * distances for disproving that the quads are visible - * through eachother, null to disable + * through each other, null to disable * * @return true if the other quad is visible through the first quad */ @@ -135,16 +144,16 @@ private static boolean quadVisibleThrough(TQuad quad, TQuad other, } // aligned quads - var quadFacing = quad.getFacing(); - var otherFacing = other.getFacing(); + var quadFacing = quad.useQuantizedFacing(); + var otherFacing = other.useQuantizedFacing(); boolean result; if (quadFacing != ModelQuadFacing.UNASSIGNED && otherFacing != ModelQuadFacing.UNASSIGNED) { - // opposites never see eachother + // opposites never see each other if (quadFacing.getOpposite() == otherFacing) { return false; } - // parallel quads, coplanar quads are not visible to eachother + // parallel quads, coplanar quads are not visible to each other if (quadFacing == otherFacing) { var sign = quadFacing.getSign(); var direction = quadFacing.ordinal(); @@ -156,8 +165,8 @@ private static boolean quadVisibleThrough(TQuad quad, TQuad other, } else { // at least one unaligned quad // this is an approximation since our quads don't store all their vertices. - // check that other center is within the halfspace of quad and that quad isn't - // in the halfspace of other + // check that other center is within the half space of quad and that quad isn't + // in the half space of other result = pointInsideHalfSpace(quad.getDotProduct(), quad.getQuantizedNormal(), other.getCenter()) && !pointInsideHalfSpace(other.getDotProduct(), other.getQuantizedNormal(), quad.getCenter()); } @@ -188,7 +197,7 @@ public static boolean topoSortDepthFirstCyclic( Object2ReferenceOpenHashMap distancesByNormal, Vector3fc cameraPos) { // if enabled, check for visibility and produce a mapping of indices - TQuad[] quads = null; + TQuad[] quads; int[] activeToRealIndex = null; int activeQuads = 0; if (cameraPos != null) { @@ -202,7 +211,7 @@ public static boolean topoSortDepthFirstCyclic( // NOTE: This approximation may introduce wrong sorting if the real and the // quantized normal aren't the same. A quad may be ignored with the quantized // normal, but it's actually visible in camera. - if (pointOutsideHalfspace(quad.getDotProduct(), quad.getQuantizedNormal(), cameraPos)) { + if (pointOutsideHalfSpace(quad.getDotProduct(), quad.getQuantizedNormal(), cameraPos)) { activeToRealIndex[activeQuads] = i; quads[activeQuads] = quad; activeQuads++; @@ -258,31 +267,33 @@ public static boolean topoSortDepthFirstCyclic( var currentQuadIndex = stack[stackPos]; var nextEdgeTest = unvisited.nextSetBit(nextEdge[stackPos]); if (nextEdgeTest != -1) { - var currentQuad = quads[currentQuadIndex]; - var nextQuad = quads[nextEdgeTest]; - if (quadVisibleThrough(currentQuad, nextQuad, distancesByNormal, cameraPos)) { - // if the visible quad is on the stack, there is a cycle - if (onStack.getAndSet(nextEdgeTest)) { - return false; + if (currentQuadIndex != nextEdgeTest) { + var currentQuad = quads[currentQuadIndex]; + var nextQuad = quads[nextEdgeTest]; + if (quadVisibleThrough(currentQuad, nextQuad, distancesByNormal, cameraPos)) { + // if the visible quad is on the stack, there is a cycle + if (onStack.getAndSet(nextEdgeTest)) { + return false; + } + + // set the next edge + nextEdge[stackPos] = nextEdgeTest + 1; + + // visit the next quad, onStack is already set + stackPos++; + stack[stackPos] = nextEdgeTest; + nextEdge[stackPos] = 0; + continue; } + } - // set the next edge - nextEdge[stackPos] = nextEdgeTest + 1; + // go to the next edge + nextEdgeTest++; - // visit the next quad, onStack is already set - stackPos++; - stack[stackPos] = nextEdgeTest; - nextEdge[stackPos] = 0; + // if we haven't reached the end of the edges yet + if (nextEdgeTest < activeQuads) { + nextEdge[stackPos] = nextEdgeTest; continue; - } else { - // go to the next edge - nextEdgeTest++; - - // if we haven't reached the end of the edges yet - if (nextEdgeTest < activeQuads) { - nextEdge[stackPos] = nextEdgeTest; - continue; - } } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java index d0c37caf36..e0ad5738c2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java @@ -40,7 +40,7 @@ public class TopoSortDynamicData extends DynamicData { private double directTriggerKey = -1; private int consecutiveTopoSortFailures = 0; private boolean pendingTriggerIsDirect; - private Object2ReferenceOpenHashMap distancesByNormal; + private final Object2ReferenceOpenHashMap distancesByNormal; private static final int MAX_TOPO_SORT_QUADS = 1000; private static final int MAX_TOPO_SORT_TIME_NS = 1_000_000; @@ -184,7 +184,6 @@ private void sort(Vector3fc cameraPos, boolean isDirectTrigger, boolean initial) if (this.directTrigger) { indexBuffer.rewind(); distanceSortDirect(indexBuffer, this.quads, cameraPos); - return; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GeometryPlanes.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GeometryPlanes.java index 1092f4728c..322c9ed2d8 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GeometryPlanes.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GeometryPlanes.java @@ -90,7 +90,7 @@ public void addUnalignedPlane(SectionPos sectionPos, Vector3fc normal, float dis } public void addQuadPlane(SectionPos sectionPos, TQuad quad) { - var facing = quad.getFacing(); + var facing = quad.useQuantizedFacing(); if (facing.isAligned()) { this.addAlignedPlane(sectionPos, facing.ordinal(), quad.getDotProduct()); } else { From 05c6c48dfcbfd51cf15219d1a4da8a8cfc230ece Mon Sep 17 00:00:00 2001 From: douira Date: Fri, 9 Feb 2024 14:24:50 +0100 Subject: [PATCH 250/256] fix including of interval tree dependency --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 682ac949e8..7ab3840a64 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -65,7 +65,7 @@ dependencies { minecraft(group = "com.mojang", name = "minecraft", version = Constants.MINECRAFT_VERSION) mappings(loom.officialMojangMappings()) modImplementation(group = "net.fabricmc", name = "fabric-loader", version = Constants.FABRIC_LOADER_VERSION) - modImplementation(group = "com.lodborg", name = "interval-tree", version = "1.0.0") + include(implementation(group = "com.lodborg", name = "interval-tree", version = "1.0.0")) fun addEmbeddedFabricModule(name: String) { val module = fabricApi.module(name, Constants.FABRIC_API_VERSION) From 03b6d2419f9a204cf75307c36f648204af89c34e Mon Sep 17 00:00:00 2001 From: douira Date: Sat, 10 Feb 2024 03:46:36 +0100 Subject: [PATCH 251/256] static topo sorting within partition tree nodes avoids using the fallback sometimes and improves the visuals of waterlogged glass panes in many cases --- .../translucent_sorting/AlignableNormal.java | 5 +- .../TranslucentGeometryCollector.java | 44 ++++------- .../bsp_tree/BSPSortState.java | 13 +++- .../bsp_tree/InnerPartitionBSPNode.java | 50 ++++++++++++- .../data/StaticTopoAcyclicData.java | 15 +++- .../data/TopoGraphSorting.java | 74 +++++++++++-------- .../data/TopoSortDynamicData.java | 14 +++- .../data/TranslucentData.java | 17 ----- 8 files changed, 144 insertions(+), 88 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AlignableNormal.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AlignableNormal.java index 27173c247a..e9cd62b95c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AlignableNormal.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AlignableNormal.java @@ -65,10 +65,7 @@ public boolean equals(Object obj) { return false; } AlignableNormal other = (AlignableNormal) obj; - if (this.alignedDirection != other.alignedDirection) { - return false; - } - return true; + return this.alignedDirection == other.alignedDirection; } public static boolean queryRange(float[] sortedDistances, float start, float end) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java index 961baa0214..9c7320cd06 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java @@ -1,11 +1,5 @@ package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; -import java.util.Arrays; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.joml.Vector3f; - import it.unimi.dsi.fastutil.objects.ReferenceArrayList; import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; @@ -13,22 +7,16 @@ import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.FluidRenderer; import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree.BSPBuildFailureException; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.AnyOrderData; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.BSPDynamicData; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.CombinedCameraPos; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.DynamicData; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.NoData; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.PresentTranslucentData; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.StaticNormalRelativeData; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.StaticTopoAcyclicData; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TopoSortDynamicData; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.*; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger.GeometryPlanes; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger.SortTriggering; import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexEncoder; import me.jellysquid.mods.sodium.client.util.NativeBuffer; import net.caffeinemc.mods.sodium.api.util.NormI8; import net.minecraft.core.SectionPos; +import org.joml.Vector3f; + +import java.util.Arrays; /** * The translucent geometry collector collects the data from the renderers and @@ -293,17 +281,17 @@ private static SortType filterSortType(SortType sortType) { * Determines the sort type for the collected geometry from the section. It * determines a sort type, which is either no sorting, a static sort or a * dynamic sort (section in GFNI only in this case). - * + * * See the section on special cases for an explanation of the special sorting - * cases: https://hackmd.io/@douira100/sodium-sl-gfni#Special-Sorting-Cases - * + * cases: ... + * * A: If there are no or only one normal, this builder can be considered * practically empty. - * + * * B: If there are two face planes with opposing normals at the same distance, * then * they can't be seen through each other and this section can be ignored. - * + * * C: If the translucent faces are on the surface of the convex hull of all * translucent faces in the section and face outwards, then there is no way to * see one through another. Since convex hulls are hard, a simpler case only @@ -313,16 +301,16 @@ private static SortType filterSortType(SortType sortType) { * distances line up with the bounding box allows the exclusion of some * sections containing a single convex translucent cuboid (of which not all * faces need to exist). - * + * * D: If there are only two normals which are opposites of * each other, then a special fixed sort order is always a correct sort order. * This ordering sorts the two sets of face planes by their ascending * normal-relative distance. The ordering between the two normals is irrelevant * as they can't be seen through each other anyway. - * + * * More heuristics can be performed here to conservatively determine if this * section could possibly have more than one translucent sort order. - * + * * @return the required sort type to ensure this section always looks correct */ private SortType sortTypeHeuristic() { @@ -481,10 +469,10 @@ private TranslucentData makeNewTranslucentData(BuiltSectionMeshParts translucent // (no backface culling) and all vertices are in the UNASSIGNED direction. NativeBuffer buffer = PresentTranslucentData.nativeBufferForQuads(this.quads); if (this.sortType == SortType.STATIC_TOPO) { -// var result = StaticTopoAcyclicData.fromMesh(translucentMesh, this.quads, this.sectionPos, buffer); -// if (result != null) { -// return result; -// } + var result = StaticTopoAcyclicData.fromMesh(translucentMesh, this.quads, this.sectionPos, buffer); + if (result != null) { + return result; + } this.sortType = SortType.DYNAMIC; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java index 0fadcff7e4..a6a2fafd7a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java @@ -85,6 +85,17 @@ private static int ceilDiv(int x, int y) { return -Math.floorDiv(-x, y); } + private static boolean isOutOfBounds(int size) { + return size < INDEX_COMPRESSION_MIN_LENGTH || size > 1 << 10; + } + + static int[] compressIndexesInPlace(int[] indexes, boolean doSort) { + if (isOutOfBounds(indexes.length)) { + return indexes; + } + return compressIndexes(IntArrayList.wrap(indexes), doSort); + } + static int[] compressIndexes(IntArrayList indexes) { return compressIndexes(indexes, true); } @@ -104,7 +115,7 @@ static int[] compressIndexes(IntArrayList indexes) { */ static int[] compressIndexes(IntArrayList indexes, boolean doSort) { // bail on short lists - if (indexes.size() < INDEX_COMPRESSION_MIN_LENGTH || indexes.size() > 1 << 10) { + if (isOutOfBounds(indexes.size())) { return indexes.toIntArray(); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java index 394105e182..6c71a3720d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java @@ -6,6 +6,7 @@ import it.unimi.dsi.fastutil.objects.ReferenceArrayList; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; +import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TopoGraphSorting; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.joml.Vector3fc; @@ -362,8 +363,11 @@ static BSPNode build(BSPWorkspace workspace, IntArrayList indexes, int depth, BS // aligned quads intersect if their bounding boxes intersect if (TQuad.extentsIntersect(quadA, quadB)) { - // TODO: use topo sort to better resolve intersecting geometry. When this falls back to topo sorting the entire thing it fails on non-intersecting but unsortable geometry (edge-orthogonal quads) that it can't deal with since it can't generate its own separators. However it can deal with intersecting geometry pretty well with the intersection edge heuristic. - throw new BSPBuildFailureException("Geometry is self-intersecting"); + var multiLeafNode = buildTopoMultiLeafNode(workspace, indexes); + if (multiLeafNode == null) { + throw new BSPBuildFailureException("Geometry is self-intersecting and can't be statically topo sorted"); + } + return multiLeafNode; } if (--testsRemaining <= 0) { @@ -381,7 +385,7 @@ static BSPNode build(BSPWorkspace workspace, IntArrayList indexes, int depth, BS // geometry is unpartitionable with free cuts (partitions that don't fragment // geometry) or it required unaligned partitioning. Unaligned partitioning is a // hard problem and solving it here isn't really necessary. Fully aligned - // unpartitonable constructions exist but not in normal Minecraft and are also + // unpartitonable constructions exist but not in normal Minecraft and are also // not likely in any other normal scenario. // Throwing this exception will cause the entire section to be either topo @@ -390,6 +394,44 @@ static BSPNode build(BSPWorkspace workspace, IntArrayList indexes, int depth, BS LOGGER.warn( "BSP build failure at {}. Please report this to douira for evaluation alongside with some way of reproducing the geometry in this section. (coordinates, and world file or seed)", workspace.sectionPos); - throw new BSPBuildFailureException("No partition found"); + + // unpartitionable non-intersecting geometry is warned about, but then we attempt to topo sort it anyway + var multiLeafNode = buildTopoMultiLeafNode(workspace, indexes); + if (multiLeafNode == null) { + throw new BSPBuildFailureException("No partition found but not intersecting and can't be statically topo sorted"); + } + return multiLeafNode; + } + + private static class QuadIndexConsumerIntoArray implements IntConsumer { + final int[] indexes; + private int index = 0; + + QuadIndexConsumerIntoArray(int size) { + this.indexes = new int[size]; + } + + @Override + public void accept(int value) { + this.indexes[this.index++] = value; + } + } + + static private BSPNode buildTopoMultiLeafNode(BSPWorkspace workspace, IntArrayList indexes) { + var quadCount = indexes.size(); + var quads = new TQuad[quadCount]; + var activeToRealIndex = new int[quadCount]; + for (int i = 0; i < indexes.size(); i++) { + var quadIndex = indexes.getInt(i); + quads[i] = workspace.quads[quadIndex]; + activeToRealIndex[i] = quadIndex; + } + + var indexWriter = new QuadIndexConsumerIntoArray(quadCount); + if (!TopoGraphSorting.topoGraphSort(indexWriter, quads, activeToRealIndex, null, null)) { + return null; + } + + return new LeafMultiBSPNode(BSPSortState.compressIndexesInPlace(indexWriter.indexes, false)); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticTopoAcyclicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticTopoAcyclicData.java index 07628d6b6f..e85d324bfd 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticTopoAcyclicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticTopoAcyclicData.java @@ -7,6 +7,9 @@ import me.jellysquid.mods.sodium.client.util.NativeBuffer; import net.minecraft.core.SectionPos; +import java.nio.IntBuffer; +import java.util.function.IntConsumer; + /** * Static topo acyclic sorting uses the topo sorting algorithm but only if it's * possible to sort without dynamic triggering, meaning the sort order never @@ -22,12 +25,20 @@ public SortType getSortType() { return SortType.STATIC_TOPO; } + private record QuadIndexConsumerIntoBuffer(IntBuffer buffer) implements IntConsumer { + @Override + public void accept(int value) { + TranslucentData.writeQuadVertexIndexes(this.buffer, value); + } + } + + public static StaticTopoAcyclicData fromMesh(BuiltSectionMeshParts translucentMesh, TQuad[] quads, SectionPos sectionPos, NativeBuffer buffer) { VertexRange range = TranslucentData.getUnassignedVertexRange(translucentMesh); - var indexBuffer = buffer.getDirectBuffer().asIntBuffer(); + var indexWriter = new QuadIndexConsumerIntoBuffer(buffer.getDirectBuffer().asIntBuffer()); - if (!TopoGraphSorting.topoSortDepthFirstCyclic(indexBuffer, quads, null, null)) { + if (!TopoGraphSorting.topoGraphSort(indexWriter, quads, null, null)) { return null; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoGraphSorting.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoGraphSorting.java index 2c5e6763bb..aa395e8c25 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoGraphSorting.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoGraphSorting.java @@ -1,20 +1,19 @@ package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data; -import java.nio.IntBuffer; - -import org.joml.Vector3fc; - import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.AlignableNormal; import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; import me.jellysquid.mods.sodium.client.util.collections.BitArray; +import org.joml.Vector3fc; + +import java.util.function.IntConsumer; /** * This class contains the sorting algorithms that do topological or distance * sorting. The algorithms are combined in this class to separate them from the * general management code in other classes. - * + *

* Rough attempts at underapproximation of the visibility graph where the * conditions for visibility between quads are made more strict did not yield * significantly more robust topo sorting. @@ -64,7 +63,7 @@ public static boolean orthogonalQuadVisibleThrough(TQuad quadA, TQuad quadB) { } private static boolean testSeparatorRange(Object2ReferenceOpenHashMap distancesByNormal, - Vector3fc normal, float start, float end) { + Vector3fc normal, float start, float end) { var distances = distancesByNormal.get(normal); if (distances == null) { return false; @@ -73,7 +72,7 @@ private static boolean testSeparatorRange(Object2ReferenceOpenHashMap distancesByNormal, Vector3fc cameraPos) { + Object2ReferenceOpenHashMap distancesByNormal, Vector3fc cameraPos) { // check if there is an aligned separator for (int direction = 0; direction < ModelQuadFacing.DIRECTIONS; direction++) { var facing = ModelQuadFacing.VALUES[direction]; @@ -134,11 +133,10 @@ private static boolean visibilityWithSeparator(TQuad quadA, TQuad quadB, * @param distancesByNormal a map of normals to sorted arrays of face plane * distances for disproving that the quads are visible * through each other, null to disable - * * @return true if the other quad is visible through the first quad */ private static boolean quadVisibleThrough(TQuad quad, TQuad other, - Object2ReferenceOpenHashMap distancesByNormal, Vector3fc cameraPos) { + Object2ReferenceOpenHashMap distancesByNormal, Vector3fc cameraPos) { if (quad == other) { return false; } @@ -185,27 +183,27 @@ private static boolean quadVisibleThrough(TQuad quad, TQuad other, * doing a DFS on the implicit graph. Edges are tested as they are searched for * and if necessary separator planes are used to disprove visibility. * - * @param indexBuffer the buffer to write the topo sort result to + * @param indexConsumer the consumer to write the topo sort result to * @param allQuads the quads to sort * @param distancesByNormal a map of normals to sorted arrays of face plane * distances, null to disable * @param cameraPos the camera position, or null to disable the * visibility check */ - public static boolean topoSortDepthFirstCyclic( - IntBuffer indexBuffer, TQuad[] allQuads, + public static boolean topoGraphSort( + IntConsumer indexConsumer, TQuad[] allQuads, Object2ReferenceOpenHashMap distancesByNormal, Vector3fc cameraPos) { // if enabled, check for visibility and produce a mapping of indices TQuad[] quads; int[] activeToRealIndex = null; - int activeQuads = 0; if (cameraPos != null) { // allocate the working quads and index map at the full size to avoid needing to // iterate the quads again after checking visibility quads = new TQuad[allQuads.length]; activeToRealIndex = new int[allQuads.length]; + int activeQuads = 0; for (int i = 0; i < allQuads.length; i++) { TQuad quad = allQuads[i]; // NOTE: This approximation may introduce wrong sorting if the real and the @@ -217,45 +215,59 @@ public static boolean topoSortDepthFirstCyclic( activeQuads++; } else { // write the invisible quads right away - TranslucentData.writeQuadVertexIndexes(indexBuffer, i); + indexConsumer.accept(i); } } } else { quads = allQuads; - activeQuads = allQuads.length; } + return topoGraphSort(indexConsumer, quads, activeToRealIndex, distancesByNormal, cameraPos); + } + + public static boolean topoGraphSort(IntConsumer indexConsumer, TQuad[] quads, int[] activeToRealIndex, Object2ReferenceOpenHashMap distancesByNormal, Vector3fc cameraPos) { + int quadCount = quads.length; + // special case for 0 to 2 quads - if (activeQuads == 0) { + if (quadCount == 0) { return true; } - if (activeQuads == 1) { - TranslucentData.writeMappedQuadVertexIndexes(indexBuffer, 0, activeToRealIndex); + if (quadCount == 1) { + if (activeToRealIndex != null) { + indexConsumer.accept(activeToRealIndex[0]); + } else { + indexConsumer.accept(0); + } return true; } // special case 2 quads for performance - if (activeQuads == 2) { + if (quadCount == 2) { var a = 0; var b = 1; if (quadVisibleThrough(quads[a], quads[b], null, null)) { a = 1; b = 0; } - TranslucentData.writeMappedQuadVertexIndexes(indexBuffer, a, activeToRealIndex); - TranslucentData.writeMappedQuadVertexIndexes(indexBuffer, b, activeToRealIndex); + if (activeToRealIndex != null) { + indexConsumer.accept(activeToRealIndex[a]); + indexConsumer.accept(activeToRealIndex[b]); + } else { + indexConsumer.accept(a); + indexConsumer.accept(b); + } return true; } - BitArray unvisited = new BitArray(activeQuads); - unvisited.set(0, activeQuads); + BitArray unvisited = new BitArray(quadCount); + unvisited.set(0, quadCount); int visitedCount = 0; - BitArray onStack = new BitArray(activeQuads); - int[] stack = new int[activeQuads]; - int[] nextEdge = new int[activeQuads]; + BitArray onStack = new BitArray(quadCount); + int[] stack = new int[quadCount]; + int[] nextEdge = new int[quadCount]; // start dfs searches until all quads are visited - while (visitedCount < activeQuads) { + while (visitedCount < quadCount) { int stackPos = 0; var root = unvisited.nextSetBit(0); stack[stackPos] = root; @@ -291,7 +303,7 @@ public static boolean topoSortDepthFirstCyclic( nextEdgeTest++; // if we haven't reached the end of the edges yet - if (nextEdgeTest < activeQuads) { + if (nextEdgeTest < quadCount) { nextEdge[stackPos] = nextEdgeTest; continue; } @@ -304,7 +316,11 @@ public static boolean topoSortDepthFirstCyclic( stackPos--; // write to the index buffer since the order is now correct - TranslucentData.writeMappedQuadVertexIndexes(indexBuffer, currentQuadIndex, activeToRealIndex); + if (activeToRealIndex != null) { + indexConsumer.accept(activeToRealIndex[currentQuadIndex]); + } else { + indexConsumer.accept(currentQuadIndex); + } } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java index e0ad5738c2..37ae88dbef 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java @@ -2,6 +2,7 @@ import java.nio.IntBuffer; import java.util.Arrays; +import java.util.function.IntConsumer; import org.joml.Vector3dc; import org.joml.Vector3fc; @@ -30,7 +31,7 @@ * this happens, I suspect weird memory behavior or the reuse is not actually * that helpful to the sorting algorithm. */ -public class TopoSortDynamicData extends DynamicData { +public class TopoSortDynamicData extends DynamicData implements IntConsumer { private final TQuad[] quads; private boolean GFNITrigger = true; private boolean directTrigger = false; @@ -41,6 +42,7 @@ public class TopoSortDynamicData extends DynamicData { private int consecutiveTopoSortFailures = 0; private boolean pendingTriggerIsDirect; private final Object2ReferenceOpenHashMap distancesByNormal; + private IntBuffer intBuffer; private static final int MAX_TOPO_SORT_QUADS = 1000; private static final int MAX_TOPO_SORT_TIME_NS = 1_000_000; @@ -148,8 +150,9 @@ private void sort(Vector3fc cameraPos, boolean isDirectTrigger, boolean initial) if (this.GFNITrigger && !isDirectTrigger) { var sortStart = initial ? 0 : System.nanoTime(); - var result = TopoGraphSorting.topoSortDepthFirstCyclic( - indexBuffer, this.quads, this.distancesByNormal, cameraPos); + this.intBuffer = indexBuffer; + var result = TopoGraphSorting.topoGraphSort(this, this.quads, this.distancesByNormal, cameraPos); + this.intBuffer = null; var sortTime = initial ? 0 : System.nanoTime() - sortStart; @@ -239,4 +242,9 @@ public static TopoSortDynamicData fromMesh(BuiltSectionMeshParts translucentMesh return dynamicData; } + + @Override + public void accept(int value) { + TranslucentData.writeQuadVertexIndexes(this.intBuffer, value); + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TranslucentData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TranslucentData.java index e577df7af8..9515c2fe52 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TranslucentData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TranslucentData.java @@ -49,11 +49,6 @@ public void prepareTrigger(boolean isAngleTrigger) { // no-op for other translucent data than GFNI dynamic } - public static int vertexCountToIndexBytes(int vertexCount) { - // convert vertex count to quads, and then to indices, and then to bytes - return vertexCount / VERTICES_PER_QUAD * BYTES_PER_QUAD; - } - public static int vertexCountToQuadCount(int vertexCount) { return vertexCount / VERTICES_PER_QUAD; } @@ -62,22 +57,10 @@ public static int quadCountToIndexBytes(int quadCount) { return quadCount * BYTES_PER_QUAD; } - public static int quadCountToIndexCount(int quadCount) { - return quadCount * INDICES_PER_QUAD; - } - public static int indexBytesToQuadCount(int indexBytes) { return indexBytes / BYTES_PER_QUAD; } - public static void writeMappedQuadVertexIndexes(IntBuffer intBuffer, int quadIndex, int[] indexMapping) { - if (indexMapping == null) { - writeQuadVertexIndexes(intBuffer, quadIndex); - } else { - writeQuadVertexIndexes(intBuffer, indexMapping[quadIndex]); - } - } - public static void writeQuadVertexIndexes(IntBuffer intBuffer, int quadIndex) { int vertexOffset = quadIndex * VERTICES_PER_QUAD; From 6338fee24a675e229632c8d13d2c0c9c5b6a395a Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 12 Feb 2024 15:20:38 +0100 Subject: [PATCH 252/256] typo --- .../mods/sodium/client/render/chunk/RenderSectionManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java index f74640f78c..90f0f65ad3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -486,7 +486,7 @@ private void submitSectionTasks(ChunkJobCollector collector, ChunkUpdateType typ // This doesn't apply to sorting tasks as that would result in the section being // marked as empty just because it was scheduled to be sorted and its dynamic // data has since been removed. In that case simply nothing is done as the - // rebuild that must have happened in the mean time includes new non-dynamic + // rebuild that must have happened in the meantime includes new non-dynamic // index data. var result = ChunkJobResult.successfully(new ChunkBuildOutput( section, frame, NoData.forEmptySection(section.getPosition()), From ce425b7ab834bfe4afe4e640ceccec9f149c026d Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 12 Feb 2024 15:38:53 +0100 Subject: [PATCH 253/256] simplify control flow to be less confusing --- .../chunk/translucent_sorting/bsp_tree/BSPNode.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java index 0e02a41846..55adac82b7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java @@ -63,9 +63,11 @@ private static boolean doubleLeafPossible(TQuad quadA, TQuad quadB) { var packedNormalA = quadA.getPackedNormal(); var packedNormalB = quadB.getPackedNormal(); // opposite normal (distance irrelevant) - return NormI8.isOpposite(packedNormalA, packedNormalB) + if (NormI8.isOpposite(packedNormalA, packedNormalB) // same normal and same distance - || packedNormalA == packedNormalB && quadA.getDotProduct() == quadB.getDotProduct(); + || packedNormalA == packedNormalB && quadA.getDotProduct() == quadB.getDotProduct()) { + return true; + } } // coplanar aligned @@ -83,6 +85,8 @@ else if (facingA == facingB.getOpposite()) { return !TopoGraphSorting.orthogonalQuadVisibleThrough(quadA, quadB) && !TopoGraphSorting.orthogonalQuadVisibleThrough(quadB, quadA); } + + return false; } static BSPNode build(BSPWorkspace workspace, IntArrayList indexes, int depth, BSPNode oldNode) { From a989f7e5729e50c9d3753dfc15eb63f922422674 Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 12 Feb 2024 18:27:09 +0100 Subject: [PATCH 254/256] package rename from me.jellysquid to net.caffeinemc to better match upstream before merging --- build.gradle.kts | 2 +- .../vertex/format/VertexFormatRegistry.java | 2 +- .../serializer/VertexSerializerRegistry.java | 2 +- .../mods/sodium/client/SodiumPreLaunch.java | 15 ---- .../mods/sodium/client/gl/util/EnumBit.java | 5 -- .../gui/console/message/MessageLevel.java | 7 -- .../client/gui/options/control/Control.java | 12 --- .../client/model/ModelCuboidAccessor.java | 7 -- .../sodium/client/model/light/LightMode.java | 6 -- .../windows/api/version/QueryResult.java | 4 - .../chunk/compile/OutputWithIndexData.java | 7 -- .../compile/buffers/ChunkModelBuilder.java | 11 --- .../chunk/compile/executor/ChunkJob.java | 12 --- .../chunk/vertex/format/ChunkMeshFormats.java | 7 -- .../client/world/WorldRendererExtended.java | 7 -- .../mods/sodium/client/SodiumClientMod.java | 16 ++-- .../mods/sodium/client/SodiumPreLaunch.java | 15 ++++ .../compatibility/checks/Configuration.java | 2 +- .../checks/EarlyDriverScanner.java | 12 +-- .../checks/LateDriverScanner.java | 10 +-- .../compatibility/checks/ModuleScanner.java | 12 +-- .../checks/ResourcePackScanner.java | 6 +- .../checks/SodiumResourcePackMetadata.java | 2 +- .../environment/GLContextInfo.java | 2 +- .../probe/GraphicsAdapterInfo.java | 2 +- .../probe/GraphicsAdapterProbe.java | 2 +- .../probe/GraphicsAdapterVendor.java | 2 +- .../workarounds/Workarounds.java | 8 +- .../nvidia/NvidiaDriverVersion.java | 4 +- .../workarounds/nvidia/NvidiaWorkarounds.java | 8 +- .../client/data/config/MixinConfig.java | 4 +- .../data/fingerprint/FingerprintMeasure.java | 2 +- .../data/fingerprint/HashedFingerprint.java | 4 +- .../mods/sodium/client/gl/GlObject.java | 2 +- .../sodium/client/gl/arena/GlBufferArena.java | 12 +-- .../client/gl/arena/GlBufferSegment.java | 2 +- .../gl/arena/PendingBufferCopyCommand.java | 2 +- .../sodium/client/gl/arena/PendingUpload.java | 4 +- .../arena/staging/FallbackStagingBuffer.java | 10 +-- .../gl/arena/staging/MappedStagingBuffer.java | 16 ++-- .../gl/arena/staging/StagingBuffer.java | 6 +- .../sodium/client/gl/array/GlVertexArray.java | 4 +- .../gl/attribute/GlVertexAttribute.java | 2 +- .../attribute/GlVertexAttributeBinding.java | 2 +- .../gl/attribute/GlVertexAttributeFormat.java | 2 +- .../client/gl/attribute/GlVertexFormat.java | 2 +- .../sodium/client/gl/buffer/GlBuffer.java | 4 +- .../client/gl/buffer/GlBufferMapFlags.java | 4 +- .../client/gl/buffer/GlBufferMapping.java | 2 +- .../gl/buffer/GlBufferStorageFlags.java | 4 +- .../client/gl/buffer/GlBufferTarget.java | 2 +- .../client/gl/buffer/GlBufferUsage.java | 2 +- .../client/gl/buffer/GlImmutableBuffer.java | 4 +- .../client/gl/buffer/GlMutableBuffer.java | 2 +- .../sodium/client/gl/device/CommandList.java | 18 ++--- .../client/gl/device/DrawCommandList.java | 4 +- .../client/gl/device/GLRenderDevice.java | 18 ++--- .../client/gl/device/MultiDrawBatch.java | 2 +- .../sodium/client/gl/device/RenderDevice.java | 4 +- .../gl/functions/BufferStorageFunctions.java | 10 +-- .../client/gl/functions/DeviceFunctions.java | 4 +- .../sodium/client/gl/shader/GlProgram.java | 10 +-- .../sodium/client/gl/shader/GlShader.java | 4 +- .../client/gl/shader/ShaderConstants.java | 2 +- .../sodium/client/gl/shader/ShaderLoader.java | 2 +- .../sodium/client/gl/shader/ShaderParser.java | 2 +- .../sodium/client/gl/shader/ShaderType.java | 2 +- .../client/gl/shader/ShaderWorkarounds.java | 2 +- .../client/gl/shader/uniform/GlUniform.java | 2 +- .../gl/shader/uniform/GlUniformBlock.java | 4 +- .../gl/shader/uniform/GlUniformFloat.java | 2 +- .../gl/shader/uniform/GlUniformFloat3v.java | 2 +- .../gl/shader/uniform/GlUniformFloat4v.java | 2 +- .../gl/shader/uniform/GlUniformInt.java | 2 +- .../gl/shader/uniform/GlUniformMatrix4f.java | 2 +- .../client/gl/state/GlStateTracker.java | 8 +- .../mods/sodium/client/gl/sync/GlFence.java | 2 +- .../tessellation/GlAbstractTessellation.java | 6 +- .../client/gl/tessellation/GlIndexType.java | 2 +- .../gl/tessellation/GlPrimitiveType.java | 2 +- .../gl/tessellation/GlTessellation.java | 4 +- .../GlVertexArrayTessellation.java | 6 +- .../gl/tessellation/TessellationBinding.java | 8 +- .../mods/sodium/client/gl/util/EnumBit.java | 5 ++ .../sodium/client/gl/util/EnumBitField.java | 2 +- .../sodium/client/gl/util/VertexRange.java | 2 +- .../client/gui/SodiumGameOptionPages.java | 24 +++--- .../sodium/client/gui/SodiumGameOptions.java | 8 +- .../sodium/client/gui/SodiumOptionsGUI.java | 30 ++++---- .../sodium/client/gui/console/Console.java | 6 +- .../client/gui/console/ConsoleHooks.java | 2 +- .../client/gui/console/ConsoleRenderer.java | 6 +- .../client/gui/console/ConsoleSink.java | 4 +- .../client/gui/console/message/Message.java | 2 +- .../gui/console/message/MessageLevel.java | 7 ++ .../sodium/client/gui/options/Option.java | 6 +- .../sodium/client/gui/options/OptionFlag.java | 2 +- .../client/gui/options/OptionGroup.java | 2 +- .../client/gui/options/OptionImpact.java | 2 +- .../sodium/client/gui/options/OptionImpl.java | 10 +-- .../sodium/client/gui/options/OptionPage.java | 2 +- .../client/gui/options/TextProvider.java | 2 +- .../gui/options/binding/GenericBinding.java | 2 +- .../gui/options/binding/OptionBinding.java | 2 +- .../compat/VanillaBooleanOptionBinding.java | 4 +- .../client/gui/options/control/Control.java | 12 +++ .../gui/options/control/ControlElement.java | 8 +- .../control/ControlValueFormatter.java | 2 +- .../gui/options/control/CyclingControl.java | 8 +- .../gui/options/control/SliderControl.java | 6 +- .../gui/options/control/TickBoxControl.java | 6 +- .../storage/MinecraftOptionsStorage.java | 4 +- .../gui/options/storage/OptionStorage.java | 2 +- .../options/storage/SodiumOptionsStorage.java | 6 +- .../client/gui/prompt/ScreenPrompt.java | 10 +-- .../client/gui/prompt/ScreenPromptable.java | 4 +- .../gui/screen/ConfigCorruptedScreen.java | 8 +- .../client/gui/widgets/AbstractWidget.java | 2 +- .../client/gui/widgets/FlatButtonWidget.java | 4 +- .../client/model/ModelCuboidAccessor.java | 7 ++ .../client/model/color/ColorProvider.java | 6 +- .../model/color/ColorProviderRegistry.java | 4 +- .../model/color/DefaultColorProviders.java | 10 +-- .../color/interop/BlockColorsExtended.java | 2 +- .../color/interop/ItemColorsExtended.java | 2 +- .../sodium/client/model/light/LightMode.java | 6 ++ .../client/model/light/LightPipeline.java | 6 +- .../model/light/LightPipelineProvider.java | 8 +- .../model/light/data/ArrayLightDataCache.java | 4 +- .../model/light/data/HashLightDataCache.java | 2 +- .../model/light/data/LightDataAccess.java | 2 +- .../model/light/data/QuadLightData.java | 2 +- .../model/light/flat/FlatLightPipeline.java | 14 ++-- .../model/light/smooth/AoCompletionFlags.java | 2 +- .../client/model/light/smooth/AoFaceData.java | 6 +- .../model/light/smooth/AoNeighborInfo.java | 2 +- .../light/smooth/SmoothLightPipeline.java | 12 +-- .../client/model/quad/BakedQuadView.java | 4 +- .../sodium/client/model/quad/ModelQuad.java | 4 +- .../client/model/quad/ModelQuadView.java | 4 +- .../model/quad/ModelQuadViewMutable.java | 4 +- .../quad/blender/BlendedColorProvider.java | 8 +- .../quad/properties/ModelQuadFacing.java | 4 +- .../model/quad/properties/ModelQuadFlags.java | 4 +- .../quad/properties/ModelQuadOrientation.java | 2 +- .../quad/properties/ModelQuadWinding.java | 2 +- .../sodium/client/platform/MessageBox.java | 8 +- .../sodium/client/platform/unix/Libc.java | 2 +- .../platform/windows/WindowsCommandLine.java | 4 +- .../windows/WindowsDriverStoreVersion.java | 2 +- .../client/platform/windows/api/Kernel32.java | 2 +- .../client/platform/windows/api/User32.java | 4 +- .../windows/api/msgbox/MsgBoxCallback.java | 2 +- .../windows/api/msgbox/MsgBoxCallbackI.java | 2 +- .../windows/api/msgbox/MsgBoxParamSw.java | 2 +- .../windows/api/version/LanguageCodePage.java | 2 +- .../windows/api/version/QueryResult.java | 4 + .../platform/windows/api/version/Version.java | 4 +- .../windows/api/version/VersionInfo.java | 2 +- .../client/render/SodiumWorldRenderer.java | 36 ++++----- .../render/chunk/ChunkRenderMatrices.java | 2 +- .../client/render/chunk/ChunkRenderer.java | 10 +-- .../client/render/chunk/ChunkUpdateType.java | 4 +- .../render/chunk/DefaultChunkRenderer.java | 58 +++++++------- .../render/chunk/LocalSectionIndex.java | 2 +- .../render/chunk/NonStoringBuilderPool.java | 2 +- .../client/render/chunk/RenderSection.java | 18 ++--- .../render/chunk/RenderSectionFlags.java | 2 +- .../render/chunk/RenderSectionManager.java | 76 +++++++++---------- .../render/chunk/ShaderChunkRenderer.java | 18 ++--- .../render/chunk/SharedQuadIndexBuffer.java | 20 ++--- .../chunk/compile/BuilderTaskOutput.java | 4 +- .../chunk/compile/ChunkBuildBuffers.java | 26 +++---- .../chunk/compile/ChunkBuildContext.java | 6 +- .../chunk/compile/ChunkBuildOutput.java | 14 ++-- .../render/chunk/compile/ChunkSortOutput.java | 8 +- .../chunk/compile/OutputWithIndexData.java | 7 ++ .../buffers/BakedChunkModelBuilder.java | 8 +- .../compile/buffers/ChunkModelBuilder.java | 11 +++ .../chunk/compile/executor/ChunkBuilder.java | 12 +-- .../chunk/compile/executor/ChunkJob.java | 12 +++ .../compile/executor/ChunkJobCollector.java | 4 +- .../chunk/compile/executor/ChunkJobQueue.java | 2 +- .../compile/executor/ChunkJobResult.java | 2 +- .../chunk/compile/executor/ChunkJobTyped.java | 8 +- .../compile/pipeline/BlockOcclusionCache.java | 4 +- .../compile/pipeline/BlockRenderCache.java | 12 +-- .../compile/pipeline/BlockRenderContext.java | 6 +- .../chunk/compile/pipeline/BlockRenderer.java | 38 +++++----- .../chunk/compile/pipeline/FluidRenderer.java | 44 +++++------ .../tasks/ChunkBuilderMeshingTask.java | 40 +++++----- .../tasks/ChunkBuilderSortingTask.java | 14 ++-- .../chunk/compile/tasks/ChunkBuilderTask.java | 12 +-- .../render/chunk/data/BuiltSectionInfo.java | 10 +-- .../chunk/data/BuiltSectionMeshParts.java | 6 +- .../chunk/data/SectionRenderDataStorage.java | 10 +-- .../chunk/data/SectionRenderDataUnsafe.java | 2 +- .../render/chunk/lists/ChunkRenderList.java | 16 ++-- .../chunk/lists/ChunkRenderListIterable.java | 2 +- .../render/chunk/lists/SortedRenderLists.java | 8 +- .../chunk/lists/VisibleChunkCollector.java | 10 +-- .../client/render/chunk/map/ChunkStatus.java | 2 +- .../client/render/chunk/map/ChunkTracker.java | 2 +- .../render/chunk/map/ChunkTrackerHolder.java | 2 +- .../chunk/map/ClientChunkEventListener.java | 2 +- .../chunk/occlusion/GraphDirection.java | 2 +- .../chunk/occlusion/GraphDirectionSet.java | 2 +- .../chunk/occlusion/OcclusionCuller.java | 14 ++-- .../chunk/occlusion/VisibilityEncoding.java | 2 +- .../render/chunk/region/RenderRegion.java | 26 +++---- .../chunk/region/RenderRegionManager.java | 38 +++++----- .../render/chunk/shader/ChunkFogMode.java | 2 +- .../shader/ChunkShaderBindingPoints.java | 2 +- .../chunk/shader/ChunkShaderFogComponent.java | 8 +- .../chunk/shader/ChunkShaderInterface.java | 10 +-- .../chunk/shader/ChunkShaderOptions.java | 8 +- .../chunk/shader/ChunkShaderTextureSlot.java | 2 +- .../chunk/shader/ShaderBindingContext.java | 6 +- .../terrain/DefaultTerrainRenderPasses.java | 2 +- .../chunk/terrain/TerrainRenderPass.java | 2 +- .../terrain/material/DefaultMaterials.java | 6 +- .../chunk/terrain/material/Material.java | 8 +- .../parameters/AlphaCutoffParameter.java | 2 +- .../parameters/MaterialParameters.java | 2 +- .../translucent_sorting/AlignableNormal.java | 4 +- .../translucent_sorting/SortBehavior.java | 2 +- .../chunk/translucent_sorting/SortType.java | 2 +- .../chunk/translucent_sorting/TQuad.java | 4 +- .../TranslucentGeometryCollector.java | 24 +++--- .../bsp_tree/BSPBuildFailureException.java | 2 +- .../translucent_sorting/bsp_tree/BSPNode.java | 8 +- .../bsp_tree/BSPResult.java | 4 +- .../bsp_tree/BSPSortState.java | 6 +- .../bsp_tree/BSPWorkspace.java | 6 +- .../bsp_tree/InnerBinaryPartitionBSPNode.java | 2 +- .../bsp_tree/InnerMultiPartitionBSPNode.java | 2 +- .../bsp_tree/InnerPartitionBSPNode.java | 8 +- .../bsp_tree/LeafDoubleBSPNode.java | 2 +- .../bsp_tree/LeafMultiBSPNode.java | 2 +- .../bsp_tree/LeafSingleBSPNode.java | 2 +- .../bsp_tree/Partition.java | 2 +- .../data/AnyOrderData.java | 12 +-- .../data/BSPDynamicData.java | 14 ++-- .../data/CombinedCameraPos.java | 2 +- .../translucent_sorting/data/DynamicData.java | 10 +-- .../data/MixedDirectionData.java | 8 +- .../translucent_sorting/data/NoData.java | 4 +- .../data/PresentTranslucentData.java | 8 +- .../data/SplitDirectionData.java | 6 +- .../data/StaticNormalRelativeData.java | 16 ++-- .../data/StaticTopoAcyclicData.java | 12 +-- .../data/TopoGraphSorting.java | 10 +-- .../data/TopoSortDynamicData.java | 14 ++-- .../data/TranslucentData.java | 10 +-- .../trigger/CameraMovement.java | 2 +- .../trigger/DirectTriggers.java | 8 +- .../trigger/GFNITriggers.java | 8 +- .../trigger/GeometryPlanes.java | 6 +- .../translucent_sorting/trigger/Group.java | 4 +- .../trigger/NormalList.java | 4 +- .../trigger/NormalPlanes.java | 4 +- .../trigger/SortTriggering.java | 16 ++-- .../builder/ChunkMeshBufferBuilder.java | 8 +- .../vertex/format/ChunkMeshAttribute.java | 2 +- .../chunk/vertex/format/ChunkMeshFormats.java | 7 ++ .../vertex/format/ChunkVertexEncoder.java | 4 +- .../chunk/vertex/format/ChunkVertexType.java | 4 +- .../format/impl/CompactChunkVertex.java | 12 +-- .../render/immediate/CloudRenderer.java | 4 +- .../immediate/model/BakedModelEncoder.java | 4 +- .../immediate/model/EntityRenderer.java | 2 +- .../render/immediate/model/ModelCuboid.java | 2 +- .../render/immediate/model/ModelPartData.java | 2 +- .../texture/SpriteContentsExtended.java | 2 +- .../client/render/texture/SpriteUtil.java | 2 +- .../render/util/DeferredRenderTask.java | 2 +- .../client/render/util/RenderAsserts.java | 2 +- .../render/vertex/VertexConsumerTracker.java | 4 +- .../render/vertex/VertexConsumerUtils.java | 2 +- .../vertex/VertexFormatDescriptionImpl.java | 4 +- .../vertex/VertexFormatRegistryImpl.java | 2 +- .../vertex/buffer/ExtendedBufferBuilder.java | 2 +- .../vertex/buffer/SodiumBufferBuilder.java | 2 +- .../VertexSerializerRegistryImpl.java | 4 +- .../generated/VertexSerializerFactory.java | 2 +- .../render/viewport/CameraTransform.java | 4 +- .../client/render/viewport/Viewport.java | 4 +- .../render/viewport/ViewportProvider.java | 2 +- .../render/viewport/frustum/Frustum.java | 2 +- .../viewport/frustum/SimpleFrustum.java | 2 +- .../mods/sodium/client/util/BitwiseMath.java | 2 +- .../mods/sodium/client/util/Dim2i.java | 2 +- .../sodium/client/util/DirectionUtil.java | 2 +- .../mods/sodium/client/util/FileUtil.java | 2 +- .../sodium/client/util/FlawlessFrames.java | 2 +- .../mods/sodium/client/util/ListUtil.java | 2 +- .../mods/sodium/client/util/MathUtil.java | 2 +- .../sodium/client/util/ModelQuadUtil.java | 2 +- .../mods/sodium/client/util/NativeBuffer.java | 4 +- .../sodium/client/util/NativeImageHelper.java | 4 +- .../mods/sodium/client/util/TextureUtil.java | 2 +- .../client/util/collections/BitArray.java | 2 +- .../util/collections/DoubleBufferedQueue.java | 2 +- .../client/util/collections/ReadQueue.java | 2 +- .../client/util/collections/WriteQueue.java | 2 +- .../sodium/client/util/color/BoxBlur.java | 2 +- .../sodium/client/util/color/ColorSRGB.java | 2 +- .../client/util/color/FastCubicSampler.java | 2 +- .../util/iterator/ByteArrayIterator.java | 2 +- .../client/util/iterator/ByteIterator.java | 2 +- .../iterator/ReversibleByteArrayIterator.java | 2 +- .../ReversibleObjectArrayIterator.java | 2 +- .../client/util/sorting/AbstractSort.java | 2 +- .../client/util/sorting/InsertionSort.java | 2 +- .../sodium/client/util/sorting/MergeSort.java | 2 +- .../sodium/client/util/sorting/RadixSort.java | 2 +- .../client/util/sorting/VertexSorters.java | 2 +- .../client/util/task/CancellationToken.java | 2 +- .../client/world/BiomeSeedProvider.java | 2 +- .../client/world/PaletteStorageExtended.java | 2 +- .../world/ReadableContainerExtended.java | 2 +- .../client/world/WorldRendererExtended.java | 7 ++ .../mods/sodium/client/world/WorldSlice.java | 16 ++-- .../client/world/biome/BiomeColorCache.java | 8 +- .../client/world/biome/BiomeColorMaps.java | 2 +- .../client/world/biome/BiomeColorSource.java | 2 +- .../client/world/biome/BiomeColorView.java | 2 +- .../sodium/client/world/biome/BiomeSlice.java | 10 +-- .../world/cloned/ChunkRenderContext.java | 2 +- .../world/cloned/ClonedChunkSection.java | 6 +- .../world/cloned/ClonedChunkSectionCache.java | 2 +- .../mods/sodium/mixin/MixinOption.java | 2 +- .../mods/sodium/mixin/SodiumMixinPlugin.java | 6 +- .../mixin/core/MinecraftClientMixin.java | 8 +- .../mods/sodium/mixin/core/WindowMixin.java | 6 +- .../core/gui/WorldLoadingStateMixin.java | 2 +- .../core/model/colors/BlockColorsMixin.java | 6 +- .../core/model/colors/ItemColorsMixin.java | 4 +- .../mixin/core/model/quad/BakedQuadMixin.java | 10 +-- .../core/render/VertexFormatAccessor.java | 2 +- .../core/render/frustum/FrustumMixin.java | 8 +- .../consumer/BufferBuilderMixin.java | 6 +- .../consumer/OutlineVertexConsumerMixin.java | 2 +- .../consumer/OverlayVertexConsumerMixin.java | 2 +- .../SpriteTexturedVertexConsumerMixin.java | 2 +- .../VertexConsumerProviderImmediateMixin.java | 6 +- .../consumer/VertexConsumersMixin.java | 2 +- .../world/BufferBuilderStorageMixin.java | 4 +- .../core/render/world/WorldRendererMixin.java | 14 ++-- .../core/world/biome/ClientWorldMixin.java | 4 +- .../world/chunk/EmptyPaletteStorageMixin.java | 4 +- .../world/chunk/PackedIntegerArrayMixin.java | 4 +- .../world/chunk/PalettedContainerMixin.java | 6 +- .../world/map/ClientChunkManagerMixin.java | 6 +- .../map/ClientPlayNetworkHandlerMixin.java | 6 +- .../core/world/map/ClientWorldMixin.java | 6 +- .../debug/checks/AbstractTextureMixin.java | 4 +- .../mixin/debug/checks/AsyncTextureMixin.java | 4 +- .../debug/checks/BufferRendererMixin.java | 4 +- .../mixin/debug/checks/FramebufferMixin.java | 4 +- .../debug/checks/GlStateManagerMixin.java | 4 +- .../checks/NativeImageBackedTextureMixin.java | 4 +- .../mixin/debug/checks/NativeImageMixin.java | 4 +- .../debug/checks/PlayerSkinTextureMixin.java | 2 +- .../mixin/debug/checks/RenderSystemMixin.java | 6 +- .../debug/checks/SpriteAtlasTextureMixin.java | 4 +- .../SpriteContentsAnimatorImplMixin.java | 4 +- .../debug/checks/TextureManagerMixin.java | 6 +- .../mixin/debug/checks/VertexBufferMixin.java | 4 +- .../mixin/debug/checks/VertexFormatMixin.java | 4 +- .../debug/checks/WindowFramebufferMixin.java | 4 +- .../gui/hooks/console/GameRendererMixin.java | 4 +- .../gui/hooks/debug/DebugHudMixin.java | 10 +-- .../hooks/settings/OptionsScreenMixin.java | 4 +- .../gui/screen/LevelLoadingScreenMixin.java | 2 +- .../model/MultipartBakedModelMixin.java | 2 +- .../model/WeightedBakedModelMixin.java | 2 +- .../options/overlays/InGameHudMixin.java | 4 +- .../render_layers/LeavesBlockMixin.java | 4 +- .../render_layers/RenderLayersMixin.java | 4 +- .../options/weather/WorldRendererMixin.java | 4 +- .../features/render/entity/CuboidMixin.java | 6 +- .../render/entity/ModelPartMixin.java | 12 +-- .../entity/cull/EntityRendererMixin.java | 4 +- .../shadows/EntityRenderDispatcherMixin.java | 4 +- .../render/gui/font/GlyphRendererMixin.java | 4 +- .../gui/outlines/WorldRendererMixin.java | 4 +- .../render/immediate/DirectionMixin.java | 4 +- .../intrinsics/BufferBuilderMixin.java | 8 +- .../sorting/BufferBuilderMixin.java | 2 +- .../sorting/VertexSorterMixin.java | 4 +- .../matrix_stack/MatrixStackMixin.java | 2 +- .../matrix_stack/VertexConsumerMixin.java | 2 +- .../render/model/RenderLayersMixin.java | 2 +- .../model/block/BlockModelRendererMixin.java | 12 +-- .../render/model/item/ItemRendererMixin.java | 16 ++-- .../particle/BillboardParticleMixin.java | 2 +- .../world/clouds/WorldRendererMixin.java | 4 +- .../world/sky/BackgroundRendererMixin.java | 4 +- .../render/world/sky/ClientWorldMixin.java | 4 +- .../render/world/sky/WorldRendererMixin.java | 2 +- .../shader/uniform/ShaderProgramMixin.java | 2 +- .../textures/NativeImageAccessor.java | 2 +- .../textures/SpriteContentsInvoker.java | 2 +- .../tracking/BlockModelRendererMixin.java | 4 +- .../animations/tracking/DrawContextMixin.java | 4 +- .../tracking/SpriteAtlasTextureMixin.java | 4 +- .../SpriteBillboardParticleMixin.java | 4 +- .../SpriteContentsAnimationAccessor.java | 2 +- .../SpriteContentsAnimationFrameAccessor.java | 2 +- .../SpriteContentsAnimatorImplMixin.java | 6 +- .../tracking/SpriteContentsMixin.java | 4 +- .../upload/SpriteContentsAccessor.java | 2 +- .../SpriteContentsAnimationAccessor.java | 2 +- .../SpriteContentsAnimationFrameAccessor.java | 2 +- .../SpriteContentsAnimatorImplAccessor.java | 2 +- .../SpriteContentsInterpolationMixin.java | 6 +- .../textures/mipmaps/MipmapHelperMixin.java | 4 +- .../textures/mipmaps/SpriteContentsMixin.java | 6 +- .../features/world/biome/BiomeMixin.java | 4 +- .../world/storage/ClientChunkMapMixin.java | 2 +- .../context_creation/WindowMixin.java | 10 +-- .../event_loop/RenderSystemMixin.java | 2 +- src/main/resources/fabric.mod.json | 4 +- src/main/resources/sodium.mixins.json | 4 +- 425 files changed, 1244 insertions(+), 1244 deletions(-) delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/SodiumPreLaunch.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/util/EnumBit.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/console/message/MessageLevel.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/Control.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/ModelCuboidAccessor.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/light/LightMode.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/platform/windows/api/version/QueryResult.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/OutputWithIndexData.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/buffers/ChunkModelBuilder.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJob.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/vertex/format/ChunkMeshFormats.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/world/WorldRendererExtended.java rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/SodiumClientMod.java (87%) create mode 100644 src/main/java/net/caffeinemc/mods/sodium/client/SodiumPreLaunch.java rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/compatibility/checks/Configuration.java (92%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/compatibility/checks/EarlyDriverScanner.java (86%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/compatibility/checks/LateDriverScanner.java (92%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/compatibility/checks/ModuleScanner.java (93%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/compatibility/checks/ResourcePackScanner.java (97%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/compatibility/checks/SodiumResourcePackMetadata.java (94%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/compatibility/environment/GLContextInfo.java (89%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/compatibility/environment/probe/GraphicsAdapterInfo.java (56%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/compatibility/environment/probe/GraphicsAdapterProbe.java (98%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/compatibility/environment/probe/GraphicsAdapterVendor.java (88%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/compatibility/workarounds/Workarounds.java (90%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/compatibility/workarounds/nvidia/NvidiaDriverVersion.java (91%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/compatibility/workarounds/nvidia/NvidiaWorkarounds.java (87%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/data/config/MixinConfig.java (98%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/data/fingerprint/FingerprintMeasure.java (97%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/data/fingerprint/HashedFingerprint.java (93%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/GlObject.java (95%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/arena/GlBufferArena.java (97%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/arena/GlBufferSegment.java (97%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/arena/PendingBufferCopyCommand.java (85%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/arena/PendingUpload.java (86%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/arena/staging/FallbackStagingBuffer.java (76%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/arena/staging/MappedStagingBuffer.java (92%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/arena/staging/StagingBuffer.java (58%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/array/GlVertexArray.java (72%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/attribute/GlVertexAttribute.java (96%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/attribute/GlVertexAttributeBinding.java (88%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/attribute/GlVertexAttributeFormat.java (92%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/attribute/GlVertexFormat.java (98%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/buffer/GlBuffer.java (79%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/buffer/GlBufferMapFlags.java (86%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/buffer/GlBufferMapping.java (93%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/buffer/GlBufferStorageFlags.java (81%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/buffer/GlBufferTarget.java (94%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/buffer/GlBufferUsage.java (91%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/buffer/GlImmutableBuffer.java (73%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/buffer/GlMutableBuffer.java (89%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/device/CommandList.java (71%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/device/DrawCommandList.java (68%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/device/GLRenderDevice.java (95%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/device/MultiDrawBatch.java (97%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/device/RenderDevice.java (79%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/functions/BufferStorageFunctions.java (80%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/functions/DeviceFunctions.java (74%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/shader/GlProgram.java (92%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/shader/GlShader.java (92%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/shader/ShaderConstants.java (97%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/shader/ShaderLoader.java (96%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/shader/ShaderParser.java (97%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/shader/ShaderType.java (84%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/shader/ShaderWorkarounds.java (97%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/shader/uniform/GlUniform.java (75%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/shader/uniform/GlUniformBlock.java (73%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/shader/uniform/GlUniformFloat.java (84%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/shader/uniform/GlUniformFloat3v.java (88%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/shader/uniform/GlUniformFloat4v.java (86%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/shader/uniform/GlUniformInt.java (84%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/shader/uniform/GlUniformMatrix4f.java (90%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/state/GlStateTracker.java (86%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/sync/GlFence.java (95%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/tessellation/GlAbstractTessellation.java (87%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/tessellation/GlIndexType.java (89%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/tessellation/GlPrimitiveType.java (80%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/tessellation/GlTessellation.java (62%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/tessellation/GlVertexArrayTessellation.java (81%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/tessellation/TessellationBinding.java (68%) create mode 100644 src/main/java/net/caffeinemc/mods/sodium/client/gl/util/EnumBit.java rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/util/EnumBitField.java (94%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gl/util/VertexRange.java (56%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gui/SodiumGameOptionPages.java (96%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gui/SodiumGameOptions.java (94%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gui/SodiumOptionsGUI.java (94%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gui/console/Console.java (79%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gui/console/ConsoleHooks.java (83%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gui/console/ConsoleRenderer.java (97%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gui/console/ConsoleSink.java (62%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gui/console/message/Message.java (66%) create mode 100644 src/main/java/net/caffeinemc/mods/sodium/client/gui/console/message/MessageLevel.java rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gui/options/Option.java (68%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gui/options/OptionFlag.java (71%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gui/options/OptionGroup.java (94%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gui/options/OptionImpact.java (92%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gui/options/OptionImpl.java (93%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gui/options/OptionPage.java (93%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gui/options/TextProvider.java (67%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gui/options/binding/GenericBinding.java (90%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gui/options/binding/OptionBinding.java (63%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gui/options/binding/compat/VanillaBooleanOptionBinding.java (78%) create mode 100644 src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/Control.java rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gui/options/control/ControlElement.java (90%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gui/options/control/ControlValueFormatter.java (96%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gui/options/control/CyclingControl.java (94%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gui/options/control/SliderControl.java (97%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gui/options/control/TickBoxControl.java (93%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gui/options/storage/MinecraftOptionsStorage.java (81%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gui/options/storage/OptionStorage.java (54%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gui/options/storage/SodiumOptionsStorage.java (78%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gui/prompt/ScreenPrompt.java (93%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gui/prompt/ScreenPromptable.java (65%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gui/screen/ConfigCorruptedScreen.java (92%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gui/widgets/AbstractWidget.java (98%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/gui/widgets/FlatButtonWidget.java (97%) create mode 100644 src/main/java/net/caffeinemc/mods/sodium/client/model/ModelCuboidAccessor.java rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/model/color/ColorProvider.java (79%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/model/color/ColorProviderRegistry.java (95%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/model/color/DefaultColorProviders.java (89%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/model/color/interop/BlockColorsExtended.java (92%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/model/color/interop/ItemColorsExtended.java (75%) create mode 100644 src/main/java/net/caffeinemc/mods/sodium/client/model/light/LightMode.java rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/model/light/LightPipeline.java (81%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/model/light/LightPipelineProvider.java (69%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/model/light/data/ArrayLightDataCache.java (93%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/model/light/data/HashLightDataCache.java (93%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/model/light/data/LightDataAccess.java (99%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/model/light/data/QuadLightData.java (87%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/model/light/flat/FlatLightPipeline.java (84%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/model/light/smooth/AoCompletionFlags.java (86%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/model/light/smooth/AoFaceData.java (97%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/model/light/smooth/AoNeighborInfo.java (99%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/model/light/smooth/SmoothLightPipeline.java (96%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/model/quad/BakedQuadView.java (51%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/model/quad/ModelQuad.java (96%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/model/quad/ModelQuadView.java (95%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/model/quad/ModelQuadViewMutable.java (92%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/model/quad/blender/BlendedColorProvider.java (90%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/model/quad/properties/ModelQuadFacing.java (96%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/model/quad/properties/ModelQuadFlags.java (95%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/model/quad/properties/ModelQuadOrientation.java (95%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/model/quad/properties/ModelQuadWinding.java (82%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/platform/MessageBox.java (92%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/platform/unix/Libc.java (92%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/platform/windows/WindowsCommandLine.java (96%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/platform/windows/WindowsDriverStoreVersion.java (95%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/platform/windows/api/Kernel32.java (98%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/platform/windows/api/User32.java (82%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/platform/windows/api/msgbox/MsgBoxCallback.java (92%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/platform/windows/api/msgbox/MsgBoxCallbackI.java (92%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/platform/windows/api/msgbox/MsgBoxParamSw.java (97%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/platform/windows/api/version/LanguageCodePage.java (85%) create mode 100644 src/main/java/net/caffeinemc/mods/sodium/client/platform/windows/api/version/QueryResult.java rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/platform/windows/api/version/Version.java (95%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/platform/windows/api/version/VersionInfo.java (96%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/SodiumWorldRenderer.java (93%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/ChunkRenderMatrices.java (89%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/ChunkRenderer.java (73%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/ChunkUpdateType.java (89%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/DefaultChunkRenderer.java (85%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/LocalSectionIndex.java (96%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/NonStoringBuilderPool.java (92%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/RenderSection.java (94%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/RenderSectionFlags.java (81%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/RenderSectionManager.java (89%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/ShaderChunkRenderer.java (83%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/SharedQuadIndexBuffer.java (89%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/compile/BuilderTaskOutput.java (81%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/compile/ChunkBuildBuffers.java (75%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/compile/ChunkBuildContext.java (72%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java (76%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java (68%) create mode 100644 src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/OutputWithIndexData.java rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/compile/buffers/BakedChunkModelBuilder.java (75%) create mode 100644 src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/buffers/ChunkModelBuilder.java rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/compile/executor/ChunkBuilder.java (94%) create mode 100644 src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkJob.java rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/compile/executor/ChunkJobCollector.java (94%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/compile/executor/ChunkJobQueue.java (97%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/compile/executor/ChunkJobResult.java (93%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/compile/executor/ChunkJobTyped.java (84%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/compile/pipeline/BlockOcclusionCache.java (97%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderCache.java (78%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderContext.java (89%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java (82%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java (92%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java (82%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java (68%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderTask.java (85%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/data/BuiltSectionInfo.java (92%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/data/BuiltSectionMeshParts.java (69%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java (95%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/data/SectionRenderDataUnsafe.java (98%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/lists/ChunkRenderList.java (85%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/lists/ChunkRenderListIterable.java (78%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/lists/SortedRenderLists.java (88%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/lists/VisibleChunkCollector.java (85%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/map/ChunkStatus.java (78%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/map/ChunkTracker.java (98%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/map/ChunkTrackerHolder.java (80%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/map/ClientChunkEventListener.java (81%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/occlusion/GraphDirection.java (96%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/occlusion/GraphDirectionSet.java (84%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/occlusion/OcclusionCuller.java (96%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/occlusion/VisibilityEncoding.java (96%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/region/RenderRegion.java (90%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/region/RenderRegionManager.java (84%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/shader/ChunkFogMode.java (92%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/shader/ChunkShaderBindingPoints.java (82%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/shader/ChunkShaderFogComponent.java (88%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/shader/ChunkShaderInterface.java (87%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/shader/ChunkShaderOptions.java (73%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/shader/ChunkShaderTextureSlot.java (70%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/shader/ShaderBindingContext.java (52%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/terrain/DefaultTerrainRenderPasses.java (89%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/terrain/TerrainRenderPass.java (92%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/terrain/material/DefaultMaterials.java (85%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/terrain/material/Material.java (58%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/terrain/material/parameters/AlphaCutoffParameter.java (57%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/terrain/material/parameters/MaterialParameters.java (80%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/translucent_sorting/AlignableNormal.java (94%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/translucent_sorting/SortBehavior.java (96%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/translucent_sorting/SortType.java (94%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java (97%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java (95%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPBuildFailureException.java (63%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java (92%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPResult.java (69%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java (97%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java (82%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java (97%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerMultiPartitionBSPNode.java (98%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java (98%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafDoubleBSPNode.java (85%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafMultiBSPNode.java (81%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafSingleBSPNode.java (81%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/Partition.java (80%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/translucent_sorting/data/AnyOrderData.java (81%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java (80%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/translucent_sorting/data/CombinedCameraPos.java (67%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicData.java (71%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/translucent_sorting/data/MixedDirectionData.java (63%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/translucent_sorting/data/NoData.java (83%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/translucent_sorting/data/PresentTranslucentData.java (85%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/translucent_sorting/data/SplitDirectionData.java (75%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java (90%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/translucent_sorting/data/StaticTopoAcyclicData.java (75%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/translucent_sorting/data/TopoGraphSorting.java (97%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java (94%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/translucent_sorting/data/TranslucentData.java (87%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/translucent_sorting/trigger/CameraMovement.java (68%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/translucent_sorting/trigger/DirectTriggers.java (96%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/translucent_sorting/trigger/GFNITriggers.java (92%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/translucent_sorting/trigger/GeometryPlanes.java (94%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/translucent_sorting/trigger/Group.java (94%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalList.java (97%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalPlanes.java (94%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java (93%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/vertex/builder/ChunkMeshBufferBuilder.java (87%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/vertex/format/ChunkMeshAttribute.java (62%) create mode 100644 src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/format/ChunkMeshFormats.java rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/vertex/format/ChunkVertexEncoder.java (78%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/vertex/format/ChunkVertexType.java (76%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/chunk/vertex/format/impl/CompactChunkVertex.java (84%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/immediate/CloudRenderer.java (99%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/immediate/model/BakedModelEncoder.java (96%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/immediate/model/EntityRenderer.java (99%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/immediate/model/ModelCuboid.java (96%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/immediate/model/ModelPartData.java (82%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/texture/SpriteContentsExtended.java (72%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/texture/SpriteUtil.java (92%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/util/DeferredRenderTask.java (94%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/util/RenderAsserts.java (93%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/vertex/VertexConsumerTracker.java (88%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/vertex/VertexConsumerUtils.java (92%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/vertex/VertexFormatDescriptionImpl.java (95%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/vertex/VertexFormatRegistryImpl.java (96%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/vertex/buffer/ExtendedBufferBuilder.java (88%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/vertex/buffer/SodiumBufferBuilder.java (99%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/vertex/serializers/VertexSerializerRegistryImpl.java (96%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/vertex/serializers/generated/VertexSerializerFactory.java (99%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/viewport/CameraTransform.java (90%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/viewport/Viewport.java (92%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/viewport/ViewportProvider.java (56%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/viewport/frustum/Frustum.java (64%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/render/viewport/frustum/SimpleFrustum.java (87%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/util/BitwiseMath.java (88%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/util/Dim2i.java (91%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/util/DirectionUtil.java (94%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/util/FileUtil.java (93%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/util/FlawlessFrames.java (96%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/util/ListUtil.java (87%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/util/MathUtil.java (96%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/util/ModelQuadUtil.java (97%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/util/NativeBuffer.java (97%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/util/NativeImageHelper.java (82%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/util/TextureUtil.java (89%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/util/collections/BitArray.java (99%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/util/collections/DoubleBufferedQueue.java (97%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/util/collections/ReadQueue.java (63%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/util/collections/WriteQueue.java (71%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/util/color/BoxBlur.java (98%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/util/color/ColorSRGB.java (99%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/util/color/FastCubicSampler.java (98%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/util/iterator/ByteArrayIterator.java (92%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/util/iterator/ByteIterator.java (59%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/util/iterator/ReversibleByteArrayIterator.java (93%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/util/iterator/ReversibleObjectArrayIterator.java (94%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/util/sorting/AbstractSort.java (81%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/util/sorting/InsertionSort.java (91%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/util/sorting/MergeSort.java (98%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/util/sorting/RadixSort.java (97%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/util/sorting/VertexSorters.java (95%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/util/task/CancellationToken.java (63%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/world/BiomeSeedProvider.java (83%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/world/PaletteStorageExtended.java (75%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/world/ReadableContainerExtended.java (93%) create mode 100644 src/main/java/net/caffeinemc/mods/sodium/client/world/WorldRendererExtended.java rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/world/WorldSlice.java (96%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/world/biome/BiomeColorCache.java (94%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/world/biome/BiomeColorMaps.java (95%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/world/biome/BiomeColorSource.java (92%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/world/biome/BiomeColorView.java (68%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/world/biome/BiomeSlice.java (96%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/world/cloned/ChunkRenderContext.java (92%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/world/cloned/ClonedChunkSection.java (97%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/client/world/cloned/ClonedChunkSectionCache.java (97%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/MixinOption.java (97%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/SodiumMixinPlugin.java (93%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/core/MinecraftClientMixin.java (94%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/core/WindowMixin.java (81%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/core/gui/WorldLoadingStateMixin.java (95%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/core/model/colors/BlockColorsMixin.java (90%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/core/model/colors/ItemColorsMixin.java (89%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/core/model/quad/BakedQuadMixin.java (89%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/core/render/VertexFormatAccessor.java (84%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/core/render/frustum/FrustumMixin.java (70%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/core/render/immediate/consumer/BufferBuilderMixin.java (95%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/core/render/immediate/consumer/OutlineVertexConsumerMixin.java (97%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/core/render/immediate/consumer/OverlayVertexConsumerMixin.java (98%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/core/render/immediate/consumer/SpriteTexturedVertexConsumerMixin.java (97%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/core/render/immediate/consumer/VertexConsumerProviderImmediateMixin.java (84%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/core/render/immediate/consumer/VertexConsumersMixin.java (97%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/core/render/world/BufferBuilderStorageMixin.java (82%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/core/render/world/WorldRendererMixin.java (93%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/core/world/biome/ClientWorldMixin.java (92%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/core/world/chunk/EmptyPaletteStorageMixin.java (85%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/core/world/chunk/PackedIntegerArrayMixin.java (89%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/core/world/chunk/PalettedContainerMixin.java (91%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/core/world/map/ClientChunkManagerMixin.java (91%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/core/world/map/ClientPlayNetworkHandlerMixin.java (86%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/core/world/map/ClientWorldMixin.java (69%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/debug/checks/AbstractTextureMixin.java (86%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/debug/checks/AsyncTextureMixin.java (79%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/debug/checks/BufferRendererMixin.java (81%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/debug/checks/FramebufferMixin.java (87%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/debug/checks/GlStateManagerMixin.java (82%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/debug/checks/NativeImageBackedTextureMixin.java (82%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/debug/checks/NativeImageMixin.java (81%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/debug/checks/PlayerSkinTextureMixin.java (94%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/debug/checks/RenderSystemMixin.java (90%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/debug/checks/SpriteAtlasTextureMixin.java (81%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/debug/checks/SpriteContentsAnimatorImplMixin.java (82%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/debug/checks/TextureManagerMixin.java (87%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/debug/checks/VertexBufferMixin.java (83%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/debug/checks/VertexFormatMixin.java (82%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/debug/checks/WindowFramebufferMixin.java (81%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/gui/hooks/console/GameRendererMixin.java (92%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/gui/hooks/debug/DebugHudMixin.java (87%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/gui/hooks/settings/OptionsScreenMixin.java (85%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/gui/screen/LevelLoadingScreenMixin.java (98%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/model/MultipartBakedModelMixin.java (97%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/model/WeightedBakedModelMixin.java (96%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/options/overlays/InGameHudMixin.java (79%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/options/render_layers/LeavesBlockMixin.java (88%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/options/render_layers/RenderLayersMixin.java (89%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/options/weather/WorldRendererMixin.java (83%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/render/entity/CuboidMixin.java (86%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/render/entity/ModelPartMixin.java (89%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/render/entity/cull/EntityRendererMixin.java (89%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/render/entity/shadows/EntityRenderDispatcherMixin.java (97%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/render/gui/font/GlyphRendererMixin.java (95%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/render/gui/outlines/WorldRendererMixin.java (98%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/render/immediate/DirectionMixin.java (93%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/render/immediate/buffer_builder/intrinsics/BufferBuilderMixin.java (88%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/render/immediate/buffer_builder/sorting/BufferBuilderMixin.java (97%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/render/immediate/buffer_builder/sorting/VertexSorterMixin.java (74%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/render/immediate/matrix_stack/MatrixStackMixin.java (93%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/render/immediate/matrix_stack/VertexConsumerMixin.java (94%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/render/model/RenderLayersMixin.java (94%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/render/model/block/BlockModelRendererMixin.java (88%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/render/model/item/ItemRendererMixin.java (87%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/render/particle/BillboardParticleMixin.java (98%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/render/world/clouds/WorldRendererMixin.java (93%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/render/world/sky/BackgroundRendererMixin.java (89%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/render/world/sky/ClientWorldMixin.java (87%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/render/world/sky/WorldRendererMixin.java (97%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/shader/uniform/ShaderProgramMixin.java (97%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/textures/NativeImageAccessor.java (80%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/textures/SpriteContentsInvoker.java (86%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/textures/animations/tracking/BlockModelRendererMixin.java (89%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/textures/animations/tracking/DrawContextMixin.java (89%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/textures/animations/tracking/SpriteAtlasTextureMixin.java (82%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/textures/animations/tracking/SpriteBillboardParticleMixin.java (91%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsAnimationAccessor.java (81%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsAnimationFrameAccessor.java (78%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsAnimatorImplMixin.java (90%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsMixin.java (83%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAccessor.java (81%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAnimationAccessor.java (82%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAnimationFrameAccessor.java (80%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAnimatorImplAccessor.java (84%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsInterpolationMixin.java (94%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/textures/mipmaps/MipmapHelperMixin.java (97%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/textures/mipmaps/SpriteContentsMixin.java (96%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/world/biome/BiomeMixin.java (95%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/features/world/storage/ClientChunkMapMixin.java (96%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/workarounds/context_creation/WindowMixin.java (89%) rename src/main/java/{me/jellysquid => net/caffeinemc}/mods/sodium/mixin/workarounds/event_loop/RenderSystemMixin.java (90%) diff --git a/build.gradle.kts b/build.gradle.kts index 7ab3840a64..1df687e101 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -19,7 +19,7 @@ plugins { base { archivesName = "sodium-fabric" - group = "me.jellysquid.mods" + group = "net.caffeinemc.mods" version = createVersionString() } diff --git a/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/VertexFormatRegistry.java b/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/VertexFormatRegistry.java index 08389a510c..0ee2f42201 100644 --- a/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/VertexFormatRegistry.java +++ b/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/VertexFormatRegistry.java @@ -5,7 +5,7 @@ public interface VertexFormatRegistry { VertexFormatRegistry INSTANCE = DependencyInjection.load(VertexFormatRegistry.class, - "me.jellysquid.mods.sodium.client.render.vertex.VertexFormatRegistryImpl"); + "net.caffeinemc.mods.sodium.client.render.vertex.VertexFormatRegistryImpl"); static VertexFormatRegistry instance() { return INSTANCE; diff --git a/src/api/java/net/caffeinemc/mods/sodium/api/vertex/serializer/VertexSerializerRegistry.java b/src/api/java/net/caffeinemc/mods/sodium/api/vertex/serializer/VertexSerializerRegistry.java index ea8b503129..8aecabc7d9 100644 --- a/src/api/java/net/caffeinemc/mods/sodium/api/vertex/serializer/VertexSerializerRegistry.java +++ b/src/api/java/net/caffeinemc/mods/sodium/api/vertex/serializer/VertexSerializerRegistry.java @@ -5,7 +5,7 @@ public interface VertexSerializerRegistry { VertexSerializerRegistry INSTANCE = DependencyInjection.load(VertexSerializerRegistry.class, - "me.jellysquid.mods.sodium.client.render.vertex.serializers.VertexSerializerRegistryImpl"); + "net.caffeinemc.mods.sodium.client.render.vertex.serializers.VertexSerializerRegistryImpl"); static VertexSerializerRegistry instance() { return INSTANCE; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/SodiumPreLaunch.java b/src/main/java/me/jellysquid/mods/sodium/client/SodiumPreLaunch.java deleted file mode 100644 index 05865a8399..0000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/SodiumPreLaunch.java +++ /dev/null @@ -1,15 +0,0 @@ -package me.jellysquid.mods.sodium.client; - -import me.jellysquid.mods.sodium.client.compatibility.checks.EarlyDriverScanner; -import me.jellysquid.mods.sodium.client.compatibility.workarounds.Workarounds; -import me.jellysquid.mods.sodium.client.compatibility.environment.probe.GraphicsAdapterProbe; -import net.fabricmc.loader.api.entrypoint.PreLaunchEntrypoint; - -public class SodiumPreLaunch implements PreLaunchEntrypoint { - @Override - public void onPreLaunch() { - GraphicsAdapterProbe.findAdapters(); - EarlyDriverScanner.scanDrivers(); - Workarounds.init(); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/util/EnumBit.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/util/EnumBit.java deleted file mode 100644 index 4262177102..0000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/util/EnumBit.java +++ /dev/null @@ -1,5 +0,0 @@ -package me.jellysquid.mods.sodium.client.gl.util; - -public interface EnumBit { - int getBits(); -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/console/message/MessageLevel.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/console/message/MessageLevel.java deleted file mode 100644 index 23094be6f5..0000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/console/message/MessageLevel.java +++ /dev/null @@ -1,7 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.console.message; - -public enum MessageLevel { - INFO, - WARN, - SEVERE -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/Control.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/Control.java deleted file mode 100644 index 28931db824..0000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/Control.java +++ /dev/null @@ -1,12 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.options.control; - -import me.jellysquid.mods.sodium.client.gui.options.Option; -import me.jellysquid.mods.sodium.client.util.Dim2i; - -public interface Control { - Option getOption(); - - ControlElement createElement(Dim2i dim); - - int getMaxWidth(); -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/ModelCuboidAccessor.java b/src/main/java/me/jellysquid/mods/sodium/client/model/ModelCuboidAccessor.java deleted file mode 100644 index a868205f7a..0000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/ModelCuboidAccessor.java +++ /dev/null @@ -1,7 +0,0 @@ -package me.jellysquid.mods.sodium.client.model; - -import me.jellysquid.mods.sodium.client.render.immediate.model.ModelCuboid; - -public interface ModelCuboidAccessor { - ModelCuboid sodium$copy(); -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/LightMode.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/LightMode.java deleted file mode 100644 index 90133268cd..0000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/LightMode.java +++ /dev/null @@ -1,6 +0,0 @@ -package me.jellysquid.mods.sodium.client.model.light; - -public enum LightMode { - SMOOTH, - FLAT -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/platform/windows/api/version/QueryResult.java b/src/main/java/me/jellysquid/mods/sodium/client/platform/windows/api/version/QueryResult.java deleted file mode 100644 index ffe9ad84f9..0000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/platform/windows/api/version/QueryResult.java +++ /dev/null @@ -1,4 +0,0 @@ -package me.jellysquid.mods.sodium.client.platform.windows.api.version; - -public record QueryResult(long address, int length) { -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/OutputWithIndexData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/OutputWithIndexData.java deleted file mode 100644 index a650fa3b92..0000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/OutputWithIndexData.java +++ /dev/null @@ -1,7 +0,0 @@ -package me.jellysquid.mods.sodium.client.render.chunk.compile; - -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.PresentTranslucentData; - -public interface OutputWithIndexData { - PresentTranslucentData getTranslucentData(); -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/buffers/ChunkModelBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/buffers/ChunkModelBuilder.java deleted file mode 100644 index ce36d0e6fd..0000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/buffers/ChunkModelBuilder.java +++ /dev/null @@ -1,11 +0,0 @@ -package me.jellysquid.mods.sodium.client.render.chunk.compile.buffers; - -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; -import me.jellysquid.mods.sodium.client.render.chunk.vertex.builder.ChunkMeshBufferBuilder; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; - -public interface ChunkModelBuilder { - ChunkMeshBufferBuilder getVertexBuffer(ModelQuadFacing facing); - - void addSprite(TextureAtlasSprite sprite); -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJob.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJob.java deleted file mode 100644 index be2852bd74..0000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJob.java +++ /dev/null @@ -1,12 +0,0 @@ -package me.jellysquid.mods.sodium.client.render.chunk.compile.executor; - -import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildContext; -import me.jellysquid.mods.sodium.client.util.task.CancellationToken; - -public interface ChunkJob extends CancellationToken { - void execute(ChunkBuildContext context); - - boolean isStarted(); - - int getEffort(); -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/vertex/format/ChunkMeshFormats.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/vertex/format/ChunkMeshFormats.java deleted file mode 100644 index fb6269fcbd..0000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/vertex/format/ChunkMeshFormats.java +++ /dev/null @@ -1,7 +0,0 @@ -package me.jellysquid.mods.sodium.client.render.chunk.vertex.format; - -import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.impl.CompactChunkVertex; - -public class ChunkMeshFormats { - public static final ChunkVertexType COMPACT = new CompactChunkVertex(); -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldRendererExtended.java b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldRendererExtended.java deleted file mode 100644 index f360f5a8f8..0000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldRendererExtended.java +++ /dev/null @@ -1,7 +0,0 @@ -package me.jellysquid.mods.sodium.client.world; - -import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; - -public interface WorldRendererExtended { - SodiumWorldRenderer sodium$getWorldRenderer(); -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java b/src/main/java/net/caffeinemc/mods/sodium/client/SodiumClientMod.java similarity index 87% rename from src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java rename to src/main/java/net/caffeinemc/mods/sodium/client/SodiumClientMod.java index 578e838310..e794c36581 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/SodiumClientMod.java @@ -1,11 +1,11 @@ -package me.jellysquid.mods.sodium.client; - -import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions; -import me.jellysquid.mods.sodium.client.data.fingerprint.FingerprintMeasure; -import me.jellysquid.mods.sodium.client.data.fingerprint.HashedFingerprint; -import me.jellysquid.mods.sodium.client.gui.console.Console; -import me.jellysquid.mods.sodium.client.gui.console.message.MessageLevel; -import me.jellysquid.mods.sodium.client.util.FlawlessFrames; +package net.caffeinemc.mods.sodium.client; + +import net.caffeinemc.mods.sodium.client.gui.SodiumGameOptions; +import net.caffeinemc.mods.sodium.client.data.fingerprint.FingerprintMeasure; +import net.caffeinemc.mods.sodium.client.data.fingerprint.HashedFingerprint; +import net.caffeinemc.mods.sodium.client.gui.console.Console; +import net.caffeinemc.mods.sodium.client.gui.console.message.MessageLevel; +import net.caffeinemc.mods.sodium.client.util.FlawlessFrames; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.ModContainer; diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/SodiumPreLaunch.java b/src/main/java/net/caffeinemc/mods/sodium/client/SodiumPreLaunch.java new file mode 100644 index 0000000000..eccfa527c6 --- /dev/null +++ b/src/main/java/net/caffeinemc/mods/sodium/client/SodiumPreLaunch.java @@ -0,0 +1,15 @@ +package net.caffeinemc.mods.sodium.client; + +import net.caffeinemc.mods.sodium.client.compatibility.checks.EarlyDriverScanner; +import net.caffeinemc.mods.sodium.client.compatibility.workarounds.Workarounds; +import net.caffeinemc.mods.sodium.client.compatibility.environment.probe.GraphicsAdapterProbe; +import net.fabricmc.loader.api.entrypoint.PreLaunchEntrypoint; + +public class SodiumPreLaunch implements PreLaunchEntrypoint { + @Override + public void onPreLaunch() { + GraphicsAdapterProbe.findAdapters(); + EarlyDriverScanner.scanDrivers(); + Workarounds.init(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/checks/Configuration.java b/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/checks/Configuration.java similarity index 92% rename from src/main/java/me/jellysquid/mods/sodium/client/compatibility/checks/Configuration.java rename to src/main/java/net/caffeinemc/mods/sodium/client/compatibility/checks/Configuration.java index 17dfcb9ff1..54250890a1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/checks/Configuration.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/checks/Configuration.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.compatibility.checks; +package net.caffeinemc.mods.sodium.client.compatibility.checks; /** * "Checks" are used to determine whether the environment we are running within is actually reasonable. Most often, diff --git a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/checks/EarlyDriverScanner.java b/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/checks/EarlyDriverScanner.java similarity index 86% rename from src/main/java/me/jellysquid/mods/sodium/client/compatibility/checks/EarlyDriverScanner.java rename to src/main/java/net/caffeinemc/mods/sodium/client/compatibility/checks/EarlyDriverScanner.java index 638298190c..96b0be563d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/checks/EarlyDriverScanner.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/checks/EarlyDriverScanner.java @@ -1,11 +1,11 @@ -package me.jellysquid.mods.sodium.client.compatibility.checks; +package net.caffeinemc.mods.sodium.client.compatibility.checks; -import me.jellysquid.mods.sodium.client.platform.MessageBox; -import me.jellysquid.mods.sodium.client.platform.windows.WindowsDriverStoreVersion; +import net.caffeinemc.mods.sodium.client.platform.MessageBox; +import net.caffeinemc.mods.sodium.client.platform.windows.WindowsDriverStoreVersion; import net.minecraft.Util; -import me.jellysquid.mods.sodium.client.compatibility.environment.probe.GraphicsAdapterInfo; -import me.jellysquid.mods.sodium.client.compatibility.environment.probe.GraphicsAdapterProbe; -import me.jellysquid.mods.sodium.client.compatibility.environment.probe.GraphicsAdapterVendor; +import net.caffeinemc.mods.sodium.client.compatibility.environment.probe.GraphicsAdapterInfo; +import net.caffeinemc.mods.sodium.client.compatibility.environment.probe.GraphicsAdapterProbe; +import net.caffeinemc.mods.sodium.client.compatibility.environment.probe.GraphicsAdapterVendor; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/checks/LateDriverScanner.java b/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/checks/LateDriverScanner.java similarity index 92% rename from src/main/java/me/jellysquid/mods/sodium/client/compatibility/checks/LateDriverScanner.java rename to src/main/java/net/caffeinemc/mods/sodium/client/compatibility/checks/LateDriverScanner.java index 23f11ee9b5..cf1a2bd658 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/checks/LateDriverScanner.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/checks/LateDriverScanner.java @@ -1,11 +1,11 @@ -package me.jellysquid.mods.sodium.client.compatibility.checks; +package net.caffeinemc.mods.sodium.client.compatibility.checks; -import me.jellysquid.mods.sodium.client.compatibility.workarounds.nvidia.NvidiaDriverVersion; -import me.jellysquid.mods.sodium.client.gui.console.Console; -import me.jellysquid.mods.sodium.client.gui.console.message.MessageLevel; +import net.caffeinemc.mods.sodium.client.compatibility.workarounds.nvidia.NvidiaDriverVersion; +import net.caffeinemc.mods.sodium.client.gui.console.Console; +import net.caffeinemc.mods.sodium.client.gui.console.message.MessageLevel; import net.minecraft.Util; import net.minecraft.network.chat.Component; -import me.jellysquid.mods.sodium.client.compatibility.environment.GLContextInfo; +import net.caffeinemc.mods.sodium.client.compatibility.environment.GLContextInfo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/checks/ModuleScanner.java b/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/checks/ModuleScanner.java similarity index 93% rename from src/main/java/me/jellysquid/mods/sodium/client/compatibility/checks/ModuleScanner.java rename to src/main/java/net/caffeinemc/mods/sodium/client/compatibility/checks/ModuleScanner.java index d07d56bfc9..bae157b3fa 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/checks/ModuleScanner.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/checks/ModuleScanner.java @@ -1,10 +1,10 @@ -package me.jellysquid.mods.sodium.client.compatibility.checks; +package net.caffeinemc.mods.sodium.client.compatibility.checks; -import me.jellysquid.mods.sodium.client.platform.MessageBox; -import me.jellysquid.mods.sodium.client.platform.windows.api.Kernel32; -import me.jellysquid.mods.sodium.client.platform.windows.api.version.LanguageCodePage; -import me.jellysquid.mods.sodium.client.platform.windows.api.version.Version; -import me.jellysquid.mods.sodium.client.platform.windows.api.version.VersionInfo; +import net.caffeinemc.mods.sodium.client.platform.MessageBox; +import net.caffeinemc.mods.sodium.client.platform.windows.api.Kernel32; +import net.caffeinemc.mods.sodium.client.platform.windows.api.version.LanguageCodePage; +import net.caffeinemc.mods.sodium.client.platform.windows.api.version.Version; +import net.caffeinemc.mods.sodium.client.platform.windows.api.version.VersionInfo; import net.minecraft.client.Minecraft; import net.minecraft.util.NativeModuleLister; import net.minecraft.util.NativeModuleLister.NativeModuleInfo; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/checks/ResourcePackScanner.java b/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/checks/ResourcePackScanner.java similarity index 97% rename from src/main/java/me/jellysquid/mods/sodium/client/compatibility/checks/ResourcePackScanner.java rename to src/main/java/net/caffeinemc/mods/sodium/client/compatibility/checks/ResourcePackScanner.java index ce48b6d78f..35dd4248c2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/checks/ResourcePackScanner.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/checks/ResourcePackScanner.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.client.compatibility.checks; +package net.caffeinemc.mods.sodium.client.compatibility.checks; -import me.jellysquid.mods.sodium.client.gui.console.Console; -import me.jellysquid.mods.sodium.client.gui.console.message.MessageLevel; +import net.caffeinemc.mods.sodium.client.gui.console.Console; +import net.caffeinemc.mods.sodium.client.gui.console.message.MessageLevel; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; import net.minecraft.resources.ResourceLocation; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/checks/SodiumResourcePackMetadata.java b/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/checks/SodiumResourcePackMetadata.java similarity index 94% rename from src/main/java/me/jellysquid/mods/sodium/client/compatibility/checks/SodiumResourcePackMetadata.java rename to src/main/java/net/caffeinemc/mods/sodium/client/compatibility/checks/SodiumResourcePackMetadata.java index c10d20520a..213b93e7ac 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/checks/SodiumResourcePackMetadata.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/checks/SodiumResourcePackMetadata.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.compatibility.checks; +package net.caffeinemc.mods.sodium.client.compatibility.checks; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/environment/GLContextInfo.java b/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/environment/GLContextInfo.java similarity index 89% rename from src/main/java/me/jellysquid/mods/sodium/client/compatibility/environment/GLContextInfo.java rename to src/main/java/net/caffeinemc/mods/sodium/client/compatibility/environment/GLContextInfo.java index a4d6c36d41..fb54c1647a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/environment/GLContextInfo.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/environment/GLContextInfo.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.compatibility.environment; +package net.caffeinemc.mods.sodium.client.compatibility.environment; import org.jetbrains.annotations.Nullable; import org.lwjgl.opengl.GL11C; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/environment/probe/GraphicsAdapterInfo.java b/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/environment/probe/GraphicsAdapterInfo.java similarity index 56% rename from src/main/java/me/jellysquid/mods/sodium/client/compatibility/environment/probe/GraphicsAdapterInfo.java rename to src/main/java/net/caffeinemc/mods/sodium/client/compatibility/environment/probe/GraphicsAdapterInfo.java index 6351fd349c..51e459429d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/environment/probe/GraphicsAdapterInfo.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/environment/probe/GraphicsAdapterInfo.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.compatibility.environment.probe; +package net.caffeinemc.mods.sodium.client.compatibility.environment.probe; public record GraphicsAdapterInfo(GraphicsAdapterVendor vendor, String name, String version) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/environment/probe/GraphicsAdapterProbe.java b/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/environment/probe/GraphicsAdapterProbe.java similarity index 98% rename from src/main/java/me/jellysquid/mods/sodium/client/compatibility/environment/probe/GraphicsAdapterProbe.java rename to src/main/java/net/caffeinemc/mods/sodium/client/compatibility/environment/probe/GraphicsAdapterProbe.java index 39d2f97db2..61129b59bc 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/environment/probe/GraphicsAdapterProbe.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/environment/probe/GraphicsAdapterProbe.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.compatibility.environment.probe; +package net.caffeinemc.mods.sodium.client.compatibility.environment.probe; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/environment/probe/GraphicsAdapterVendor.java b/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/environment/probe/GraphicsAdapterVendor.java similarity index 88% rename from src/main/java/me/jellysquid/mods/sodium/client/compatibility/environment/probe/GraphicsAdapterVendor.java rename to src/main/java/net/caffeinemc/mods/sodium/client/compatibility/environment/probe/GraphicsAdapterVendor.java index 61a40fd68c..1f55a93aa8 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/environment/probe/GraphicsAdapterVendor.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/environment/probe/GraphicsAdapterVendor.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.compatibility.environment.probe; +package net.caffeinemc.mods.sodium.client.compatibility.environment.probe; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/workarounds/Workarounds.java b/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/workarounds/Workarounds.java similarity index 90% rename from src/main/java/me/jellysquid/mods/sodium/client/compatibility/workarounds/Workarounds.java rename to src/main/java/net/caffeinemc/mods/sodium/client/compatibility/workarounds/Workarounds.java index 643b337664..a1010bbf32 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/workarounds/Workarounds.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/workarounds/Workarounds.java @@ -1,8 +1,8 @@ -package me.jellysquid.mods.sodium.client.compatibility.workarounds; +package net.caffeinemc.mods.sodium.client.compatibility.workarounds; -import me.jellysquid.mods.sodium.client.compatibility.environment.probe.GraphicsAdapterInfo; -import me.jellysquid.mods.sodium.client.compatibility.environment.probe.GraphicsAdapterProbe; -import me.jellysquid.mods.sodium.client.compatibility.environment.probe.GraphicsAdapterVendor; +import net.caffeinemc.mods.sodium.client.compatibility.environment.probe.GraphicsAdapterInfo; +import net.caffeinemc.mods.sodium.client.compatibility.environment.probe.GraphicsAdapterProbe; +import net.caffeinemc.mods.sodium.client.compatibility.environment.probe.GraphicsAdapterVendor; import net.minecraft.Util; import net.minecraft.Util.OS; import org.slf4j.Logger; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/workarounds/nvidia/NvidiaDriverVersion.java b/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/workarounds/nvidia/NvidiaDriverVersion.java similarity index 91% rename from src/main/java/me/jellysquid/mods/sodium/client/compatibility/workarounds/nvidia/NvidiaDriverVersion.java rename to src/main/java/net/caffeinemc/mods/sodium/client/compatibility/workarounds/nvidia/NvidiaDriverVersion.java index ff2c05e95b..54ba821f82 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/workarounds/nvidia/NvidiaDriverVersion.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/workarounds/nvidia/NvidiaDriverVersion.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.client.compatibility.workarounds.nvidia; +package net.caffeinemc.mods.sodium.client.compatibility.workarounds.nvidia; -import me.jellysquid.mods.sodium.client.compatibility.environment.GLContextInfo; +import net.caffeinemc.mods.sodium.client.compatibility.environment.GLContextInfo; import org.apache.commons.lang3.Validate; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/workarounds/nvidia/NvidiaWorkarounds.java b/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/workarounds/nvidia/NvidiaWorkarounds.java similarity index 87% rename from src/main/java/me/jellysquid/mods/sodium/client/compatibility/workarounds/nvidia/NvidiaWorkarounds.java rename to src/main/java/net/caffeinemc/mods/sodium/client/compatibility/workarounds/nvidia/NvidiaWorkarounds.java index 1e25ae2eb7..9445a5af7a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/compatibility/workarounds/nvidia/NvidiaWorkarounds.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/workarounds/nvidia/NvidiaWorkarounds.java @@ -1,9 +1,9 @@ -package me.jellysquid.mods.sodium.client.compatibility.workarounds.nvidia; +package net.caffeinemc.mods.sodium.client.compatibility.workarounds.nvidia; -import me.jellysquid.mods.sodium.client.platform.unix.Libc; -import me.jellysquid.mods.sodium.client.platform.windows.api.Kernel32; +import net.caffeinemc.mods.sodium.client.platform.unix.Libc; +import net.caffeinemc.mods.sodium.client.platform.windows.api.Kernel32; import net.minecraft.Util; -import me.jellysquid.mods.sodium.client.platform.windows.WindowsCommandLine; +import net.caffeinemc.mods.sodium.client.platform.windows.WindowsCommandLine; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/data/config/MixinConfig.java b/src/main/java/net/caffeinemc/mods/sodium/client/data/config/MixinConfig.java similarity index 98% rename from src/main/java/me/jellysquid/mods/sodium/client/data/config/MixinConfig.java rename to src/main/java/net/caffeinemc/mods/sodium/client/data/config/MixinConfig.java index c7bb953892..86a92caa4b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/data/config/MixinConfig.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/data/config/MixinConfig.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.client.data.config; +package net.caffeinemc.mods.sodium.client.data.config; -import me.jellysquid.mods.sodium.mixin.MixinOption; +import net.caffeinemc.mods.sodium.mixin.MixinOption; import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.ModContainer; import net.fabricmc.loader.api.metadata.CustomValue; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/data/fingerprint/FingerprintMeasure.java b/src/main/java/net/caffeinemc/mods/sodium/client/data/fingerprint/FingerprintMeasure.java similarity index 97% rename from src/main/java/me/jellysquid/mods/sodium/client/data/fingerprint/FingerprintMeasure.java rename to src/main/java/net/caffeinemc/mods/sodium/client/data/fingerprint/FingerprintMeasure.java index ff4705ad6f..e5b429302a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/data/fingerprint/FingerprintMeasure.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/data/fingerprint/FingerprintMeasure.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.data.fingerprint; +package net.caffeinemc.mods.sodium.client.data.fingerprint; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.client.Minecraft; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/data/fingerprint/HashedFingerprint.java b/src/main/java/net/caffeinemc/mods/sodium/client/data/fingerprint/HashedFingerprint.java similarity index 93% rename from src/main/java/me/jellysquid/mods/sodium/client/data/fingerprint/HashedFingerprint.java rename to src/main/java/net/caffeinemc/mods/sodium/client/data/fingerprint/HashedFingerprint.java index e1d4326571..eda5bc8c61 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/data/fingerprint/HashedFingerprint.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/data/fingerprint/HashedFingerprint.java @@ -1,8 +1,8 @@ -package me.jellysquid.mods.sodium.client.data.fingerprint; +package net.caffeinemc.mods.sodium.client.data.fingerprint; import com.google.gson.Gson; import com.google.gson.annotations.SerializedName; -import me.jellysquid.mods.sodium.client.util.FileUtil; +import net.caffeinemc.mods.sodium.client.util.FileUtil; import net.fabricmc.loader.api.FabricLoader; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/GlObject.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/GlObject.java similarity index 95% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/GlObject.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/GlObject.java index 09455bb76f..89bb9d487e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/GlObject.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/GlObject.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.gl; +package net.caffeinemc.mods.sodium.client.gl; /** * An abstract object used to represent objects in OpenGL code safely. This class hides the direct handle to a OpenGL diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/arena/GlBufferArena.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/GlBufferArena.java similarity index 97% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/arena/GlBufferArena.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/GlBufferArena.java index f82c4db7df..f26cf032ce 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/arena/GlBufferArena.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/GlBufferArena.java @@ -1,10 +1,10 @@ -package me.jellysquid.mods.sodium.client.gl.arena; +package net.caffeinemc.mods.sodium.client.gl.arena; -import me.jellysquid.mods.sodium.client.gl.arena.staging.StagingBuffer; -import me.jellysquid.mods.sodium.client.gl.buffer.GlBuffer; -import me.jellysquid.mods.sodium.client.gl.buffer.GlBufferUsage; -import me.jellysquid.mods.sodium.client.gl.buffer.GlMutableBuffer; -import me.jellysquid.mods.sodium.client.gl.device.CommandList; +import net.caffeinemc.mods.sodium.client.gl.arena.staging.StagingBuffer; +import net.caffeinemc.mods.sodium.client.gl.buffer.GlBuffer; +import net.caffeinemc.mods.sodium.client.gl.buffer.GlBufferUsage; +import net.caffeinemc.mods.sodium.client.gl.buffer.GlMutableBuffer; +import net.caffeinemc.mods.sodium.client.gl.device.CommandList; import java.nio.ByteBuffer; import java.util.ArrayList; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/arena/GlBufferSegment.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/GlBufferSegment.java similarity index 97% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/arena/GlBufferSegment.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/GlBufferSegment.java index 564039dfe6..480727ee92 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/arena/GlBufferSegment.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/GlBufferSegment.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.gl.arena; +package net.caffeinemc.mods.sodium.client.gl.arena; public class GlBufferSegment { private final GlBufferArena arena; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/arena/PendingBufferCopyCommand.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/PendingBufferCopyCommand.java similarity index 85% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/arena/PendingBufferCopyCommand.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/PendingBufferCopyCommand.java index e5a090ef16..e7be6b80fb 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/arena/PendingBufferCopyCommand.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/PendingBufferCopyCommand.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.gl.arena; +package net.caffeinemc.mods.sodium.client.gl.arena; class PendingBufferCopyCommand { public final int readOffset; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/arena/PendingUpload.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/PendingUpload.java similarity index 86% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/arena/PendingUpload.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/PendingUpload.java index 38bb8da6b9..2da0227f3f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/arena/PendingUpload.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/PendingUpload.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.client.gl.arena; +package net.caffeinemc.mods.sodium.client.gl.arena; -import me.jellysquid.mods.sodium.client.util.NativeBuffer; +import net.caffeinemc.mods.sodium.client.util.NativeBuffer; public class PendingUpload { private final NativeBuffer data; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/arena/staging/FallbackStagingBuffer.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/staging/FallbackStagingBuffer.java similarity index 76% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/arena/staging/FallbackStagingBuffer.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/staging/FallbackStagingBuffer.java index 7df5902219..cfe9aae5a8 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/arena/staging/FallbackStagingBuffer.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/staging/FallbackStagingBuffer.java @@ -1,9 +1,9 @@ -package me.jellysquid.mods.sodium.client.gl.arena.staging; +package net.caffeinemc.mods.sodium.client.gl.arena.staging; -import me.jellysquid.mods.sodium.client.gl.buffer.GlBuffer; -import me.jellysquid.mods.sodium.client.gl.buffer.GlBufferUsage; -import me.jellysquid.mods.sodium.client.gl.buffer.GlMutableBuffer; -import me.jellysquid.mods.sodium.client.gl.device.CommandList; +import net.caffeinemc.mods.sodium.client.gl.buffer.GlBuffer; +import net.caffeinemc.mods.sodium.client.gl.buffer.GlBufferUsage; +import net.caffeinemc.mods.sodium.client.gl.buffer.GlMutableBuffer; +import net.caffeinemc.mods.sodium.client.gl.device.CommandList; import java.nio.ByteBuffer; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/arena/staging/MappedStagingBuffer.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/staging/MappedStagingBuffer.java similarity index 92% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/arena/staging/MappedStagingBuffer.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/staging/MappedStagingBuffer.java index db6f44ce12..aec2840186 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/arena/staging/MappedStagingBuffer.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/staging/MappedStagingBuffer.java @@ -1,14 +1,14 @@ -package me.jellysquid.mods.sodium.client.gl.arena.staging; +package net.caffeinemc.mods.sodium.client.gl.arena.staging; import it.unimi.dsi.fastutil.PriorityQueue; import it.unimi.dsi.fastutil.objects.ObjectArrayFIFOQueue; -import me.jellysquid.mods.sodium.client.gl.buffer.*; -import me.jellysquid.mods.sodium.client.gl.device.CommandList; -import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; -import me.jellysquid.mods.sodium.client.gl.functions.BufferStorageFunctions; -import me.jellysquid.mods.sodium.client.gl.sync.GlFence; -import me.jellysquid.mods.sodium.client.gl.util.EnumBitField; -import me.jellysquid.mods.sodium.client.util.MathUtil; +import net.caffeinemc.mods.sodium.client.gl.buffer.*; +import net.caffeinemc.mods.sodium.client.gl.device.CommandList; +import net.caffeinemc.mods.sodium.client.gl.device.RenderDevice; +import net.caffeinemc.mods.sodium.client.gl.functions.BufferStorageFunctions; +import net.caffeinemc.mods.sodium.client.gl.sync.GlFence; +import net.caffeinemc.mods.sodium.client.gl.util.EnumBitField; +import net.caffeinemc.mods.sodium.client.util.MathUtil; import java.nio.ByteBuffer; import java.util.ArrayList; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/arena/staging/StagingBuffer.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/staging/StagingBuffer.java similarity index 58% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/arena/staging/StagingBuffer.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/staging/StagingBuffer.java index 82252ec5e2..d3087e8df5 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/arena/staging/StagingBuffer.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/staging/StagingBuffer.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.client.gl.arena.staging; +package net.caffeinemc.mods.sodium.client.gl.arena.staging; -import me.jellysquid.mods.sodium.client.gl.buffer.GlBuffer; -import me.jellysquid.mods.sodium.client.gl.device.CommandList; +import net.caffeinemc.mods.sodium.client.gl.buffer.GlBuffer; +import net.caffeinemc.mods.sodium.client.gl.device.CommandList; import java.nio.ByteBuffer; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/array/GlVertexArray.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/array/GlVertexArray.java similarity index 72% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/array/GlVertexArray.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/array/GlVertexArray.java index 04f4cb9af8..b4e68999a3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/array/GlVertexArray.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/array/GlVertexArray.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.client.gl.array; +package net.caffeinemc.mods.sodium.client.gl.array; -import me.jellysquid.mods.sodium.client.gl.GlObject; +import net.caffeinemc.mods.sodium.client.gl.GlObject; import org.lwjgl.opengl.GL30C; /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/GlVertexAttribute.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/attribute/GlVertexAttribute.java similarity index 96% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/GlVertexAttribute.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/attribute/GlVertexAttribute.java index c48ae715ed..cf9c53282f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/GlVertexAttribute.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/attribute/GlVertexAttribute.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.gl.attribute; +package net.caffeinemc.mods.sodium.client.gl.attribute; public class GlVertexAttribute { private final int format; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/GlVertexAttributeBinding.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/attribute/GlVertexAttributeBinding.java similarity index 88% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/GlVertexAttributeBinding.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/attribute/GlVertexAttributeBinding.java index 920adf5e27..6762ccc2ee 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/GlVertexAttributeBinding.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/attribute/GlVertexAttributeBinding.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.gl.attribute; +package net.caffeinemc.mods.sodium.client.gl.attribute; public class GlVertexAttributeBinding extends GlVertexAttribute { private final int index; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/GlVertexAttributeFormat.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/attribute/GlVertexAttributeFormat.java similarity index 92% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/GlVertexAttributeFormat.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/attribute/GlVertexAttributeFormat.java index e1bb381fa8..c54921e824 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/GlVertexAttributeFormat.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/attribute/GlVertexAttributeFormat.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.gl.attribute; +package net.caffeinemc.mods.sodium.client.gl.attribute; import org.lwjgl.opengl.GL20C; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/GlVertexFormat.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/attribute/GlVertexFormat.java similarity index 98% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/GlVertexFormat.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/attribute/GlVertexFormat.java index 4e4effe71d..aee75108d0 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/GlVertexFormat.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/attribute/GlVertexFormat.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.gl.attribute; +package net.caffeinemc.mods.sodium.client.gl.attribute; import java.util.EnumMap; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBuffer.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBuffer.java similarity index 79% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBuffer.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBuffer.java index 8c18c122a0..3749194c96 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBuffer.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBuffer.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.client.gl.buffer; +package net.caffeinemc.mods.sodium.client.gl.buffer; -import me.jellysquid.mods.sodium.client.gl.GlObject; +import net.caffeinemc.mods.sodium.client.gl.GlObject; import org.lwjgl.opengl.GL20C; public abstract class GlBuffer extends GlObject { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBufferMapFlags.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBufferMapFlags.java similarity index 86% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBufferMapFlags.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBufferMapFlags.java index d93f45a1b0..34ceff6ff0 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBufferMapFlags.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBufferMapFlags.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.client.gl.buffer; +package net.caffeinemc.mods.sodium.client.gl.buffer; -import me.jellysquid.mods.sodium.client.gl.util.EnumBit; +import net.caffeinemc.mods.sodium.client.gl.util.EnumBit; import org.lwjgl.opengl.GL30C; import org.lwjgl.opengl.GL33C; import org.lwjgl.opengl.GL44C; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBufferMapping.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBufferMapping.java similarity index 93% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBufferMapping.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBufferMapping.java index f7288f8ab7..ca54f8fa46 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBufferMapping.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBufferMapping.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.gl.buffer; +package net.caffeinemc.mods.sodium.client.gl.buffer; import org.lwjgl.system.MemoryUtil; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBufferStorageFlags.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBufferStorageFlags.java similarity index 81% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBufferStorageFlags.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBufferStorageFlags.java index 403d9eeb72..c473e802c3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBufferStorageFlags.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBufferStorageFlags.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.client.gl.buffer; +package net.caffeinemc.mods.sodium.client.gl.buffer; -import me.jellysquid.mods.sodium.client.gl.util.EnumBit; +import net.caffeinemc.mods.sodium.client.gl.util.EnumBit; import org.lwjgl.opengl.GL30C; import org.lwjgl.opengl.GL44C; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBufferTarget.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBufferTarget.java similarity index 94% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBufferTarget.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBufferTarget.java index 522128d970..0b4dc2909b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBufferTarget.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBufferTarget.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.gl.buffer; +package net.caffeinemc.mods.sodium.client.gl.buffer; import org.lwjgl.opengl.GL20C; import org.lwjgl.opengl.GL31C; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBufferUsage.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBufferUsage.java similarity index 91% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBufferUsage.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBufferUsage.java index f86345065f..56666453d6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBufferUsage.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBufferUsage.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.gl.buffer; +package net.caffeinemc.mods.sodium.client.gl.buffer; import org.lwjgl.opengl.GL20C; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlImmutableBuffer.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlImmutableBuffer.java similarity index 73% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlImmutableBuffer.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlImmutableBuffer.java index 3d0ff747f8..e816103300 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlImmutableBuffer.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlImmutableBuffer.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.client.gl.buffer; +package net.caffeinemc.mods.sodium.client.gl.buffer; -import me.jellysquid.mods.sodium.client.gl.util.EnumBitField; +import net.caffeinemc.mods.sodium.client.gl.util.EnumBitField; public class GlImmutableBuffer extends GlBuffer { private final EnumBitField flags; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlMutableBuffer.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlMutableBuffer.java similarity index 89% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlMutableBuffer.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlMutableBuffer.java index 3287f903ec..4a8fd23689 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlMutableBuffer.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlMutableBuffer.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.gl.buffer; +package net.caffeinemc.mods.sodium.client.gl.buffer; /** * A mutable buffer type which is supported with OpenGL 1.5+. The buffer's storage can be reallocated at any time diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/device/CommandList.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/device/CommandList.java similarity index 71% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/device/CommandList.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/device/CommandList.java index afbea83eca..d11fbce614 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/device/CommandList.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/device/CommandList.java @@ -1,12 +1,12 @@ -package me.jellysquid.mods.sodium.client.gl.device; - -import me.jellysquid.mods.sodium.client.gl.array.GlVertexArray; -import me.jellysquid.mods.sodium.client.gl.buffer.*; -import me.jellysquid.mods.sodium.client.gl.sync.GlFence; -import me.jellysquid.mods.sodium.client.gl.tessellation.GlPrimitiveType; -import me.jellysquid.mods.sodium.client.gl.tessellation.GlTessellation; -import me.jellysquid.mods.sodium.client.gl.tessellation.TessellationBinding; -import me.jellysquid.mods.sodium.client.gl.util.EnumBitField; +package net.caffeinemc.mods.sodium.client.gl.device; + +import net.caffeinemc.mods.sodium.client.gl.array.GlVertexArray; +import net.caffeinemc.mods.sodium.client.gl.buffer.*; +import net.caffeinemc.mods.sodium.client.gl.sync.GlFence; +import net.caffeinemc.mods.sodium.client.gl.tessellation.GlPrimitiveType; +import net.caffeinemc.mods.sodium.client.gl.tessellation.GlTessellation; +import net.caffeinemc.mods.sodium.client.gl.tessellation.TessellationBinding; +import net.caffeinemc.mods.sodium.client.gl.util.EnumBitField; import java.nio.ByteBuffer; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/device/DrawCommandList.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/device/DrawCommandList.java similarity index 68% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/device/DrawCommandList.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/device/DrawCommandList.java index 2f0d674f4b..649a36a11c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/device/DrawCommandList.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/device/DrawCommandList.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.client.gl.device; +package net.caffeinemc.mods.sodium.client.gl.device; -import me.jellysquid.mods.sodium.client.gl.tessellation.GlIndexType; +import net.caffeinemc.mods.sodium.client.gl.tessellation.GlIndexType; public interface DrawCommandList extends AutoCloseable { void multiDrawElementsBaseVertex(MultiDrawBatch batch, GlIndexType indexType); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/device/GLRenderDevice.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/device/GLRenderDevice.java similarity index 95% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/device/GLRenderDevice.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/device/GLRenderDevice.java index 66a0433934..98af1f3ba3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/device/GLRenderDevice.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/device/GLRenderDevice.java @@ -1,12 +1,12 @@ -package me.jellysquid.mods.sodium.client.gl.device; - -import me.jellysquid.mods.sodium.client.gl.array.GlVertexArray; -import me.jellysquid.mods.sodium.client.gl.buffer.*; -import me.jellysquid.mods.sodium.client.gl.functions.DeviceFunctions; -import me.jellysquid.mods.sodium.client.gl.state.GlStateTracker; -import me.jellysquid.mods.sodium.client.gl.sync.GlFence; -import me.jellysquid.mods.sodium.client.gl.tessellation.*; -import me.jellysquid.mods.sodium.client.gl.util.EnumBitField; +package net.caffeinemc.mods.sodium.client.gl.device; + +import net.caffeinemc.mods.sodium.client.gl.array.GlVertexArray; +import net.caffeinemc.mods.sodium.client.gl.buffer.*; +import net.caffeinemc.mods.sodium.client.gl.functions.DeviceFunctions; +import net.caffeinemc.mods.sodium.client.gl.state.GlStateTracker; +import net.caffeinemc.mods.sodium.client.gl.sync.GlFence; +import net.caffeinemc.mods.sodium.client.gl.tessellation.*; +import net.caffeinemc.mods.sodium.client.gl.util.EnumBitField; import org.lwjgl.opengl.*; import com.mojang.blaze3d.vertex.BufferUploader; import java.nio.ByteBuffer; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/device/MultiDrawBatch.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/device/MultiDrawBatch.java similarity index 97% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/device/MultiDrawBatch.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/device/MultiDrawBatch.java index 258213beda..ceda21721a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/device/MultiDrawBatch.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/device/MultiDrawBatch.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.gl.device; +package net.caffeinemc.mods.sodium.client.gl.device; import org.lwjgl.PointerBuffer; import org.lwjgl.system.MemoryUtil; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/device/RenderDevice.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/device/RenderDevice.java similarity index 79% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/device/RenderDevice.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/device/RenderDevice.java index 49bcfb3d84..e87edf1cec 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/device/RenderDevice.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/device/RenderDevice.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.client.gl.device; +package net.caffeinemc.mods.sodium.client.gl.device; -import me.jellysquid.mods.sodium.client.gl.functions.DeviceFunctions; +import net.caffeinemc.mods.sodium.client.gl.functions.DeviceFunctions; import org.lwjgl.opengl.GLCapabilities; public interface RenderDevice { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/functions/BufferStorageFunctions.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/functions/BufferStorageFunctions.java similarity index 80% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/functions/BufferStorageFunctions.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/functions/BufferStorageFunctions.java index 4105336b3f..6ef3ec93b1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/functions/BufferStorageFunctions.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/functions/BufferStorageFunctions.java @@ -1,9 +1,9 @@ -package me.jellysquid.mods.sodium.client.gl.functions; +package net.caffeinemc.mods.sodium.client.gl.functions; -import me.jellysquid.mods.sodium.client.gl.buffer.GlBufferStorageFlags; -import me.jellysquid.mods.sodium.client.gl.buffer.GlBufferTarget; -import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; -import me.jellysquid.mods.sodium.client.gl.util.EnumBitField; +import net.caffeinemc.mods.sodium.client.gl.buffer.GlBufferStorageFlags; +import net.caffeinemc.mods.sodium.client.gl.buffer.GlBufferTarget; +import net.caffeinemc.mods.sodium.client.gl.device.RenderDevice; +import net.caffeinemc.mods.sodium.client.gl.util.EnumBitField; import org.lwjgl.opengl.ARBBufferStorage; import org.lwjgl.opengl.GL44C; import org.lwjgl.opengl.GLCapabilities; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/functions/DeviceFunctions.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/functions/DeviceFunctions.java similarity index 74% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/functions/DeviceFunctions.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/functions/DeviceFunctions.java index 36a0250d74..2b3e00ea69 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/functions/DeviceFunctions.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/functions/DeviceFunctions.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.client.gl.functions; +package net.caffeinemc.mods.sodium.client.gl.functions; -import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; +import net.caffeinemc.mods.sodium.client.gl.device.RenderDevice; public class DeviceFunctions { private final BufferStorageFunctions bufferStorageFunctions; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlProgram.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/GlProgram.java similarity index 92% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlProgram.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/GlProgram.java index a46f41152d..c081fbeed5 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlProgram.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/GlProgram.java @@ -1,10 +1,10 @@ -package me.jellysquid.mods.sodium.client.gl.shader; +package net.caffeinemc.mods.sodium.client.gl.shader; import com.mojang.blaze3d.platform.GlStateManager; -import me.jellysquid.mods.sodium.client.gl.GlObject; -import me.jellysquid.mods.sodium.client.gl.shader.uniform.GlUniform; -import me.jellysquid.mods.sodium.client.gl.shader.uniform.GlUniformBlock; -import me.jellysquid.mods.sodium.client.render.chunk.shader.ShaderBindingContext; +import net.caffeinemc.mods.sodium.client.gl.GlObject; +import net.caffeinemc.mods.sodium.client.gl.shader.uniform.GlUniform; +import net.caffeinemc.mods.sodium.client.gl.shader.uniform.GlUniformBlock; +import net.caffeinemc.mods.sodium.client.render.chunk.shader.ShaderBindingContext; import net.minecraft.resources.ResourceLocation; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlShader.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/GlShader.java similarity index 92% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlShader.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/GlShader.java index 2c73d10f2c..0cc4058234 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlShader.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/GlShader.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.client.gl.shader; +package net.caffeinemc.mods.sodium.client.gl.shader; import com.mojang.blaze3d.platform.GlStateManager; -import me.jellysquid.mods.sodium.client.gl.GlObject; +import net.caffeinemc.mods.sodium.client.gl.GlObject; import net.minecraft.resources.ResourceLocation; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderConstants.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/ShaderConstants.java similarity index 97% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderConstants.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/ShaderConstants.java index 4fed6c522a..8a419d5d2c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderConstants.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/ShaderConstants.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.gl.shader; +package net.caffeinemc.mods.sodium.client.gl.shader; import java.util.*; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderLoader.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/ShaderLoader.java similarity index 96% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderLoader.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/ShaderLoader.java index 6dd27f8458..03d04c0e97 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderLoader.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/ShaderLoader.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.gl.shader; +package net.caffeinemc.mods.sodium.client.gl.shader; import org.apache.commons.io.IOUtils; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderParser.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/ShaderParser.java similarity index 97% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderParser.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/ShaderParser.java index 9bdb7c8a93..ad4fde7456 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderParser.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/ShaderParser.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.gl.shader; +package net.caffeinemc.mods.sodium.client.gl.shader; import java.io.BufferedReader; import java.io.IOException; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderType.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/ShaderType.java similarity index 84% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderType.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/ShaderType.java index 4791e3dc81..4d4f1842bf 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderType.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/ShaderType.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.gl.shader; +package net.caffeinemc.mods.sodium.client.gl.shader; import org.lwjgl.opengl.GL20C; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderWorkarounds.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/ShaderWorkarounds.java similarity index 97% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderWorkarounds.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/ShaderWorkarounds.java index ef87e5c11c..b5a5dbb039 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderWorkarounds.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/ShaderWorkarounds.java @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package me.jellysquid.mods.sodium.client.gl.shader; +package net.caffeinemc.mods.sodium.client.gl.shader; import java.nio.ByteBuffer; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/uniform/GlUniform.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniform.java similarity index 75% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/shader/uniform/GlUniform.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniform.java index 733588d974..4ea0546732 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/uniform/GlUniform.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniform.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.gl.shader.uniform; +package net.caffeinemc.mods.sodium.client.gl.shader.uniform; public abstract class GlUniform { protected final int index; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/uniform/GlUniformBlock.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformBlock.java similarity index 73% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/shader/uniform/GlUniformBlock.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformBlock.java index 719ad4d957..a64d6f89c5 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/uniform/GlUniformBlock.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformBlock.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.client.gl.shader.uniform; +package net.caffeinemc.mods.sodium.client.gl.shader.uniform; -import me.jellysquid.mods.sodium.client.gl.buffer.GlBuffer; +import net.caffeinemc.mods.sodium.client.gl.buffer.GlBuffer; import org.lwjgl.opengl.GL32C; public class GlUniformBlock { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/uniform/GlUniformFloat.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformFloat.java similarity index 84% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/shader/uniform/GlUniformFloat.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformFloat.java index dc7650709b..ab56099676 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/uniform/GlUniformFloat.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformFloat.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.gl.shader.uniform; +package net.caffeinemc.mods.sodium.client.gl.shader.uniform; import org.lwjgl.opengl.GL30C; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/uniform/GlUniformFloat3v.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformFloat3v.java similarity index 88% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/shader/uniform/GlUniformFloat3v.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformFloat3v.java index 7fdc92fb4e..07d81fb3a5 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/uniform/GlUniformFloat3v.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformFloat3v.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.gl.shader.uniform; +package net.caffeinemc.mods.sodium.client.gl.shader.uniform; import org.lwjgl.opengl.GL30C; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/uniform/GlUniformFloat4v.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformFloat4v.java similarity index 86% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/shader/uniform/GlUniformFloat4v.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformFloat4v.java index c2edf0c89e..c968f69bdb 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/uniform/GlUniformFloat4v.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformFloat4v.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.gl.shader.uniform; +package net.caffeinemc.mods.sodium.client.gl.shader.uniform; import org.lwjgl.opengl.GL30C; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/uniform/GlUniformInt.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformInt.java similarity index 84% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/shader/uniform/GlUniformInt.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformInt.java index 46998efaa9..30691bd61f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/uniform/GlUniformInt.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformInt.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.gl.shader.uniform; +package net.caffeinemc.mods.sodium.client.gl.shader.uniform; import org.lwjgl.opengl.GL30C; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/uniform/GlUniformMatrix4f.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformMatrix4f.java similarity index 90% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/shader/uniform/GlUniformMatrix4f.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformMatrix4f.java index 2bc5c27039..f413590d36 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/uniform/GlUniformMatrix4f.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformMatrix4f.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.gl.shader.uniform; +package net.caffeinemc.mods.sodium.client.gl.shader.uniform; import org.joml.Matrix4f; import org.joml.Matrix4fc; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/state/GlStateTracker.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/state/GlStateTracker.java similarity index 86% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/state/GlStateTracker.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/state/GlStateTracker.java index 2f1e4a8115..836ed919ce 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/state/GlStateTracker.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/state/GlStateTracker.java @@ -1,8 +1,8 @@ -package me.jellysquid.mods.sodium.client.gl.state; +package net.caffeinemc.mods.sodium.client.gl.state; -import me.jellysquid.mods.sodium.client.gl.array.GlVertexArray; -import me.jellysquid.mods.sodium.client.gl.buffer.GlBuffer; -import me.jellysquid.mods.sodium.client.gl.buffer.GlBufferTarget; +import net.caffeinemc.mods.sodium.client.gl.array.GlVertexArray; +import net.caffeinemc.mods.sodium.client.gl.buffer.GlBuffer; +import net.caffeinemc.mods.sodium.client.gl.buffer.GlBufferTarget; import java.util.Arrays; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/sync/GlFence.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/sync/GlFence.java similarity index 95% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/sync/GlFence.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/sync/GlFence.java index 4fdd00557d..589afa1d92 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/sync/GlFence.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/sync/GlFence.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.gl.sync; +package net.caffeinemc.mods.sodium.client.gl.sync; import org.lwjgl.opengl.GL32C; import org.lwjgl.system.MemoryStack; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlAbstractTessellation.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/GlAbstractTessellation.java similarity index 87% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlAbstractTessellation.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/GlAbstractTessellation.java index e4ba5a8c01..a5707a476c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlAbstractTessellation.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/GlAbstractTessellation.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.client.gl.tessellation; +package net.caffeinemc.mods.sodium.client.gl.tessellation; -import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexAttributeBinding; -import me.jellysquid.mods.sodium.client.gl.device.CommandList; +import net.caffeinemc.mods.sodium.client.gl.attribute.GlVertexAttributeBinding; +import net.caffeinemc.mods.sodium.client.gl.device.CommandList; import org.lwjgl.opengl.GL20C; import org.lwjgl.opengl.GL30C; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlIndexType.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/GlIndexType.java similarity index 89% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlIndexType.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/GlIndexType.java index 61cae6e5f1..9cc4ef76e1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlIndexType.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/GlIndexType.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.gl.tessellation; +package net.caffeinemc.mods.sodium.client.gl.tessellation; import org.lwjgl.opengl.GL32C; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlPrimitiveType.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/GlPrimitiveType.java similarity index 80% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlPrimitiveType.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/GlPrimitiveType.java index ba56716a64..2946bc40b6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlPrimitiveType.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/GlPrimitiveType.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.gl.tessellation; +package net.caffeinemc.mods.sodium.client.gl.tessellation; import org.lwjgl.opengl.GL20C; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlTessellation.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/GlTessellation.java similarity index 62% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlTessellation.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/GlTessellation.java index cf7aeb70ac..78162686f1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlTessellation.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/GlTessellation.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.client.gl.tessellation; +package net.caffeinemc.mods.sodium.client.gl.tessellation; -import me.jellysquid.mods.sodium.client.gl.device.CommandList; +import net.caffeinemc.mods.sodium.client.gl.device.CommandList; public interface GlTessellation { void delete(CommandList commandList); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlVertexArrayTessellation.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/GlVertexArrayTessellation.java similarity index 81% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlVertexArrayTessellation.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/GlVertexArrayTessellation.java index 6803be6e4c..6c861993ca 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlVertexArrayTessellation.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/GlVertexArrayTessellation.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.client.gl.tessellation; +package net.caffeinemc.mods.sodium.client.gl.tessellation; -import me.jellysquid.mods.sodium.client.gl.array.GlVertexArray; -import me.jellysquid.mods.sodium.client.gl.device.CommandList; +import net.caffeinemc.mods.sodium.client.gl.array.GlVertexArray; +import net.caffeinemc.mods.sodium.client.gl.device.CommandList; public class GlVertexArrayTessellation extends GlAbstractTessellation { private final GlVertexArray array; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/TessellationBinding.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/TessellationBinding.java similarity index 68% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/TessellationBinding.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/TessellationBinding.java index 1c66e28d86..a2d436563c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/TessellationBinding.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/TessellationBinding.java @@ -1,8 +1,8 @@ -package me.jellysquid.mods.sodium.client.gl.tessellation; +package net.caffeinemc.mods.sodium.client.gl.tessellation; -import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexAttributeBinding; -import me.jellysquid.mods.sodium.client.gl.buffer.GlBuffer; -import me.jellysquid.mods.sodium.client.gl.buffer.GlBufferTarget; +import net.caffeinemc.mods.sodium.client.gl.attribute.GlVertexAttributeBinding; +import net.caffeinemc.mods.sodium.client.gl.buffer.GlBuffer; +import net.caffeinemc.mods.sodium.client.gl.buffer.GlBufferTarget; public record TessellationBinding(GlBufferTarget target, GlBuffer buffer, diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/util/EnumBit.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/util/EnumBit.java new file mode 100644 index 0000000000..5a6c5688fc --- /dev/null +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/util/EnumBit.java @@ -0,0 +1,5 @@ +package net.caffeinemc.mods.sodium.client.gl.util; + +public interface EnumBit { + int getBits(); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/util/EnumBitField.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/util/EnumBitField.java similarity index 94% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/util/EnumBitField.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/util/EnumBitField.java index 26f8c9f4a4..10fe829fd3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/util/EnumBitField.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/util/EnumBitField.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.gl.util; +package net.caffeinemc.mods.sodium.client.gl.util; import java.util.Arrays; import java.util.EnumSet; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/util/VertexRange.java b/src/main/java/net/caffeinemc/mods/sodium/client/gl/util/VertexRange.java similarity index 56% rename from src/main/java/me/jellysquid/mods/sodium/client/gl/util/VertexRange.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gl/util/VertexRange.java index c37655f09a..1520a6b6aa 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/util/VertexRange.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gl/util/VertexRange.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.gl.util; +package net.caffeinemc.mods.sodium.client.gl.util; public record VertexRange(int vertexStart, int vertexCount) { } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java b/src/main/java/net/caffeinemc/mods/sodium/client/gui/SodiumGameOptionPages.java similarity index 96% rename from src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gui/SodiumGameOptionPages.java index 7a417a2718..d3e3f14a23 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gui/SodiumGameOptionPages.java @@ -1,19 +1,19 @@ -package me.jellysquid.mods.sodium.client.gui; +package net.caffeinemc.mods.sodium.client.gui; import com.google.common.collect.ImmutableList; import com.mojang.blaze3d.pipeline.RenderTarget; import com.mojang.blaze3d.platform.Window; -import me.jellysquid.mods.sodium.client.gl.arena.staging.MappedStagingBuffer; -import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; -import me.jellysquid.mods.sodium.client.gui.options.*; -import me.jellysquid.mods.sodium.client.gui.options.binding.compat.VanillaBooleanOptionBinding; -import me.jellysquid.mods.sodium.client.gui.options.control.ControlValueFormatter; -import me.jellysquid.mods.sodium.client.gui.options.control.CyclingControl; -import me.jellysquid.mods.sodium.client.gui.options.control.SliderControl; -import me.jellysquid.mods.sodium.client.gui.options.control.TickBoxControl; -import me.jellysquid.mods.sodium.client.gui.options.storage.MinecraftOptionsStorage; -import me.jellysquid.mods.sodium.client.gui.options.storage.SodiumOptionsStorage; -import me.jellysquid.mods.sodium.client.compatibility.workarounds.Workarounds; +import net.caffeinemc.mods.sodium.client.gl.arena.staging.MappedStagingBuffer; +import net.caffeinemc.mods.sodium.client.gl.device.RenderDevice; +import net.caffeinemc.mods.sodium.client.gui.options.*; +import net.caffeinemc.mods.sodium.client.gui.options.binding.compat.VanillaBooleanOptionBinding; +import net.caffeinemc.mods.sodium.client.gui.options.control.ControlValueFormatter; +import net.caffeinemc.mods.sodium.client.gui.options.control.CyclingControl; +import net.caffeinemc.mods.sodium.client.gui.options.control.SliderControl; +import net.caffeinemc.mods.sodium.client.gui.options.control.TickBoxControl; +import net.caffeinemc.mods.sodium.client.gui.options.storage.MinecraftOptionsStorage; +import net.caffeinemc.mods.sodium.client.gui.options.storage.SodiumOptionsStorage; +import net.caffeinemc.mods.sodium.client.compatibility.workarounds.Workarounds; import net.minecraft.client.AttackIndicatorStatus; import net.minecraft.client.CloudStatus; import net.minecraft.client.GraphicsStatus; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java b/src/main/java/net/caffeinemc/mods/sodium/client/gui/SodiumGameOptions.java similarity index 94% rename from src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gui/SodiumGameOptions.java index e0b1aba388..7c7649df39 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gui/SodiumGameOptions.java @@ -1,12 +1,12 @@ -package me.jellysquid.mods.sodium.client.gui; +package net.caffeinemc.mods.sodium.client.gui; import com.google.gson.FieldNamingPolicy; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.annotations.SerializedName; -import me.jellysquid.mods.sodium.client.gui.options.TextProvider; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortBehavior; -import me.jellysquid.mods.sodium.client.util.FileUtil; +import net.caffeinemc.mods.sodium.client.gui.options.TextProvider; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.SortBehavior; +import net.caffeinemc.mods.sodium.client.util.FileUtil; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.client.GraphicsStatus; import net.minecraft.network.chat.Component; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java b/src/main/java/net/caffeinemc/mods/sodium/client/gui/SodiumOptionsGUI.java similarity index 94% rename from src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gui/SodiumOptionsGUI.java index b8ea794f82..1484150cec 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gui/SodiumOptionsGUI.java @@ -1,18 +1,18 @@ -package me.jellysquid.mods.sodium.client.gui; - -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import me.jellysquid.mods.sodium.client.data.fingerprint.HashedFingerprint; -import me.jellysquid.mods.sodium.client.gui.console.Console; -import me.jellysquid.mods.sodium.client.gui.console.message.MessageLevel; -import me.jellysquid.mods.sodium.client.gui.options.*; -import me.jellysquid.mods.sodium.client.gui.options.control.Control; -import me.jellysquid.mods.sodium.client.gui.options.control.ControlElement; -import me.jellysquid.mods.sodium.client.gui.options.storage.OptionStorage; -import me.jellysquid.mods.sodium.client.gui.prompt.ScreenPrompt; -import me.jellysquid.mods.sodium.client.gui.prompt.ScreenPromptable; -import me.jellysquid.mods.sodium.client.gui.screen.ConfigCorruptedScreen; -import me.jellysquid.mods.sodium.client.gui.widgets.FlatButtonWidget; -import me.jellysquid.mods.sodium.client.util.Dim2i; +package net.caffeinemc.mods.sodium.client.gui; + +import net.caffeinemc.mods.sodium.client.SodiumClientMod; +import net.caffeinemc.mods.sodium.client.data.fingerprint.HashedFingerprint; +import net.caffeinemc.mods.sodium.client.gui.console.Console; +import net.caffeinemc.mods.sodium.client.gui.console.message.MessageLevel; +import net.caffeinemc.mods.sodium.client.gui.options.*; +import net.caffeinemc.mods.sodium.client.gui.options.control.Control; +import net.caffeinemc.mods.sodium.client.gui.options.control.ControlElement; +import net.caffeinemc.mods.sodium.client.gui.options.storage.OptionStorage; +import net.caffeinemc.mods.sodium.client.gui.prompt.ScreenPrompt; +import net.caffeinemc.mods.sodium.client.gui.prompt.ScreenPromptable; +import net.caffeinemc.mods.sodium.client.gui.screen.ConfigCorruptedScreen; +import net.caffeinemc.mods.sodium.client.gui.widgets.FlatButtonWidget; +import net.caffeinemc.mods.sodium.client.util.Dim2i; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.ChatFormatting; import net.minecraft.Util; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/console/Console.java b/src/main/java/net/caffeinemc/mods/sodium/client/gui/console/Console.java similarity index 79% rename from src/main/java/me/jellysquid/mods/sodium/client/gui/console/Console.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gui/console/Console.java index 72cdaf6543..999f8de344 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/console/Console.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gui/console/Console.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.client.gui.console; +package net.caffeinemc.mods.sodium.client.gui.console; -import me.jellysquid.mods.sodium.client.gui.console.message.Message; -import me.jellysquid.mods.sodium.client.gui.console.message.MessageLevel; +import net.caffeinemc.mods.sodium.client.gui.console.message.Message; +import net.caffeinemc.mods.sodium.client.gui.console.message.MessageLevel; import net.minecraft.network.chat.Component; import org.apache.commons.lang3.Validate; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/console/ConsoleHooks.java b/src/main/java/net/caffeinemc/mods/sodium/client/gui/console/ConsoleHooks.java similarity index 83% rename from src/main/java/me/jellysquid/mods/sodium/client/gui/console/ConsoleHooks.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gui/console/ConsoleHooks.java index 587e1dd3bd..9afbffbd5e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/console/ConsoleHooks.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gui/console/ConsoleHooks.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.gui.console; +package net.caffeinemc.mods.sodium.client.gui.console; import net.minecraft.client.gui.GuiGraphics; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/console/ConsoleRenderer.java b/src/main/java/net/caffeinemc/mods/sodium/client/gui/console/ConsoleRenderer.java similarity index 97% rename from src/main/java/me/jellysquid/mods/sodium/client/gui/console/ConsoleRenderer.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gui/console/ConsoleRenderer.java index fedd7c1df0..c2b0175125 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/console/ConsoleRenderer.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gui/console/ConsoleRenderer.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.client.gui.console; +package net.caffeinemc.mods.sodium.client.gui.console; -import me.jellysquid.mods.sodium.client.gui.console.message.Message; -import me.jellysquid.mods.sodium.client.gui.console.message.MessageLevel; +import net.caffeinemc.mods.sodium.client.gui.console.message.Message; +import net.caffeinemc.mods.sodium.client.gui.console.message.MessageLevel; import net.caffeinemc.mods.sodium.api.util.ColorARGB; import net.caffeinemc.mods.sodium.api.util.ColorU8; import net.minecraft.client.Minecraft; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/console/ConsoleSink.java b/src/main/java/net/caffeinemc/mods/sodium/client/gui/console/ConsoleSink.java similarity index 62% rename from src/main/java/me/jellysquid/mods/sodium/client/gui/console/ConsoleSink.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gui/console/ConsoleSink.java index 758b4e7b08..c2c347acec 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/console/ConsoleSink.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gui/console/ConsoleSink.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.client.gui.console; +package net.caffeinemc.mods.sodium.client.gui.console; -import me.jellysquid.mods.sodium.client.gui.console.message.MessageLevel; +import net.caffeinemc.mods.sodium.client.gui.console.message.MessageLevel; import net.minecraft.network.chat.Component; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/console/message/Message.java b/src/main/java/net/caffeinemc/mods/sodium/client/gui/console/message/Message.java similarity index 66% rename from src/main/java/me/jellysquid/mods/sodium/client/gui/console/message/Message.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gui/console/message/Message.java index f1f45f5494..8425899645 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/console/message/Message.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gui/console/message/Message.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.gui.console.message; +package net.caffeinemc.mods.sodium.client.gui.console.message; import net.minecraft.network.chat.Component; diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gui/console/message/MessageLevel.java b/src/main/java/net/caffeinemc/mods/sodium/client/gui/console/message/MessageLevel.java new file mode 100644 index 0000000000..569373d1c1 --- /dev/null +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gui/console/message/MessageLevel.java @@ -0,0 +1,7 @@ +package net.caffeinemc.mods.sodium.client.gui.console.message; + +public enum MessageLevel { + INFO, + WARN, + SEVERE +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/Option.java b/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/Option.java similarity index 68% rename from src/main/java/me/jellysquid/mods/sodium/client/gui/options/Option.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gui/options/Option.java index 4eb9ac86ea..0b88b64478 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/Option.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/Option.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.client.gui.options; +package net.caffeinemc.mods.sodium.client.gui.options; -import me.jellysquid.mods.sodium.client.gui.options.control.Control; -import me.jellysquid.mods.sodium.client.gui.options.storage.OptionStorage; +import net.caffeinemc.mods.sodium.client.gui.options.control.Control; +import net.caffeinemc.mods.sodium.client.gui.options.storage.OptionStorage; import net.minecraft.network.chat.Component; import java.util.Collection; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionFlag.java b/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/OptionFlag.java similarity index 71% rename from src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionFlag.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gui/options/OptionFlag.java index ea87bddd88..8ea3e5b0bf 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionFlag.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/OptionFlag.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.gui.options; +package net.caffeinemc.mods.sodium.client.gui.options; public enum OptionFlag { REQUIRES_RENDERER_RELOAD, diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionGroup.java b/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/OptionGroup.java similarity index 94% rename from src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionGroup.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gui/options/OptionGroup.java index 97426724a7..88d21dc7d3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionGroup.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/OptionGroup.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.gui.options; +package net.caffeinemc.mods.sodium.client.gui.options; import com.google.common.collect.ImmutableList; import org.apache.commons.lang3.Validate; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpact.java b/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/OptionImpact.java similarity index 92% rename from src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpact.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gui/options/OptionImpact.java index 693e6e6fca..f8172ca1e2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpact.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/OptionImpact.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.gui.options; +package net.caffeinemc.mods.sodium.client.gui.options; import net.minecraft.ChatFormatting; import net.minecraft.network.chat.Component; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpl.java b/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/OptionImpl.java similarity index 93% rename from src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpl.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gui/options/OptionImpl.java index 7fd6a654de..42c4af342d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpl.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/OptionImpl.java @@ -1,9 +1,9 @@ -package me.jellysquid.mods.sodium.client.gui.options; +package net.caffeinemc.mods.sodium.client.gui.options; -import me.jellysquid.mods.sodium.client.gui.options.binding.GenericBinding; -import me.jellysquid.mods.sodium.client.gui.options.binding.OptionBinding; -import me.jellysquid.mods.sodium.client.gui.options.control.Control; -import me.jellysquid.mods.sodium.client.gui.options.storage.OptionStorage; +import net.caffeinemc.mods.sodium.client.gui.options.binding.GenericBinding; +import net.caffeinemc.mods.sodium.client.gui.options.binding.OptionBinding; +import net.caffeinemc.mods.sodium.client.gui.options.control.Control; +import net.caffeinemc.mods.sodium.client.gui.options.storage.OptionStorage; import net.minecraft.network.chat.Component; import org.apache.commons.lang3.Validate; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionPage.java b/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/OptionPage.java similarity index 93% rename from src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionPage.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gui/options/OptionPage.java index 0baaceee6b..c34450ea22 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionPage.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/OptionPage.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.gui.options; +package net.caffeinemc.mods.sodium.client.gui.options; import com.google.common.collect.ImmutableList; import net.minecraft.network.chat.Component; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/TextProvider.java b/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/TextProvider.java similarity index 67% rename from src/main/java/me/jellysquid/mods/sodium/client/gui/options/TextProvider.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gui/options/TextProvider.java index 9f438c2709..9e74e438b2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/TextProvider.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/TextProvider.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.gui.options; +package net.caffeinemc.mods.sodium.client.gui.options; import net.minecraft.network.chat.Component; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/GenericBinding.java b/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/binding/GenericBinding.java similarity index 90% rename from src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/GenericBinding.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gui/options/binding/GenericBinding.java index 9e166c93ef..a66555039c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/GenericBinding.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/binding/GenericBinding.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.gui.options.binding; +package net.caffeinemc.mods.sodium.client.gui.options.binding; import java.util.function.BiConsumer; import java.util.function.Function; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/OptionBinding.java b/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/binding/OptionBinding.java similarity index 63% rename from src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/OptionBinding.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gui/options/binding/OptionBinding.java index 5e597a679f..8af6daffca 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/OptionBinding.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/binding/OptionBinding.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.gui.options.binding; +package net.caffeinemc.mods.sodium.client.gui.options.binding; public interface OptionBinding { void setValue(S storage, T value); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/compat/VanillaBooleanOptionBinding.java b/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/binding/compat/VanillaBooleanOptionBinding.java similarity index 78% rename from src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/compat/VanillaBooleanOptionBinding.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gui/options/binding/compat/VanillaBooleanOptionBinding.java index c78dec6c02..d72c4bbda4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/compat/VanillaBooleanOptionBinding.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/binding/compat/VanillaBooleanOptionBinding.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.client.gui.options.binding.compat; +package net.caffeinemc.mods.sodium.client.gui.options.binding.compat; -import me.jellysquid.mods.sodium.client.gui.options.binding.OptionBinding; +import net.caffeinemc.mods.sodium.client.gui.options.binding.OptionBinding; import net.minecraft.client.OptionInstance; import net.minecraft.client.Options; diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/Control.java b/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/Control.java new file mode 100644 index 0000000000..efb82730be --- /dev/null +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/Control.java @@ -0,0 +1,12 @@ +package net.caffeinemc.mods.sodium.client.gui.options.control; + +import net.caffeinemc.mods.sodium.client.gui.options.Option; +import net.caffeinemc.mods.sodium.client.util.Dim2i; + +public interface Control { + Option getOption(); + + ControlElement createElement(Dim2i dim); + + int getMaxWidth(); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlElement.java b/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/ControlElement.java similarity index 90% rename from src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlElement.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/ControlElement.java index c6336be1b6..cd9dba278e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlElement.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/ControlElement.java @@ -1,8 +1,8 @@ -package me.jellysquid.mods.sodium.client.gui.options.control; +package net.caffeinemc.mods.sodium.client.gui.options.control; -import me.jellysquid.mods.sodium.client.gui.options.Option; -import me.jellysquid.mods.sodium.client.gui.widgets.AbstractWidget; -import me.jellysquid.mods.sodium.client.util.Dim2i; +import net.caffeinemc.mods.sodium.client.gui.options.Option; +import net.caffeinemc.mods.sodium.client.gui.widgets.AbstractWidget; +import net.caffeinemc.mods.sodium.client.util.Dim2i; import net.minecraft.ChatFormatting; import net.minecraft.client.gui.ComponentPath; import net.minecraft.client.gui.GuiGraphics; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlValueFormatter.java b/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/ControlValueFormatter.java similarity index 96% rename from src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlValueFormatter.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/ControlValueFormatter.java index 4ee1d8f683..e72a682b1b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlValueFormatter.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/ControlValueFormatter.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.gui.options.control; +package net.caffeinemc.mods.sodium.client.gui.options.control; import net.minecraft.network.chat.Component; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/CyclingControl.java b/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/CyclingControl.java similarity index 94% rename from src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/CyclingControl.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/CyclingControl.java index db9bcc37ed..4f3f19fee9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/CyclingControl.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/CyclingControl.java @@ -1,8 +1,8 @@ -package me.jellysquid.mods.sodium.client.gui.options.control; +package net.caffeinemc.mods.sodium.client.gui.options.control; -import me.jellysquid.mods.sodium.client.gui.options.Option; -import me.jellysquid.mods.sodium.client.gui.options.TextProvider; -import me.jellysquid.mods.sodium.client.util.Dim2i; +import net.caffeinemc.mods.sodium.client.gui.options.Option; +import net.caffeinemc.mods.sodium.client.gui.options.TextProvider; +import net.caffeinemc.mods.sodium.client.util.Dim2i; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.navigation.CommonInputs; import net.minecraft.client.gui.screens.Screen; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/SliderControl.java b/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/SliderControl.java similarity index 97% rename from src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/SliderControl.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/SliderControl.java index f8ded9a65f..cbe4e527cb 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/SliderControl.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/SliderControl.java @@ -1,8 +1,8 @@ -package me.jellysquid.mods.sodium.client.gui.options.control; +package net.caffeinemc.mods.sodium.client.gui.options.control; import com.mojang.blaze3d.platform.InputConstants; -import me.jellysquid.mods.sodium.client.gui.options.Option; -import me.jellysquid.mods.sodium.client.util.Dim2i; +import net.caffeinemc.mods.sodium.client.gui.options.Option; +import net.caffeinemc.mods.sodium.client.util.Dim2i; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.renderer.Rect2i; import net.minecraft.network.chat.Component; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/TickBoxControl.java b/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/TickBoxControl.java similarity index 93% rename from src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/TickBoxControl.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/TickBoxControl.java index abdc1e1dce..a33dc4ca8b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/TickBoxControl.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/TickBoxControl.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.client.gui.options.control; +package net.caffeinemc.mods.sodium.client.gui.options.control; -import me.jellysquid.mods.sodium.client.gui.options.Option; -import me.jellysquid.mods.sodium.client.util.Dim2i; +import net.caffeinemc.mods.sodium.client.gui.options.Option; +import net.caffeinemc.mods.sodium.client.util.Dim2i; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.navigation.CommonInputs; import net.minecraft.client.renderer.Rect2i; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/MinecraftOptionsStorage.java b/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/storage/MinecraftOptionsStorage.java similarity index 81% rename from src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/MinecraftOptionsStorage.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gui/options/storage/MinecraftOptionsStorage.java index 92748aae01..296e8532d5 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/MinecraftOptionsStorage.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/storage/MinecraftOptionsStorage.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.client.gui.options.storage; +package net.caffeinemc.mods.sodium.client.gui.options.storage; -import me.jellysquid.mods.sodium.client.SodiumClientMod; +import net.caffeinemc.mods.sodium.client.SodiumClientMod; import net.minecraft.client.Minecraft; import net.minecraft.client.Options; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/OptionStorage.java b/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/storage/OptionStorage.java similarity index 54% rename from src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/OptionStorage.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gui/options/storage/OptionStorage.java index a2e4966da2..90f251ae23 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/OptionStorage.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/storage/OptionStorage.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.gui.options.storage; +package net.caffeinemc.mods.sodium.client.gui.options.storage; public interface OptionStorage { T getData(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/SodiumOptionsStorage.java b/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/storage/SodiumOptionsStorage.java similarity index 78% rename from src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/SodiumOptionsStorage.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gui/options/storage/SodiumOptionsStorage.java index 063dd19416..cd77f3cf2d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/SodiumOptionsStorage.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/storage/SodiumOptionsStorage.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.client.gui.options.storage; +package net.caffeinemc.mods.sodium.client.gui.options.storage; -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions; +import net.caffeinemc.mods.sodium.client.SodiumClientMod; +import net.caffeinemc.mods.sodium.client.gui.SodiumGameOptions; import java.io.IOException; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/prompt/ScreenPrompt.java b/src/main/java/net/caffeinemc/mods/sodium/client/gui/prompt/ScreenPrompt.java similarity index 93% rename from src/main/java/me/jellysquid/mods/sodium/client/gui/prompt/ScreenPrompt.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gui/prompt/ScreenPrompt.java index b28acdf918..2136ffbb61 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/prompt/ScreenPrompt.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gui/prompt/ScreenPrompt.java @@ -1,9 +1,9 @@ -package me.jellysquid.mods.sodium.client.gui.prompt; +package net.caffeinemc.mods.sodium.client.gui.prompt; -import me.jellysquid.mods.sodium.client.gui.widgets.AbstractWidget; -import me.jellysquid.mods.sodium.client.gui.widgets.FlatButtonWidget; -import me.jellysquid.mods.sodium.client.gui.widgets.FlatButtonWidget.Style; -import me.jellysquid.mods.sodium.client.util.Dim2i; +import net.caffeinemc.mods.sodium.client.gui.widgets.AbstractWidget; +import net.caffeinemc.mods.sodium.client.gui.widgets.FlatButtonWidget; +import net.caffeinemc.mods.sodium.client.gui.widgets.FlatButtonWidget.Style; +import net.caffeinemc.mods.sodium.client.util.Dim2i; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphics; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/prompt/ScreenPromptable.java b/src/main/java/net/caffeinemc/mods/sodium/client/gui/prompt/ScreenPromptable.java similarity index 65% rename from src/main/java/me/jellysquid/mods/sodium/client/gui/prompt/ScreenPromptable.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gui/prompt/ScreenPromptable.java index b791fd8379..b16e0cad54 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/prompt/ScreenPromptable.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gui/prompt/ScreenPromptable.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.client.gui.prompt; +package net.caffeinemc.mods.sodium.client.gui.prompt; -import me.jellysquid.mods.sodium.client.util.Dim2i; +import net.caffeinemc.mods.sodium.client.util.Dim2i; import org.jetbrains.annotations.Nullable; public interface ScreenPromptable { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/screen/ConfigCorruptedScreen.java b/src/main/java/net/caffeinemc/mods/sodium/client/gui/screen/ConfigCorruptedScreen.java similarity index 92% rename from src/main/java/me/jellysquid/mods/sodium/client/gui/screen/ConfigCorruptedScreen.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gui/screen/ConfigCorruptedScreen.java index 9340b62c2d..4cdbbf00aa 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/screen/ConfigCorruptedScreen.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gui/screen/ConfigCorruptedScreen.java @@ -1,8 +1,8 @@ -package me.jellysquid.mods.sodium.client.gui.screen; +package net.caffeinemc.mods.sodium.client.gui.screen; -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import me.jellysquid.mods.sodium.client.gui.console.Console; -import me.jellysquid.mods.sodium.client.gui.console.message.MessageLevel; +import net.caffeinemc.mods.sodium.client.SodiumClientMod; +import net.caffeinemc.mods.sodium.client.gui.console.Console; +import net.caffeinemc.mods.sodium.client.gui.console.message.MessageLevel; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.Button; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/AbstractWidget.java b/src/main/java/net/caffeinemc/mods/sodium/client/gui/widgets/AbstractWidget.java similarity index 98% rename from src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/AbstractWidget.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gui/widgets/AbstractWidget.java index e18349d0d9..0bfee90fee 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/AbstractWidget.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gui/widgets/AbstractWidget.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.gui.widgets; +package net.caffeinemc.mods.sodium.client.gui.widgets; import net.minecraft.client.InputType; import net.minecraft.client.Minecraft; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/FlatButtonWidget.java b/src/main/java/net/caffeinemc/mods/sodium/client/gui/widgets/FlatButtonWidget.java similarity index 97% rename from src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/FlatButtonWidget.java rename to src/main/java/net/caffeinemc/mods/sodium/client/gui/widgets/FlatButtonWidget.java index ae3df5d623..359a66ffb6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/FlatButtonWidget.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/gui/widgets/FlatButtonWidget.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.client.gui.widgets; +package net.caffeinemc.mods.sodium.client.gui.widgets; -import me.jellysquid.mods.sodium.client.util.Dim2i; +import net.caffeinemc.mods.sodium.client.util.Dim2i; import net.minecraft.client.gui.ComponentPath; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.Renderable; diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/model/ModelCuboidAccessor.java b/src/main/java/net/caffeinemc/mods/sodium/client/model/ModelCuboidAccessor.java new file mode 100644 index 0000000000..c7aa736f20 --- /dev/null +++ b/src/main/java/net/caffeinemc/mods/sodium/client/model/ModelCuboidAccessor.java @@ -0,0 +1,7 @@ +package net.caffeinemc.mods.sodium.client.model; + +import net.caffeinemc.mods.sodium.client.render.immediate.model.ModelCuboid; + +public interface ModelCuboidAccessor { + ModelCuboid sodium$copy(); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/color/ColorProvider.java b/src/main/java/net/caffeinemc/mods/sodium/client/model/color/ColorProvider.java similarity index 79% rename from src/main/java/me/jellysquid/mods/sodium/client/model/color/ColorProvider.java rename to src/main/java/net/caffeinemc/mods/sodium/client/model/color/ColorProvider.java index a0f7262d94..dc259b0fa7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/color/ColorProvider.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/model/color/ColorProvider.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.client.model.color; +package net.caffeinemc.mods.sodium.client.model.color; -import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; -import me.jellysquid.mods.sodium.client.world.WorldSlice; +import net.caffeinemc.mods.sodium.client.model.quad.ModelQuadView; +import net.caffeinemc.mods.sodium.client.world.WorldSlice; import net.minecraft.core.BlockPos; public interface ColorProvider { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/color/ColorProviderRegistry.java b/src/main/java/net/caffeinemc/mods/sodium/client/model/color/ColorProviderRegistry.java similarity index 95% rename from src/main/java/me/jellysquid/mods/sodium/client/model/color/ColorProviderRegistry.java rename to src/main/java/net/caffeinemc/mods/sodium/client/model/color/ColorProviderRegistry.java index 138d9cd0d7..f1e418ab58 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/color/ColorProviderRegistry.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/model/color/ColorProviderRegistry.java @@ -1,10 +1,10 @@ -package me.jellysquid.mods.sodium.client.model.color; +package net.caffeinemc.mods.sodium.client.model.color; import it.unimi.dsi.fastutil.objects.Reference2ReferenceMap; import it.unimi.dsi.fastutil.objects.Reference2ReferenceMap.Entry; import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; import it.unimi.dsi.fastutil.objects.ReferenceSet; -import me.jellysquid.mods.sodium.client.model.color.interop.BlockColorsExtended; +import net.caffeinemc.mods.sodium.client.model.color.interop.BlockColorsExtended; import net.minecraft.client.color.block.BlockColors; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/color/DefaultColorProviders.java b/src/main/java/net/caffeinemc/mods/sodium/client/model/color/DefaultColorProviders.java similarity index 89% rename from src/main/java/me/jellysquid/mods/sodium/client/model/color/DefaultColorProviders.java rename to src/main/java/net/caffeinemc/mods/sodium/client/model/color/DefaultColorProviders.java index 19cba63f76..4725832842 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/color/DefaultColorProviders.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/model/color/DefaultColorProviders.java @@ -1,9 +1,9 @@ -package me.jellysquid.mods.sodium.client.model.color; +package net.caffeinemc.mods.sodium.client.model.color; -import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; -import me.jellysquid.mods.sodium.client.model.quad.blender.BlendedColorProvider; -import me.jellysquid.mods.sodium.client.world.biome.BiomeColorSource; -import me.jellysquid.mods.sodium.client.world.WorldSlice; +import net.caffeinemc.mods.sodium.client.model.quad.ModelQuadView; +import net.caffeinemc.mods.sodium.client.model.quad.blender.BlendedColorProvider; +import net.caffeinemc.mods.sodium.client.world.biome.BiomeColorSource; +import net.caffeinemc.mods.sodium.client.world.WorldSlice; import net.caffeinemc.mods.sodium.api.util.ColorARGB; import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandler; import net.minecraft.client.color.block.BlockColor; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/color/interop/BlockColorsExtended.java b/src/main/java/net/caffeinemc/mods/sodium/client/model/color/interop/BlockColorsExtended.java similarity index 92% rename from src/main/java/me/jellysquid/mods/sodium/client/model/color/interop/BlockColorsExtended.java rename to src/main/java/net/caffeinemc/mods/sodium/client/model/color/interop/BlockColorsExtended.java index 922d8676ac..c7c6097171 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/color/interop/BlockColorsExtended.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/model/color/interop/BlockColorsExtended.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.model.color.interop; +package net.caffeinemc.mods.sodium.client.model.color.interop; import it.unimi.dsi.fastutil.objects.Reference2ReferenceMap; import it.unimi.dsi.fastutil.objects.ReferenceSet; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/color/interop/ItemColorsExtended.java b/src/main/java/net/caffeinemc/mods/sodium/client/model/color/interop/ItemColorsExtended.java similarity index 75% rename from src/main/java/me/jellysquid/mods/sodium/client/model/color/interop/ItemColorsExtended.java rename to src/main/java/net/caffeinemc/mods/sodium/client/model/color/interop/ItemColorsExtended.java index b7d9e0d6a1..2eaffbceed 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/color/interop/ItemColorsExtended.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/model/color/interop/ItemColorsExtended.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.model.color.interop; +package net.caffeinemc.mods.sodium.client.model.color.interop; import net.minecraft.client.color.item.ItemColor; import net.minecraft.world.item.ItemStack; diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/model/light/LightMode.java b/src/main/java/net/caffeinemc/mods/sodium/client/model/light/LightMode.java new file mode 100644 index 0000000000..e7f9733b0d --- /dev/null +++ b/src/main/java/net/caffeinemc/mods/sodium/client/model/light/LightMode.java @@ -0,0 +1,6 @@ +package net.caffeinemc.mods.sodium.client.model.light; + +public enum LightMode { + SMOOTH, + FLAT +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/LightPipeline.java b/src/main/java/net/caffeinemc/mods/sodium/client/model/light/LightPipeline.java similarity index 81% rename from src/main/java/me/jellysquid/mods/sodium/client/model/light/LightPipeline.java rename to src/main/java/net/caffeinemc/mods/sodium/client/model/light/LightPipeline.java index fb091e1f72..3aebb6f090 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/LightPipeline.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/model/light/LightPipeline.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.client.model.light; +package net.caffeinemc.mods.sodium.client.model.light; -import me.jellysquid.mods.sodium.client.model.light.data.QuadLightData; -import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; +import net.caffeinemc.mods.sodium.client.model.light.data.QuadLightData; +import net.caffeinemc.mods.sodium.client.model.quad.ModelQuadView; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/LightPipelineProvider.java b/src/main/java/net/caffeinemc/mods/sodium/client/model/light/LightPipelineProvider.java similarity index 69% rename from src/main/java/me/jellysquid/mods/sodium/client/model/light/LightPipelineProvider.java rename to src/main/java/net/caffeinemc/mods/sodium/client/model/light/LightPipelineProvider.java index 49fb741888..3aef424469 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/LightPipelineProvider.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/model/light/LightPipelineProvider.java @@ -1,8 +1,8 @@ -package me.jellysquid.mods.sodium.client.model.light; +package net.caffeinemc.mods.sodium.client.model.light; -import me.jellysquid.mods.sodium.client.model.light.data.LightDataAccess; -import me.jellysquid.mods.sodium.client.model.light.flat.FlatLightPipeline; -import me.jellysquid.mods.sodium.client.model.light.smooth.SmoothLightPipeline; +import net.caffeinemc.mods.sodium.client.model.light.data.LightDataAccess; +import net.caffeinemc.mods.sodium.client.model.light.flat.FlatLightPipeline; +import net.caffeinemc.mods.sodium.client.model.light.smooth.SmoothLightPipeline; import java.util.EnumMap; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/ArrayLightDataCache.java b/src/main/java/net/caffeinemc/mods/sodium/client/model/light/data/ArrayLightDataCache.java similarity index 93% rename from src/main/java/me/jellysquid/mods/sodium/client/model/light/data/ArrayLightDataCache.java rename to src/main/java/net/caffeinemc/mods/sodium/client/model/light/data/ArrayLightDataCache.java index a9f3ae4ba6..1d7000109d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/ArrayLightDataCache.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/model/light/data/ArrayLightDataCache.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.client.model.light.data; +package net.caffeinemc.mods.sodium.client.model.light.data; -import me.jellysquid.mods.sodium.client.world.WorldSlice; +import net.caffeinemc.mods.sodium.client.world.WorldSlice; import net.minecraft.core.SectionPos; import net.minecraft.world.level.BlockAndTintGetter; import java.util.Arrays; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/HashLightDataCache.java b/src/main/java/net/caffeinemc/mods/sodium/client/model/light/data/HashLightDataCache.java similarity index 93% rename from src/main/java/me/jellysquid/mods/sodium/client/model/light/data/HashLightDataCache.java rename to src/main/java/net/caffeinemc/mods/sodium/client/model/light/data/HashLightDataCache.java index 47b03df67c..0ff39e549f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/HashLightDataCache.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/model/light/data/HashLightDataCache.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.model.light.data; +package net.caffeinemc.mods.sodium.client.model.light.data; import it.unimi.dsi.fastutil.longs.Long2IntLinkedOpenHashMap; import net.minecraft.core.BlockPos; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/LightDataAccess.java b/src/main/java/net/caffeinemc/mods/sodium/client/model/light/data/LightDataAccess.java similarity index 99% rename from src/main/java/me/jellysquid/mods/sodium/client/model/light/data/LightDataAccess.java rename to src/main/java/net/caffeinemc/mods/sodium/client/model/light/data/LightDataAccess.java index 9c1ba0e512..460c48d2fc 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/LightDataAccess.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/model/light/data/LightDataAccess.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.model.light.data; +package net.caffeinemc.mods.sodium.client.model.light.data; import net.minecraft.client.renderer.LevelRenderer; import net.minecraft.client.renderer.LightTexture; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/QuadLightData.java b/src/main/java/net/caffeinemc/mods/sodium/client/model/light/data/QuadLightData.java similarity index 87% rename from src/main/java/me/jellysquid/mods/sodium/client/model/light/data/QuadLightData.java rename to src/main/java/net/caffeinemc/mods/sodium/client/model/light/data/QuadLightData.java index 1342e1dcf3..99c5dc1407 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/QuadLightData.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/model/light/data/QuadLightData.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.model.light.data; +package net.caffeinemc.mods.sodium.client.model.light.data; /** * Stores the computed light data for a block model quad. The vertex order of each array is defined as that of the diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/flat/FlatLightPipeline.java b/src/main/java/net/caffeinemc/mods/sodium/client/model/light/flat/FlatLightPipeline.java similarity index 84% rename from src/main/java/me/jellysquid/mods/sodium/client/model/light/flat/FlatLightPipeline.java rename to src/main/java/net/caffeinemc/mods/sodium/client/model/light/flat/FlatLightPipeline.java index 134ee5799e..8564545730 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/flat/FlatLightPipeline.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/model/light/flat/FlatLightPipeline.java @@ -1,10 +1,10 @@ -package me.jellysquid.mods.sodium.client.model.light.flat; +package net.caffeinemc.mods.sodium.client.model.light.flat; -import me.jellysquid.mods.sodium.client.model.light.LightPipeline; -import me.jellysquid.mods.sodium.client.model.light.data.LightDataAccess; -import me.jellysquid.mods.sodium.client.model.light.data.QuadLightData; -import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFlags; +import net.caffeinemc.mods.sodium.client.model.light.LightPipeline; +import net.caffeinemc.mods.sodium.client.model.light.data.LightDataAccess; +import net.caffeinemc.mods.sodium.client.model.light.data.QuadLightData; +import net.caffeinemc.mods.sodium.client.model.quad.ModelQuadView; +import net.caffeinemc.mods.sodium.client.model.quad.properties.ModelQuadFlags; import net.minecraft.client.renderer.LevelRenderer; import net.minecraft.client.renderer.LightTexture; import net.minecraft.core.BlockPos; @@ -13,7 +13,7 @@ import net.minecraft.world.level.block.state.BlockState; import java.util.Arrays; -import static me.jellysquid.mods.sodium.client.model.light.data.LightDataAccess.*; +import static net.caffeinemc.mods.sodium.client.model.light.data.LightDataAccess.*; /** * A light pipeline which implements "classic-style" lighting through simply using the light value of the adjacent diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoCompletionFlags.java b/src/main/java/net/caffeinemc/mods/sodium/client/model/light/smooth/AoCompletionFlags.java similarity index 86% rename from src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoCompletionFlags.java rename to src/main/java/net/caffeinemc/mods/sodium/client/model/light/smooth/AoCompletionFlags.java index 4dd78bcc4e..cbf469ee1c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoCompletionFlags.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/model/light/smooth/AoCompletionFlags.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.model.light.smooth; +package net.caffeinemc.mods.sodium.client.model.light.smooth; /** * Bit flags to indicate which light properties have been computed for a given face. diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoFaceData.java b/src/main/java/net/caffeinemc/mods/sodium/client/model/light/smooth/AoFaceData.java similarity index 97% rename from src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoFaceData.java rename to src/main/java/net/caffeinemc/mods/sodium/client/model/light/smooth/AoFaceData.java index 5ec8df8a00..13a3129882 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoFaceData.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/model/light/smooth/AoFaceData.java @@ -1,11 +1,11 @@ -package me.jellysquid.mods.sodium.client.model.light.smooth; +package net.caffeinemc.mods.sodium.client.model.light.smooth; -import me.jellysquid.mods.sodium.client.model.light.data.LightDataAccess; +import net.caffeinemc.mods.sodium.client.model.light.data.LightDataAccess; import net.minecraft.client.renderer.LightTexture; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; -import static me.jellysquid.mods.sodium.client.model.light.data.ArrayLightDataCache.*; +import static net.caffeinemc.mods.sodium.client.model.light.data.ArrayLightDataCache.*; class AoFaceData { public final int[] lm = new int[4]; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoNeighborInfo.java b/src/main/java/net/caffeinemc/mods/sodium/client/model/light/smooth/AoNeighborInfo.java similarity index 99% rename from src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoNeighborInfo.java rename to src/main/java/net/caffeinemc/mods/sodium/client/model/light/smooth/AoNeighborInfo.java index 372f6a1920..61b83f37d6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoNeighborInfo.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/model/light/smooth/AoNeighborInfo.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.model.light.smooth; +package net.caffeinemc.mods.sodium.client.model.light.smooth; import net.minecraft.core.Direction; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/SmoothLightPipeline.java b/src/main/java/net/caffeinemc/mods/sodium/client/model/light/smooth/SmoothLightPipeline.java similarity index 96% rename from src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/SmoothLightPipeline.java rename to src/main/java/net/caffeinemc/mods/sodium/client/model/light/smooth/SmoothLightPipeline.java index abedf92c57..f9a3fe9168 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/SmoothLightPipeline.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/model/light/smooth/SmoothLightPipeline.java @@ -1,10 +1,10 @@ -package me.jellysquid.mods.sodium.client.model.light.smooth; +package net.caffeinemc.mods.sodium.client.model.light.smooth; -import me.jellysquid.mods.sodium.client.model.light.LightPipeline; -import me.jellysquid.mods.sodium.client.model.light.data.LightDataAccess; -import me.jellysquid.mods.sodium.client.model.light.data.QuadLightData; -import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFlags; +import net.caffeinemc.mods.sodium.client.model.light.LightPipeline; +import net.caffeinemc.mods.sodium.client.model.light.data.LightDataAccess; +import net.caffeinemc.mods.sodium.client.model.light.data.QuadLightData; +import net.caffeinemc.mods.sodium.client.model.quad.ModelQuadView; +import net.caffeinemc.mods.sodium.client.model.quad.properties.ModelQuadFlags; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.util.Mth; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/BakedQuadView.java b/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/BakedQuadView.java similarity index 51% rename from src/main/java/me/jellysquid/mods/sodium/client/model/quad/BakedQuadView.java rename to src/main/java/net/caffeinemc/mods/sodium/client/model/quad/BakedQuadView.java index 499acca1a3..b95ee43fa2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/BakedQuadView.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/BakedQuadView.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.client.model.quad; +package net.caffeinemc.mods.sodium.client.model.quad; -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import net.caffeinemc.mods.sodium.client.model.quad.properties.ModelQuadFacing; public interface BakedQuadView extends ModelQuadView { ModelQuadFacing getNormalFace(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuad.java b/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/ModelQuad.java similarity index 96% rename from src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuad.java rename to src/main/java/net/caffeinemc/mods/sodium/client/model/quad/ModelQuad.java index 8318e45425..f34bea060e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuad.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/ModelQuad.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.client.model.quad; +package net.caffeinemc.mods.sodium.client.model.quad; -import static me.jellysquid.mods.sodium.client.util.ModelQuadUtil.*; +import static net.caffeinemc.mods.sodium.client.util.ModelQuadUtil.*; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.core.Direction; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java b/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/ModelQuadView.java similarity index 95% rename from src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java rename to src/main/java/net/caffeinemc/mods/sodium/client/model/quad/ModelQuadView.java index 9053a8b6d7..fb0a0ee88b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/ModelQuadView.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.client.model.quad; +package net.caffeinemc.mods.sodium.client.model.quad; -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFlags; +import net.caffeinemc.mods.sodium.client.model.quad.properties.ModelQuadFlags; import net.caffeinemc.mods.sodium.api.util.NormI8; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.core.Direction; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadViewMutable.java b/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/ModelQuadViewMutable.java similarity index 92% rename from src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadViewMutable.java rename to src/main/java/net/caffeinemc/mods/sodium/client/model/quad/ModelQuadViewMutable.java index dab620471a..13d0345481 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadViewMutable.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/ModelQuadViewMutable.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.client.model.quad; +package net.caffeinemc.mods.sodium.client.model.quad; -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFlags; +import net.caffeinemc.mods.sodium.client.model.quad.properties.ModelQuadFlags; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.core.Direction; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/BlendedColorProvider.java b/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/blender/BlendedColorProvider.java similarity index 90% rename from src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/BlendedColorProvider.java rename to src/main/java/net/caffeinemc/mods/sodium/client/model/quad/blender/BlendedColorProvider.java index 805eddc3da..c0897f5c3a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/BlendedColorProvider.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/blender/BlendedColorProvider.java @@ -1,8 +1,8 @@ -package me.jellysquid.mods.sodium.client.model.quad.blender; +package net.caffeinemc.mods.sodium.client.model.quad.blender; -import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; -import me.jellysquid.mods.sodium.client.model.color.ColorProvider; -import me.jellysquid.mods.sodium.client.world.WorldSlice; +import net.caffeinemc.mods.sodium.client.model.quad.ModelQuadView; +import net.caffeinemc.mods.sodium.client.model.color.ColorProvider; +import net.caffeinemc.mods.sodium.client.world.WorldSlice; import net.caffeinemc.mods.sodium.api.util.ColorARGB; import net.caffeinemc.mods.sodium.api.util.ColorMixer; import net.minecraft.core.BlockPos; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java b/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/properties/ModelQuadFacing.java similarity index 96% rename from src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java rename to src/main/java/net/caffeinemc/mods/sodium/client/model/quad/properties/ModelQuadFacing.java index 9c736e65b7..0f1241649f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/properties/ModelQuadFacing.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.client.model.quad.properties; +package net.caffeinemc.mods.sodium.client.model.quad.properties; -import me.jellysquid.mods.sodium.client.util.DirectionUtil; +import net.caffeinemc.mods.sodium.client.util.DirectionUtil; import net.caffeinemc.mods.sodium.api.util.NormI8; import net.minecraft.core.Direction; import net.minecraft.util.Mth; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFlags.java b/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/properties/ModelQuadFlags.java similarity index 95% rename from src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFlags.java rename to src/main/java/net/caffeinemc/mods/sodium/client/model/quad/properties/ModelQuadFlags.java index 08f3ad02b8..6b46654731 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFlags.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/properties/ModelQuadFlags.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.client.model.quad.properties; +package net.caffeinemc.mods.sodium.client.model.quad.properties; -import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; +import net.caffeinemc.mods.sodium.client.model.quad.ModelQuadView; import net.minecraft.core.Direction; public class ModelQuadFlags { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadOrientation.java b/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/properties/ModelQuadOrientation.java similarity index 95% rename from src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadOrientation.java rename to src/main/java/net/caffeinemc/mods/sodium/client/model/quad/properties/ModelQuadOrientation.java index 50c7ae3de4..21e5c6121f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadOrientation.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/properties/ModelQuadOrientation.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.model.quad.properties; +package net.caffeinemc.mods.sodium.client.model.quad.properties; /** * Defines the orientation of vertices in a model quad. This information be used to re-orient the quad's vertices to a diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadWinding.java b/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/properties/ModelQuadWinding.java similarity index 82% rename from src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadWinding.java rename to src/main/java/net/caffeinemc/mods/sodium/client/model/quad/properties/ModelQuadWinding.java index 311b841a85..d77e63b60b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadWinding.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/properties/ModelQuadWinding.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.model.quad.properties; +package net.caffeinemc.mods.sodium.client.model.quad.properties; public enum ModelQuadWinding { CLOCKWISE(new int[] { 0, 1, 2, 2, 3, 0 }), diff --git a/src/main/java/me/jellysquid/mods/sodium/client/platform/MessageBox.java b/src/main/java/net/caffeinemc/mods/sodium/client/platform/MessageBox.java similarity index 92% rename from src/main/java/me/jellysquid/mods/sodium/client/platform/MessageBox.java rename to src/main/java/net/caffeinemc/mods/sodium/client/platform/MessageBox.java index a29f7b9cae..0c092bd203 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/platform/MessageBox.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/platform/MessageBox.java @@ -1,9 +1,9 @@ -package me.jellysquid.mods.sodium.client.platform; +package net.caffeinemc.mods.sodium.client.platform; -import me.jellysquid.mods.sodium.client.platform.windows.api.msgbox.MsgBoxParamSw; +import net.caffeinemc.mods.sodium.client.platform.windows.api.msgbox.MsgBoxParamSw; import net.minecraft.Util; -import me.jellysquid.mods.sodium.client.platform.windows.api.msgbox.MsgBoxCallback; -import me.jellysquid.mods.sodium.client.platform.windows.api.User32; +import net.caffeinemc.mods.sodium.client.platform.windows.api.msgbox.MsgBoxCallback; +import net.caffeinemc.mods.sodium.client.platform.windows.api.User32; import org.jetbrains.annotations.Nullable; import org.lwjgl.glfw.GLFWNativeWin32; import org.lwjgl.system.MemoryStack; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/platform/unix/Libc.java b/src/main/java/net/caffeinemc/mods/sodium/client/platform/unix/Libc.java similarity index 92% rename from src/main/java/me/jellysquid/mods/sodium/client/platform/unix/Libc.java rename to src/main/java/net/caffeinemc/mods/sodium/client/platform/unix/Libc.java index db64bb69e0..b821a5df7c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/platform/unix/Libc.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/platform/unix/Libc.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.platform.unix; +package net.caffeinemc.mods.sodium.client.platform.unix; import java.nio.ByteBuffer; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/platform/windows/WindowsCommandLine.java b/src/main/java/net/caffeinemc/mods/sodium/client/platform/windows/WindowsCommandLine.java similarity index 96% rename from src/main/java/me/jellysquid/mods/sodium/client/platform/windows/WindowsCommandLine.java rename to src/main/java/net/caffeinemc/mods/sodium/client/platform/windows/WindowsCommandLine.java index 9d223b2e17..3165ad6d1e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/platform/windows/WindowsCommandLine.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/platform/windows/WindowsCommandLine.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.client.platform.windows; +package net.caffeinemc.mods.sodium.client.platform.windows; -import me.jellysquid.mods.sodium.client.platform.windows.api.Kernel32; +import net.caffeinemc.mods.sodium.client.platform.windows.api.Kernel32; import org.lwjgl.system.MemoryUtil; import java.nio.BufferOverflowException; import java.nio.ByteBuffer; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/platform/windows/WindowsDriverStoreVersion.java b/src/main/java/net/caffeinemc/mods/sodium/client/platform/windows/WindowsDriverStoreVersion.java similarity index 95% rename from src/main/java/me/jellysquid/mods/sodium/client/platform/windows/WindowsDriverStoreVersion.java rename to src/main/java/net/caffeinemc/mods/sodium/client/platform/windows/WindowsDriverStoreVersion.java index eecda4add6..db04a573f1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/platform/windows/WindowsDriverStoreVersion.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/platform/windows/WindowsDriverStoreVersion.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.platform.windows; +package net.caffeinemc.mods.sodium.client.platform.windows; import java.util.regex.Matcher; import java.util.regex.Pattern; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/platform/windows/api/Kernel32.java b/src/main/java/net/caffeinemc/mods/sodium/client/platform/windows/api/Kernel32.java similarity index 98% rename from src/main/java/me/jellysquid/mods/sodium/client/platform/windows/api/Kernel32.java rename to src/main/java/net/caffeinemc/mods/sodium/client/platform/windows/api/Kernel32.java index 072d8f7994..86ed38e56a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/platform/windows/api/Kernel32.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/platform/windows/api/Kernel32.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.platform.windows.api; +package net.caffeinemc.mods.sodium.client.platform.windows.api; import org.jetbrains.annotations.Nullable; import org.lwjgl.PointerBuffer; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/platform/windows/api/User32.java b/src/main/java/net/caffeinemc/mods/sodium/client/platform/windows/api/User32.java similarity index 82% rename from src/main/java/me/jellysquid/mods/sodium/client/platform/windows/api/User32.java rename to src/main/java/net/caffeinemc/mods/sodium/client/platform/windows/api/User32.java index d4892a5249..d20b4c26a5 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/platform/windows/api/User32.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/platform/windows/api/User32.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.client.platform.windows.api; +package net.caffeinemc.mods.sodium.client.platform.windows.api; -import me.jellysquid.mods.sodium.client.platform.windows.api.msgbox.MsgBoxParamSw; +import net.caffeinemc.mods.sodium.client.platform.windows.api.msgbox.MsgBoxParamSw; import org.lwjgl.system.APIUtil; import org.lwjgl.system.JNI; import org.lwjgl.system.Library; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/platform/windows/api/msgbox/MsgBoxCallback.java b/src/main/java/net/caffeinemc/mods/sodium/client/platform/windows/api/msgbox/MsgBoxCallback.java similarity index 92% rename from src/main/java/me/jellysquid/mods/sodium/client/platform/windows/api/msgbox/MsgBoxCallback.java rename to src/main/java/net/caffeinemc/mods/sodium/client/platform/windows/api/msgbox/MsgBoxCallback.java index ab8388c0e0..c7634b3c7f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/platform/windows/api/msgbox/MsgBoxCallback.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/platform/windows/api/msgbox/MsgBoxCallback.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.platform.windows.api.msgbox; +package net.caffeinemc.mods.sodium.client.platform.windows.api.msgbox; import org.lwjgl.system.Callback; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/platform/windows/api/msgbox/MsgBoxCallbackI.java b/src/main/java/net/caffeinemc/mods/sodium/client/platform/windows/api/msgbox/MsgBoxCallbackI.java similarity index 92% rename from src/main/java/me/jellysquid/mods/sodium/client/platform/windows/api/msgbox/MsgBoxCallbackI.java rename to src/main/java/net/caffeinemc/mods/sodium/client/platform/windows/api/msgbox/MsgBoxCallbackI.java index cebd949822..0994026e18 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/platform/windows/api/msgbox/MsgBoxCallbackI.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/platform/windows/api/msgbox/MsgBoxCallbackI.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.platform.windows.api.msgbox; +package net.caffeinemc.mods.sodium.client.platform.windows.api.msgbox; import org.jetbrains.annotations.NotNull; import org.lwjgl.system.CallbackI; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/platform/windows/api/msgbox/MsgBoxParamSw.java b/src/main/java/net/caffeinemc/mods/sodium/client/platform/windows/api/msgbox/MsgBoxParamSw.java similarity index 97% rename from src/main/java/me/jellysquid/mods/sodium/client/platform/windows/api/msgbox/MsgBoxParamSw.java rename to src/main/java/net/caffeinemc/mods/sodium/client/platform/windows/api/msgbox/MsgBoxParamSw.java index 2ac7349c70..0eff5fb40a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/platform/windows/api/msgbox/MsgBoxParamSw.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/platform/windows/api/msgbox/MsgBoxParamSw.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.platform.windows.api.msgbox; +package net.caffeinemc.mods.sodium.client.platform.windows.api.msgbox; import org.jetbrains.annotations.Nullable; import org.lwjgl.system.MemoryStack; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/platform/windows/api/version/LanguageCodePage.java b/src/main/java/net/caffeinemc/mods/sodium/client/platform/windows/api/version/LanguageCodePage.java similarity index 85% rename from src/main/java/me/jellysquid/mods/sodium/client/platform/windows/api/version/LanguageCodePage.java rename to src/main/java/net/caffeinemc/mods/sodium/client/platform/windows/api/version/LanguageCodePage.java index 27fa38e395..9debe2adb9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/platform/windows/api/version/LanguageCodePage.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/platform/windows/api/version/LanguageCodePage.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.platform.windows.api.version; +package net.caffeinemc.mods.sodium.client.platform.windows.api.version; import org.lwjgl.system.MemoryUtil; diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/platform/windows/api/version/QueryResult.java b/src/main/java/net/caffeinemc/mods/sodium/client/platform/windows/api/version/QueryResult.java new file mode 100644 index 0000000000..c9dbf18c78 --- /dev/null +++ b/src/main/java/net/caffeinemc/mods/sodium/client/platform/windows/api/version/QueryResult.java @@ -0,0 +1,4 @@ +package net.caffeinemc.mods.sodium.client.platform.windows.api.version; + +public record QueryResult(long address, int length) { +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/platform/windows/api/version/Version.java b/src/main/java/net/caffeinemc/mods/sodium/client/platform/windows/api/version/Version.java similarity index 95% rename from src/main/java/me/jellysquid/mods/sodium/client/platform/windows/api/version/Version.java rename to src/main/java/net/caffeinemc/mods/sodium/client/platform/windows/api/version/Version.java index 1151edd12c..ea7c10b339 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/platform/windows/api/version/Version.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/platform/windows/api/version/Version.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.client.platform.windows.api.version; +package net.caffeinemc.mods.sodium.client.platform.windows.api.version; -import me.jellysquid.mods.sodium.client.platform.windows.api.Kernel32; +import net.caffeinemc.mods.sodium.client.platform.windows.api.Kernel32; import org.jetbrains.annotations.Nullable; import org.lwjgl.PointerBuffer; import org.lwjgl.system.*; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/platform/windows/api/version/VersionInfo.java b/src/main/java/net/caffeinemc/mods/sodium/client/platform/windows/api/version/VersionInfo.java similarity index 96% rename from src/main/java/me/jellysquid/mods/sodium/client/platform/windows/api/version/VersionInfo.java rename to src/main/java/net/caffeinemc/mods/sodium/client/platform/windows/api/version/VersionInfo.java index ea277b508d..3fb1bea854 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/platform/windows/api/version/VersionInfo.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/platform/windows/api/version/VersionInfo.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.platform.windows.api.version; +package net.caffeinemc.mods.sodium.client.platform.windows.api.version; import org.jetbrains.annotations.Nullable; import org.lwjgl.system.MemoryUtil; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/SodiumWorldRenderer.java similarity index 93% rename from src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/SodiumWorldRenderer.java index d690bb13f8..31738fafbc 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/SodiumWorldRenderer.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render; +package net.caffeinemc.mods.sodium.client.render; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; @@ -6,23 +6,23 @@ import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.blaze3d.vertex.VertexMultiConsumer; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import me.jellysquid.mods.sodium.client.gl.device.CommandList; -import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; -import me.jellysquid.mods.sodium.client.render.chunk.ChunkRenderMatrices; -import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; -import me.jellysquid.mods.sodium.client.render.chunk.RenderSectionManager; -import me.jellysquid.mods.sodium.client.render.chunk.lists.ChunkRenderList; -import me.jellysquid.mods.sodium.client.render.chunk.lists.SortedRenderLists; -import me.jellysquid.mods.sodium.client.render.chunk.map.ChunkTracker; -import me.jellysquid.mods.sodium.client.render.chunk.map.ChunkTrackerHolder; -import me.jellysquid.mods.sodium.client.render.chunk.region.RenderRegion; -import me.jellysquid.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger.CameraMovement; -import me.jellysquid.mods.sodium.client.render.viewport.Viewport; -import me.jellysquid.mods.sodium.client.util.NativeBuffer; -import me.jellysquid.mods.sodium.client.util.iterator.ByteIterator; -import me.jellysquid.mods.sodium.client.world.WorldRendererExtended; +import net.caffeinemc.mods.sodium.client.SodiumClientMod; +import net.caffeinemc.mods.sodium.client.gl.device.CommandList; +import net.caffeinemc.mods.sodium.client.gl.device.RenderDevice; +import net.caffeinemc.mods.sodium.client.render.chunk.ChunkRenderMatrices; +import net.caffeinemc.mods.sodium.client.render.chunk.RenderSection; +import net.caffeinemc.mods.sodium.client.render.chunk.RenderSectionManager; +import net.caffeinemc.mods.sodium.client.render.chunk.lists.ChunkRenderList; +import net.caffeinemc.mods.sodium.client.render.chunk.lists.SortedRenderLists; +import net.caffeinemc.mods.sodium.client.render.chunk.map.ChunkTracker; +import net.caffeinemc.mods.sodium.client.render.chunk.map.ChunkTrackerHolder; +import net.caffeinemc.mods.sodium.client.render.chunk.region.RenderRegion; +import net.caffeinemc.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.trigger.CameraMovement; +import net.caffeinemc.mods.sodium.client.render.viewport.Viewport; +import net.caffeinemc.mods.sodium.client.util.NativeBuffer; +import net.caffeinemc.mods.sodium.client.util.iterator.ByteIterator; +import net.caffeinemc.mods.sodium.client.world.WorldRendererExtended; import net.minecraft.client.Camera; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientLevel; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderMatrices.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/ChunkRenderMatrices.java similarity index 89% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderMatrices.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/ChunkRenderMatrices.java index 8fcb9d4f7c..108353f5f1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderMatrices.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/ChunkRenderMatrices.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk; +package net.caffeinemc.mods.sodium.client.render.chunk; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderer.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/ChunkRenderer.java similarity index 73% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderer.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/ChunkRenderer.java index e8621226ed..2db8a0bc9c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderer.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/ChunkRenderer.java @@ -1,9 +1,9 @@ -package me.jellysquid.mods.sodium.client.render.chunk; +package net.caffeinemc.mods.sodium.client.render.chunk; -import me.jellysquid.mods.sodium.client.gl.device.CommandList; -import me.jellysquid.mods.sodium.client.render.chunk.lists.ChunkRenderListIterable; -import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; -import me.jellysquid.mods.sodium.client.render.viewport.CameraTransform; +import net.caffeinemc.mods.sodium.client.gl.device.CommandList; +import net.caffeinemc.mods.sodium.client.render.chunk.lists.ChunkRenderListIterable; +import net.caffeinemc.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; +import net.caffeinemc.mods.sodium.client.render.viewport.CameraTransform; /** * The chunk render backend takes care of managing the graphics resource state of chunk render containers. This includes diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkUpdateType.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/ChunkUpdateType.java similarity index 89% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkUpdateType.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/ChunkUpdateType.java index 262a2d8a35..2cd7859716 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkUpdateType.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/ChunkUpdateType.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.client.render.chunk; +package net.caffeinemc.mods.sodium.client.render.chunk; -import me.jellysquid.mods.sodium.client.render.chunk.compile.executor.ChunkBuilder; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.executor.ChunkBuilder; public enum ChunkUpdateType { SORT(Integer.MAX_VALUE, ChunkBuilder.LOW_EFFORT), diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/DefaultChunkRenderer.java similarity index 85% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/DefaultChunkRenderer.java index abb5189b62..2ddccba42d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/DefaultChunkRenderer.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/DefaultChunkRenderer.java @@ -1,32 +1,32 @@ -package me.jellysquid.mods.sodium.client.render.chunk; - -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexAttributeBinding; -import me.jellysquid.mods.sodium.client.gl.device.CommandList; -import me.jellysquid.mods.sodium.client.gl.device.DrawCommandList; -import me.jellysquid.mods.sodium.client.gl.device.MultiDrawBatch; -import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; -import me.jellysquid.mods.sodium.client.gl.tessellation.GlIndexType; -import me.jellysquid.mods.sodium.client.gl.tessellation.GlPrimitiveType; -import me.jellysquid.mods.sodium.client.gl.tessellation.GlTessellation; -import me.jellysquid.mods.sodium.client.gl.tessellation.TessellationBinding; -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; -import me.jellysquid.mods.sodium.client.render.chunk.data.SectionRenderDataStorage; -import me.jellysquid.mods.sodium.client.render.chunk.data.SectionRenderDataUnsafe; -import me.jellysquid.mods.sodium.client.render.chunk.lists.ChunkRenderListIterable; -import me.jellysquid.mods.sodium.client.render.chunk.lists.ChunkRenderList; -import me.jellysquid.mods.sodium.client.render.chunk.region.RenderRegion; -import me.jellysquid.mods.sodium.client.render.chunk.region.RenderRegion.DeviceResources; -import me.jellysquid.mods.sodium.client.render.chunk.shader.ChunkShaderBindingPoints; -import me.jellysquid.mods.sodium.client.render.chunk.shader.ChunkShaderInterface; -import me.jellysquid.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses; -import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortBehavior; -import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkMeshAttribute; -import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexType; -import me.jellysquid.mods.sodium.client.render.viewport.CameraTransform; -import me.jellysquid.mods.sodium.client.util.BitwiseMath; -import me.jellysquid.mods.sodium.client.util.iterator.ByteIterator; +package net.caffeinemc.mods.sodium.client.render.chunk; + +import net.caffeinemc.mods.sodium.client.SodiumClientMod; +import net.caffeinemc.mods.sodium.client.gl.attribute.GlVertexAttributeBinding; +import net.caffeinemc.mods.sodium.client.gl.device.CommandList; +import net.caffeinemc.mods.sodium.client.gl.device.DrawCommandList; +import net.caffeinemc.mods.sodium.client.gl.device.MultiDrawBatch; +import net.caffeinemc.mods.sodium.client.gl.device.RenderDevice; +import net.caffeinemc.mods.sodium.client.gl.tessellation.GlIndexType; +import net.caffeinemc.mods.sodium.client.gl.tessellation.GlPrimitiveType; +import net.caffeinemc.mods.sodium.client.gl.tessellation.GlTessellation; +import net.caffeinemc.mods.sodium.client.gl.tessellation.TessellationBinding; +import net.caffeinemc.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import net.caffeinemc.mods.sodium.client.render.chunk.data.SectionRenderDataStorage; +import net.caffeinemc.mods.sodium.client.render.chunk.data.SectionRenderDataUnsafe; +import net.caffeinemc.mods.sodium.client.render.chunk.lists.ChunkRenderListIterable; +import net.caffeinemc.mods.sodium.client.render.chunk.lists.ChunkRenderList; +import net.caffeinemc.mods.sodium.client.render.chunk.region.RenderRegion; +import net.caffeinemc.mods.sodium.client.render.chunk.region.RenderRegion.DeviceResources; +import net.caffeinemc.mods.sodium.client.render.chunk.shader.ChunkShaderBindingPoints; +import net.caffeinemc.mods.sodium.client.render.chunk.shader.ChunkShaderInterface; +import net.caffeinemc.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses; +import net.caffeinemc.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.SortBehavior; +import net.caffeinemc.mods.sodium.client.render.chunk.vertex.format.ChunkMeshAttribute; +import net.caffeinemc.mods.sodium.client.render.chunk.vertex.format.ChunkVertexType; +import net.caffeinemc.mods.sodium.client.render.viewport.CameraTransform; +import net.caffeinemc.mods.sodium.client.util.BitwiseMath; +import net.caffeinemc.mods.sodium.client.util.iterator.ByteIterator; import org.lwjgl.system.MemoryUtil; import java.util.Iterator; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/LocalSectionIndex.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/LocalSectionIndex.java similarity index 96% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/LocalSectionIndex.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/LocalSectionIndex.java index 21b03237ae..7737512410 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/LocalSectionIndex.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/LocalSectionIndex.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk; +package net.caffeinemc.mods.sodium.client.render.chunk; public class LocalSectionIndex { // XZY order diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/NonStoringBuilderPool.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/NonStoringBuilderPool.java similarity index 92% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/NonStoringBuilderPool.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/NonStoringBuilderPool.java index 360789b6fd..aa9d01f155 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/NonStoringBuilderPool.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/NonStoringBuilderPool.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk; +package net.caffeinemc.mods.sodium.client.render.chunk; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/RenderSection.java similarity index 94% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/RenderSection.java index 61188558a7..d4b3e0e8c6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSection.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/RenderSection.java @@ -1,12 +1,12 @@ -package me.jellysquid.mods.sodium.client.render.chunk; - -import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionInfo; -import me.jellysquid.mods.sodium.client.render.chunk.occlusion.GraphDirection; -import me.jellysquid.mods.sodium.client.render.chunk.occlusion.GraphDirectionSet; -import me.jellysquid.mods.sodium.client.render.chunk.occlusion.VisibilityEncoding; -import me.jellysquid.mods.sodium.client.render.chunk.region.RenderRegion; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; -import me.jellysquid.mods.sodium.client.util.task.CancellationToken; +package net.caffeinemc.mods.sodium.client.render.chunk; + +import net.caffeinemc.mods.sodium.client.render.chunk.data.BuiltSectionInfo; +import net.caffeinemc.mods.sodium.client.render.chunk.occlusion.GraphDirection; +import net.caffeinemc.mods.sodium.client.render.chunk.occlusion.GraphDirectionSet; +import net.caffeinemc.mods.sodium.client.render.chunk.occlusion.VisibilityEncoding; +import net.caffeinemc.mods.sodium.client.render.chunk.region.RenderRegion; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; +import net.caffeinemc.mods.sodium.client.util.task.CancellationToken; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionFlags.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/RenderSectionFlags.java similarity index 81% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionFlags.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/RenderSectionFlags.java index 5177a7af96..cb19504069 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionFlags.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/RenderSectionFlags.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk; +package net.caffeinemc.mods.sodium.client.render.chunk; public class RenderSectionFlags { public static final int HAS_BLOCK_GEOMETRY = 0; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/RenderSectionManager.java similarity index 89% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/RenderSectionManager.java index 90f0f65ad3..b39c262c76 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk; +package net.caffeinemc.mods.sodium.client.render.chunk; import com.mojang.blaze3d.systems.RenderSystem; import it.unimi.dsi.fastutil.longs.Long2ReferenceMap; @@ -8,43 +8,43 @@ import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; import it.unimi.dsi.fastutil.objects.ReferenceSet; import it.unimi.dsi.fastutil.objects.ReferenceSets; -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import me.jellysquid.mods.sodium.client.gl.device.CommandList; -import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; -import me.jellysquid.mods.sodium.client.render.chunk.compile.BuilderTaskOutput; -import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildOutput; -import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkSortOutput; -import me.jellysquid.mods.sodium.client.render.chunk.compile.executor.ChunkBuilder; -import me.jellysquid.mods.sodium.client.render.chunk.compile.executor.ChunkJobCollector; -import me.jellysquid.mods.sodium.client.render.chunk.compile.executor.ChunkJobResult; -import me.jellysquid.mods.sodium.client.render.chunk.compile.tasks.ChunkBuilderMeshingTask; -import me.jellysquid.mods.sodium.client.render.chunk.compile.tasks.ChunkBuilderSortingTask; -import me.jellysquid.mods.sodium.client.render.chunk.compile.tasks.ChunkBuilderTask; -import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionInfo; -import me.jellysquid.mods.sodium.client.render.chunk.lists.ChunkRenderList; -import me.jellysquid.mods.sodium.client.render.chunk.lists.SortedRenderLists; -import me.jellysquid.mods.sodium.client.render.chunk.lists.VisibleChunkCollector; -import me.jellysquid.mods.sodium.client.render.chunk.occlusion.GraphDirection; -import me.jellysquid.mods.sodium.client.render.chunk.occlusion.OcclusionCuller; -import me.jellysquid.mods.sodium.client.render.chunk.region.RenderRegion; -import me.jellysquid.mods.sodium.client.render.chunk.region.RenderRegionManager; -import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortBehavior.DeferMode; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortBehavior.PriorityMode; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.NoData; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TopoSortDynamicData; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger.CameraMovement; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger.SortTriggering; -import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkMeshFormats; -import me.jellysquid.mods.sodium.client.render.texture.SpriteUtil; -import me.jellysquid.mods.sodium.client.render.util.RenderAsserts; -import me.jellysquid.mods.sodium.client.render.viewport.CameraTransform; -import me.jellysquid.mods.sodium.client.render.viewport.Viewport; -import me.jellysquid.mods.sodium.client.util.MathUtil; -import me.jellysquid.mods.sodium.client.world.WorldSlice; -import me.jellysquid.mods.sodium.client.world.cloned.ChunkRenderContext; -import me.jellysquid.mods.sodium.client.world.cloned.ClonedChunkSectionCache; +import net.caffeinemc.mods.sodium.client.SodiumClientMod; +import net.caffeinemc.mods.sodium.client.gl.device.CommandList; +import net.caffeinemc.mods.sodium.client.gl.device.RenderDevice; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.BuilderTaskOutput; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.ChunkBuildOutput; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.ChunkSortOutput; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.executor.ChunkBuilder; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.executor.ChunkJobCollector; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.executor.ChunkJobResult; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.tasks.ChunkBuilderMeshingTask; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.tasks.ChunkBuilderSortingTask; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.tasks.ChunkBuilderTask; +import net.caffeinemc.mods.sodium.client.render.chunk.data.BuiltSectionInfo; +import net.caffeinemc.mods.sodium.client.render.chunk.lists.ChunkRenderList; +import net.caffeinemc.mods.sodium.client.render.chunk.lists.SortedRenderLists; +import net.caffeinemc.mods.sodium.client.render.chunk.lists.VisibleChunkCollector; +import net.caffeinemc.mods.sodium.client.render.chunk.occlusion.GraphDirection; +import net.caffeinemc.mods.sodium.client.render.chunk.occlusion.OcclusionCuller; +import net.caffeinemc.mods.sodium.client.render.chunk.region.RenderRegion; +import net.caffeinemc.mods.sodium.client.render.chunk.region.RenderRegionManager; +import net.caffeinemc.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.SortBehavior.DeferMode; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.SortBehavior.PriorityMode; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data.NoData; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data.TopoSortDynamicData; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.trigger.CameraMovement; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.trigger.SortTriggering; +import net.caffeinemc.mods.sodium.client.render.chunk.vertex.format.ChunkMeshFormats; +import net.caffeinemc.mods.sodium.client.render.texture.SpriteUtil; +import net.caffeinemc.mods.sodium.client.render.util.RenderAsserts; +import net.caffeinemc.mods.sodium.client.render.viewport.CameraTransform; +import net.caffeinemc.mods.sodium.client.render.viewport.Viewport; +import net.caffeinemc.mods.sodium.client.util.MathUtil; +import net.caffeinemc.mods.sodium.client.world.WorldSlice; +import net.caffeinemc.mods.sodium.client.world.cloned.ChunkRenderContext; +import net.caffeinemc.mods.sodium.client.world.cloned.ClonedChunkSectionCache; import net.minecraft.client.Camera; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientLevel; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ShaderChunkRenderer.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/ShaderChunkRenderer.java similarity index 83% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ShaderChunkRenderer.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/ShaderChunkRenderer.java index 858c0df5b7..a3ba6221c7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ShaderChunkRenderer.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/ShaderChunkRenderer.java @@ -1,14 +1,14 @@ -package me.jellysquid.mods.sodium.client.render.chunk; +package net.caffeinemc.mods.sodium.client.render.chunk; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexFormat; -import me.jellysquid.mods.sodium.client.gl.device.CommandList; -import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; -import me.jellysquid.mods.sodium.client.gl.shader.*; -import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; -import me.jellysquid.mods.sodium.client.render.chunk.shader.*; -import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkMeshAttribute; -import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexType; +import net.caffeinemc.mods.sodium.client.gl.attribute.GlVertexFormat; +import net.caffeinemc.mods.sodium.client.gl.device.CommandList; +import net.caffeinemc.mods.sodium.client.gl.device.RenderDevice; +import net.caffeinemc.mods.sodium.client.gl.shader.*; +import net.caffeinemc.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; +import net.caffeinemc.mods.sodium.client.render.chunk.shader.*; +import net.caffeinemc.mods.sodium.client.render.chunk.vertex.format.ChunkMeshAttribute; +import net.caffeinemc.mods.sodium.client.render.chunk.vertex.format.ChunkVertexType; import net.minecraft.resources.ResourceLocation; import java.util.Map; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/SharedQuadIndexBuffer.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/SharedQuadIndexBuffer.java similarity index 89% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/SharedQuadIndexBuffer.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/SharedQuadIndexBuffer.java index 4c0036a235..bfc9baa8e4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/SharedQuadIndexBuffer.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/SharedQuadIndexBuffer.java @@ -1,13 +1,13 @@ -package me.jellysquid.mods.sodium.client.render.chunk; - -import me.jellysquid.mods.sodium.client.gl.buffer.GlBuffer; -import me.jellysquid.mods.sodium.client.gl.buffer.GlBufferMapFlags; -import me.jellysquid.mods.sodium.client.gl.buffer.GlBufferMapping; -import me.jellysquid.mods.sodium.client.gl.buffer.GlBufferUsage; -import me.jellysquid.mods.sodium.client.gl.buffer.GlMutableBuffer; -import me.jellysquid.mods.sodium.client.gl.device.CommandList; -import me.jellysquid.mods.sodium.client.gl.tessellation.GlIndexType; -import me.jellysquid.mods.sodium.client.gl.util.EnumBitField; +package net.caffeinemc.mods.sodium.client.render.chunk; + +import net.caffeinemc.mods.sodium.client.gl.buffer.GlBuffer; +import net.caffeinemc.mods.sodium.client.gl.buffer.GlBufferMapFlags; +import net.caffeinemc.mods.sodium.client.gl.buffer.GlBufferMapping; +import net.caffeinemc.mods.sodium.client.gl.buffer.GlBufferUsage; +import net.caffeinemc.mods.sodium.client.gl.buffer.GlMutableBuffer; +import net.caffeinemc.mods.sodium.client.gl.device.CommandList; +import net.caffeinemc.mods.sodium.client.gl.tessellation.GlIndexType; +import net.caffeinemc.mods.sodium.client.gl.util.EnumBitField; import java.nio.ByteBuffer; import java.nio.IntBuffer; import java.nio.ShortBuffer; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/BuilderTaskOutput.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/BuilderTaskOutput.java similarity index 81% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/BuilderTaskOutput.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/BuilderTaskOutput.java index 02cb4a1236..6eca395788 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/BuilderTaskOutput.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/BuilderTaskOutput.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.client.render.chunk.compile; +package net.caffeinemc.mods.sodium.client.render.chunk.compile; -import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; +import net.caffeinemc.mods.sodium.client.render.chunk.RenderSection; public abstract class BuilderTaskOutput { public final RenderSection render; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildBuffers.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/ChunkBuildBuffers.java similarity index 75% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildBuffers.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/ChunkBuildBuffers.java index 65bfad62d6..f7be0bee49 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildBuffers.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/ChunkBuildBuffers.java @@ -1,18 +1,18 @@ -package me.jellysquid.mods.sodium.client.render.chunk.compile; +package net.caffeinemc.mods.sodium.client.render.chunk.compile; import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; -import me.jellysquid.mods.sodium.client.gl.util.VertexRange; -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; -import me.jellysquid.mods.sodium.client.render.chunk.compile.buffers.BakedChunkModelBuilder; -import me.jellysquid.mods.sodium.client.render.chunk.compile.buffers.ChunkModelBuilder; -import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionInfo; -import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; -import me.jellysquid.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses; -import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; -import me.jellysquid.mods.sodium.client.render.chunk.terrain.material.Material; -import me.jellysquid.mods.sodium.client.render.chunk.vertex.builder.ChunkMeshBufferBuilder; -import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexType; -import me.jellysquid.mods.sodium.client.util.NativeBuffer; +import net.caffeinemc.mods.sodium.client.gl.util.VertexRange; +import net.caffeinemc.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.buffers.BakedChunkModelBuilder; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.buffers.ChunkModelBuilder; +import net.caffeinemc.mods.sodium.client.render.chunk.data.BuiltSectionInfo; +import net.caffeinemc.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; +import net.caffeinemc.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses; +import net.caffeinemc.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; +import net.caffeinemc.mods.sodium.client.render.chunk.terrain.material.Material; +import net.caffeinemc.mods.sodium.client.render.chunk.vertex.builder.ChunkMeshBufferBuilder; +import net.caffeinemc.mods.sodium.client.render.chunk.vertex.format.ChunkVertexType; +import net.caffeinemc.mods.sodium.client.util.NativeBuffer; import java.nio.ByteBuffer; import java.util.ArrayList; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildContext.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/ChunkBuildContext.java similarity index 72% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildContext.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/ChunkBuildContext.java index 54ce282db0..27ef6f1092 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildContext.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/ChunkBuildContext.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.client.render.chunk.compile; +package net.caffeinemc.mods.sodium.client.render.chunk.compile; -import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.BlockRenderCache; -import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexType; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.pipeline.BlockRenderCache; +import net.caffeinemc.mods.sodium.client.render.chunk.vertex.format.ChunkVertexType; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientLevel; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java similarity index 76% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java index b099540053..17f85cb392 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java @@ -1,11 +1,11 @@ -package me.jellysquid.mods.sodium.client.render.chunk.compile; +package net.caffeinemc.mods.sodium.client.render.chunk.compile; -import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; -import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.PresentTranslucentData; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; -import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; -import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionInfo; +import net.caffeinemc.mods.sodium.client.render.chunk.RenderSection; +import net.caffeinemc.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data.PresentTranslucentData; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; +import net.caffeinemc.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; +import net.caffeinemc.mods.sodium.client.render.chunk.data.BuiltSectionInfo; import java.util.Map; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java similarity index 68% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java index 0cf4ec60fd..0702ab604d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java @@ -1,8 +1,8 @@ -package me.jellysquid.mods.sodium.client.render.chunk.compile; +package net.caffeinemc.mods.sodium.client.render.chunk.compile; -import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.DynamicData; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.PresentTranslucentData; +import net.caffeinemc.mods.sodium.client.render.chunk.RenderSection; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data.DynamicData; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data.PresentTranslucentData; public class ChunkSortOutput extends BuilderTaskOutput implements OutputWithIndexData { public final DynamicData dynamicData; diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/OutputWithIndexData.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/OutputWithIndexData.java new file mode 100644 index 0000000000..fc96b50a30 --- /dev/null +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/OutputWithIndexData.java @@ -0,0 +1,7 @@ +package net.caffeinemc.mods.sodium.client.render.chunk.compile; + +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data.PresentTranslucentData; + +public interface OutputWithIndexData { + PresentTranslucentData getTranslucentData(); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/buffers/BakedChunkModelBuilder.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/buffers/BakedChunkModelBuilder.java similarity index 75% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/buffers/BakedChunkModelBuilder.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/buffers/BakedChunkModelBuilder.java index 2f0ba5e39b..1225f5d49f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/buffers/BakedChunkModelBuilder.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/buffers/BakedChunkModelBuilder.java @@ -1,9 +1,9 @@ -package me.jellysquid.mods.sodium.client.render.chunk.compile.buffers; +package net.caffeinemc.mods.sodium.client.render.chunk.compile.buffers; -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; -import me.jellysquid.mods.sodium.client.render.chunk.vertex.builder.ChunkMeshBufferBuilder; +import net.caffeinemc.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import net.caffeinemc.mods.sodium.client.render.chunk.vertex.builder.ChunkMeshBufferBuilder; import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionInfo; +import net.caffeinemc.mods.sodium.client.render.chunk.data.BuiltSectionInfo; public class BakedChunkModelBuilder implements ChunkModelBuilder { private final ChunkMeshBufferBuilder[] vertexBuffers; diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/buffers/ChunkModelBuilder.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/buffers/ChunkModelBuilder.java new file mode 100644 index 0000000000..15c0c1996c --- /dev/null +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/buffers/ChunkModelBuilder.java @@ -0,0 +1,11 @@ +package net.caffeinemc.mods.sodium.client.render.chunk.compile.buffers; + +import net.caffeinemc.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import net.caffeinemc.mods.sodium.client.render.chunk.vertex.builder.ChunkMeshBufferBuilder; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; + +public interface ChunkModelBuilder { + ChunkMeshBufferBuilder getVertexBuffer(ModelQuadFacing facing); + + void addSprite(TextureAtlasSprite sprite); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkBuilder.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkBuilder.java similarity index 94% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkBuilder.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkBuilder.java index 60a15c170f..0b4ad48d93 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkBuilder.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkBuilder.java @@ -1,10 +1,10 @@ -package me.jellysquid.mods.sodium.client.render.chunk.compile.executor; +package net.caffeinemc.mods.sodium.client.render.chunk.compile.executor; -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import me.jellysquid.mods.sodium.client.render.chunk.compile.BuilderTaskOutput; -import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildContext; -import me.jellysquid.mods.sodium.client.render.chunk.compile.tasks.ChunkBuilderTask; -import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexType; +import net.caffeinemc.mods.sodium.client.SodiumClientMod; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.BuilderTaskOutput; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.ChunkBuildContext; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.tasks.ChunkBuilderTask; +import net.caffeinemc.mods.sodium.client.render.chunk.vertex.format.ChunkVertexType; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.util.Mth; import org.apache.commons.lang3.Validate; diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkJob.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkJob.java new file mode 100644 index 0000000000..a0bcb33505 --- /dev/null +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkJob.java @@ -0,0 +1,12 @@ +package net.caffeinemc.mods.sodium.client.render.chunk.compile.executor; + +import net.caffeinemc.mods.sodium.client.render.chunk.compile.ChunkBuildContext; +import net.caffeinemc.mods.sodium.client.util.task.CancellationToken; + +public interface ChunkJob extends CancellationToken { + void execute(ChunkBuildContext context); + + boolean isStarted(); + + int getEffort(); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJobCollector.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkJobCollector.java similarity index 94% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJobCollector.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkJobCollector.java index 1d6a0f0a32..39d6d6ff2e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJobCollector.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkJobCollector.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.client.render.chunk.compile.executor; +package net.caffeinemc.mods.sodium.client.render.chunk.compile.executor; -import me.jellysquid.mods.sodium.client.render.chunk.compile.BuilderTaskOutput; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.BuilderTaskOutput; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJobQueue.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkJobQueue.java similarity index 97% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJobQueue.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkJobQueue.java index fab009570f..0e6c2b9aa2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJobQueue.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkJobQueue.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.compile.executor; +package net.caffeinemc.mods.sodium.client.render.chunk.compile.executor; import org.apache.commons.lang3.Validate; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJobResult.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkJobResult.java similarity index 93% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJobResult.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkJobResult.java index 3d28187eea..5b1dee99c4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJobResult.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkJobResult.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.compile.executor; +package net.caffeinemc.mods.sodium.client.render.chunk.compile.executor; import net.minecraft.ReportedException; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJobTyped.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkJobTyped.java similarity index 84% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJobTyped.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkJobTyped.java index 53b9a648bb..78e1242803 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/executor/ChunkJobTyped.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkJobTyped.java @@ -1,8 +1,8 @@ -package me.jellysquid.mods.sodium.client.render.chunk.compile.executor; +package net.caffeinemc.mods.sodium.client.render.chunk.compile.executor; -import me.jellysquid.mods.sodium.client.render.chunk.compile.BuilderTaskOutput; -import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildContext; -import me.jellysquid.mods.sodium.client.render.chunk.compile.tasks.ChunkBuilderTask; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.BuilderTaskOutput; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.ChunkBuildContext; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.tasks.ChunkBuilderTask; import java.util.function.Consumer; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockOcclusionCache.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/BlockOcclusionCache.java similarity index 97% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockOcclusionCache.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/BlockOcclusionCache.java index 9ff930fd1e..8df9f3e90c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockOcclusionCache.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/BlockOcclusionCache.java @@ -1,8 +1,8 @@ -package me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline; +package net.caffeinemc.mods.sodium.client.render.chunk.compile.pipeline; import it.unimi.dsi.fastutil.Hash; import it.unimi.dsi.fastutil.objects.Object2IntLinkedOpenCustomHashMap; -import me.jellysquid.mods.sodium.client.util.DirectionUtil; +import net.caffeinemc.mods.sodium.client.util.DirectionUtil; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.level.BlockGetter; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderCache.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderCache.java similarity index 78% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderCache.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderCache.java index f666101a99..d11576f72a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderCache.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderCache.java @@ -1,10 +1,10 @@ -package me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline; +package net.caffeinemc.mods.sodium.client.render.chunk.compile.pipeline; -import me.jellysquid.mods.sodium.client.model.color.ColorProviderRegistry; -import me.jellysquid.mods.sodium.client.model.light.LightPipelineProvider; -import me.jellysquid.mods.sodium.client.model.light.data.ArrayLightDataCache; -import me.jellysquid.mods.sodium.client.world.WorldSlice; -import me.jellysquid.mods.sodium.client.world.cloned.ChunkRenderContext; +import net.caffeinemc.mods.sodium.client.model.color.ColorProviderRegistry; +import net.caffeinemc.mods.sodium.client.model.light.LightPipelineProvider; +import net.caffeinemc.mods.sodium.client.model.light.data.ArrayLightDataCache; +import net.caffeinemc.mods.sodium.client.world.WorldSlice; +import net.caffeinemc.mods.sodium.client.world.cloned.ChunkRenderContext; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.renderer.block.BlockModelShaper; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderContext.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderContext.java similarity index 89% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderContext.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderContext.java index 1ad610cefd..259882b1fe 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderContext.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderContext.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline; +package net.caffeinemc.mods.sodium.client.render.chunk.compile.pipeline; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TranslucentGeometryCollector; -import me.jellysquid.mods.sodium.client.world.WorldSlice; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.TranslucentGeometryCollector; +import net.caffeinemc.mods.sodium.client.world.WorldSlice; import net.minecraft.client.resources.model.BakedModel; import net.minecraft.core.BlockPos; import net.minecraft.world.level.block.state.BlockState; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java similarity index 82% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java index c408434f6d..53c48a0e89 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java @@ -1,22 +1,22 @@ -package me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline; - -import me.jellysquid.mods.sodium.client.model.color.ColorProvider; -import me.jellysquid.mods.sodium.client.model.color.ColorProviderRegistry; -import me.jellysquid.mods.sodium.client.model.light.LightMode; -import me.jellysquid.mods.sodium.client.model.light.LightPipeline; -import me.jellysquid.mods.sodium.client.model.light.LightPipelineProvider; -import me.jellysquid.mods.sodium.client.model.light.data.QuadLightData; -import me.jellysquid.mods.sodium.client.model.quad.BakedQuadView; -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadOrientation; -import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildBuffers; -import me.jellysquid.mods.sodium.client.render.chunk.compile.buffers.ChunkModelBuilder; -import me.jellysquid.mods.sodium.client.render.chunk.terrain.material.DefaultMaterials; -import me.jellysquid.mods.sodium.client.render.chunk.terrain.material.Material; -import me.jellysquid.mods.sodium.client.render.chunk.vertex.builder.ChunkMeshBufferBuilder; -import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexEncoder; -import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexEncoder.Vertex; -import me.jellysquid.mods.sodium.client.util.DirectionUtil; +package net.caffeinemc.mods.sodium.client.render.chunk.compile.pipeline; + +import net.caffeinemc.mods.sodium.client.model.color.ColorProvider; +import net.caffeinemc.mods.sodium.client.model.color.ColorProviderRegistry; +import net.caffeinemc.mods.sodium.client.model.light.LightMode; +import net.caffeinemc.mods.sodium.client.model.light.LightPipeline; +import net.caffeinemc.mods.sodium.client.model.light.LightPipelineProvider; +import net.caffeinemc.mods.sodium.client.model.light.data.QuadLightData; +import net.caffeinemc.mods.sodium.client.model.quad.BakedQuadView; +import net.caffeinemc.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import net.caffeinemc.mods.sodium.client.model.quad.properties.ModelQuadOrientation; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.ChunkBuildBuffers; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.buffers.ChunkModelBuilder; +import net.caffeinemc.mods.sodium.client.render.chunk.terrain.material.DefaultMaterials; +import net.caffeinemc.mods.sodium.client.render.chunk.terrain.material.Material; +import net.caffeinemc.mods.sodium.client.render.chunk.vertex.builder.ChunkMeshBufferBuilder; +import net.caffeinemc.mods.sodium.client.render.chunk.vertex.format.ChunkVertexEncoder; +import net.caffeinemc.mods.sodium.client.render.chunk.vertex.format.ChunkVertexEncoder.Vertex; +import net.caffeinemc.mods.sodium.client.util.DirectionUtil; import net.caffeinemc.mods.sodium.api.util.ColorABGR; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.block.model.BakedQuad; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java similarity index 92% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java index 45291c7b38..e75bee8391 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java @@ -1,25 +1,25 @@ -package me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline; - -import me.jellysquid.mods.sodium.client.model.color.ColorProvider; -import me.jellysquid.mods.sodium.client.model.color.ColorProviderRegistry; -import me.jellysquid.mods.sodium.client.model.color.DefaultColorProviders; -import me.jellysquid.mods.sodium.client.model.light.LightMode; -import me.jellysquid.mods.sodium.client.model.light.LightPipeline; -import me.jellysquid.mods.sodium.client.model.light.LightPipelineProvider; -import me.jellysquid.mods.sodium.client.model.light.data.QuadLightData; -import me.jellysquid.mods.sodium.client.model.quad.ModelQuad; -import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; -import me.jellysquid.mods.sodium.client.model.quad.ModelQuadViewMutable; -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFlags; -import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildBuffers; -import me.jellysquid.mods.sodium.client.render.chunk.compile.buffers.ChunkModelBuilder; -import me.jellysquid.mods.sodium.client.render.chunk.terrain.material.DefaultMaterials; -import me.jellysquid.mods.sodium.client.render.chunk.terrain.material.Material; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TranslucentGeometryCollector; -import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexEncoder; -import me.jellysquid.mods.sodium.client.util.DirectionUtil; -import me.jellysquid.mods.sodium.client.world.WorldSlice; +package net.caffeinemc.mods.sodium.client.render.chunk.compile.pipeline; + +import net.caffeinemc.mods.sodium.client.model.color.ColorProvider; +import net.caffeinemc.mods.sodium.client.model.color.ColorProviderRegistry; +import net.caffeinemc.mods.sodium.client.model.color.DefaultColorProviders; +import net.caffeinemc.mods.sodium.client.model.light.LightMode; +import net.caffeinemc.mods.sodium.client.model.light.LightPipeline; +import net.caffeinemc.mods.sodium.client.model.light.LightPipelineProvider; +import net.caffeinemc.mods.sodium.client.model.light.data.QuadLightData; +import net.caffeinemc.mods.sodium.client.model.quad.ModelQuad; +import net.caffeinemc.mods.sodium.client.model.quad.ModelQuadView; +import net.caffeinemc.mods.sodium.client.model.quad.ModelQuadViewMutable; +import net.caffeinemc.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import net.caffeinemc.mods.sodium.client.model.quad.properties.ModelQuadFlags; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.ChunkBuildBuffers; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.buffers.ChunkModelBuilder; +import net.caffeinemc.mods.sodium.client.render.chunk.terrain.material.DefaultMaterials; +import net.caffeinemc.mods.sodium.client.render.chunk.terrain.material.Material; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.TranslucentGeometryCollector; +import net.caffeinemc.mods.sodium.client.render.chunk.vertex.format.ChunkVertexEncoder; +import net.caffeinemc.mods.sodium.client.util.DirectionUtil; +import net.caffeinemc.mods.sodium.client.world.WorldSlice; import net.caffeinemc.mods.sodium.api.util.ColorABGR; import net.caffeinemc.mods.sodium.api.util.NormI8; import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandler; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java similarity index 82% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java index 0011fced4d..283b72def4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java @@ -1,25 +1,25 @@ -package me.jellysquid.mods.sodium.client.render.chunk.compile.tasks; +package net.caffeinemc.mods.sodium.client.render.chunk.compile.tasks; import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; -import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildBuffers; -import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildContext; -import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildOutput; -import me.jellysquid.mods.sodium.client.render.chunk.compile.executor.ChunkBuilder; -import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.BlockRenderCache; -import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.BlockRenderContext; -import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionInfo; -import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; -import me.jellysquid.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses; -import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortBehavior; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortType; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TranslucentGeometryCollector; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; -import me.jellysquid.mods.sodium.client.util.task.CancellationToken; -import me.jellysquid.mods.sodium.client.world.WorldSlice; -import me.jellysquid.mods.sodium.client.world.cloned.ChunkRenderContext; +import net.caffeinemc.mods.sodium.client.SodiumClientMod; +import net.caffeinemc.mods.sodium.client.render.chunk.RenderSection; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.ChunkBuildBuffers; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.ChunkBuildContext; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.ChunkBuildOutput; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.executor.ChunkBuilder; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.pipeline.BlockRenderCache; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.pipeline.BlockRenderContext; +import net.caffeinemc.mods.sodium.client.render.chunk.data.BuiltSectionInfo; +import net.caffeinemc.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; +import net.caffeinemc.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses; +import net.caffeinemc.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.SortBehavior; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.SortType; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.TranslucentGeometryCollector; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; +import net.caffeinemc.mods.sodium.client.util.task.CancellationToken; +import net.caffeinemc.mods.sodium.client.world.WorldSlice; +import net.caffeinemc.mods.sodium.client.world.cloned.ChunkRenderContext; import net.minecraft.CrashReport; import net.minecraft.CrashReportCategory; import net.minecraft.ReportedException; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java similarity index 68% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java index d5733f918d..690fbae2d4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java @@ -1,13 +1,13 @@ -package me.jellysquid.mods.sodium.client.render.chunk.compile.tasks; +package net.caffeinemc.mods.sodium.client.render.chunk.compile.tasks; import org.joml.Vector3dc; -import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; -import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildContext; -import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkSortOutput; -import me.jellysquid.mods.sodium.client.render.chunk.compile.executor.ChunkBuilder; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.DynamicData; -import me.jellysquid.mods.sodium.client.util.task.CancellationToken; +import net.caffeinemc.mods.sodium.client.render.chunk.RenderSection; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.ChunkBuildContext; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.ChunkSortOutput; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.executor.ChunkBuilder; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data.DynamicData; +import net.caffeinemc.mods.sodium.client.util.task.CancellationToken; public class ChunkBuilderSortingTask extends ChunkBuilderTask { private final DynamicData dynamicData; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderTask.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderTask.java similarity index 85% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderTask.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderTask.java index d01ce40f03..1735c23bb6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderTask.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderTask.java @@ -1,14 +1,14 @@ -package me.jellysquid.mods.sodium.client.render.chunk.compile.tasks; +package net.caffeinemc.mods.sodium.client.render.chunk.compile.tasks; import org.joml.Vector3dc; import org.joml.Vector3f; import org.joml.Vector3fc; -import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; -import me.jellysquid.mods.sodium.client.render.chunk.compile.BuilderTaskOutput; -import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildContext; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.CombinedCameraPos; -import me.jellysquid.mods.sodium.client.util.task.CancellationToken; +import net.caffeinemc.mods.sodium.client.render.chunk.RenderSection; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.BuilderTaskOutput; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.ChunkBuildContext; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data.CombinedCameraPos; +import net.caffeinemc.mods.sodium.client.util.task.CancellationToken; /** * Build tasks are immutable jobs (with optional prioritization) which contain all the necessary state to perform diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/BuiltSectionInfo.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/data/BuiltSectionInfo.java similarity index 92% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/BuiltSectionInfo.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/data/BuiltSectionInfo.java index 3f4eaaf8ba..25bf883a4d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/BuiltSectionInfo.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/data/BuiltSectionInfo.java @@ -1,10 +1,10 @@ -package me.jellysquid.mods.sodium.client.render.chunk.data; +package net.caffeinemc.mods.sodium.client.render.chunk.data; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; -import me.jellysquid.mods.sodium.client.render.chunk.RenderSectionFlags; -import me.jellysquid.mods.sodium.client.render.chunk.occlusion.VisibilityEncoding; -import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; -import me.jellysquid.mods.sodium.client.render.texture.SpriteUtil; +import net.caffeinemc.mods.sodium.client.render.chunk.RenderSectionFlags; +import net.caffeinemc.mods.sodium.client.render.chunk.occlusion.VisibilityEncoding; +import net.caffeinemc.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; +import net.caffeinemc.mods.sodium.client.render.texture.SpriteUtil; import net.minecraft.client.renderer.chunk.VisibilitySet; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.core.Direction; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/BuiltSectionMeshParts.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/data/BuiltSectionMeshParts.java similarity index 69% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/BuiltSectionMeshParts.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/data/BuiltSectionMeshParts.java index 40171e3577..c57e49964b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/BuiltSectionMeshParts.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/data/BuiltSectionMeshParts.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.client.render.chunk.data; +package net.caffeinemc.mods.sodium.client.render.chunk.data; -import me.jellysquid.mods.sodium.client.gl.util.VertexRange; -import me.jellysquid.mods.sodium.client.util.NativeBuffer; +import net.caffeinemc.mods.sodium.client.gl.util.VertexRange; +import net.caffeinemc.mods.sodium.client.util.NativeBuffer; public class BuiltSectionMeshParts { private final VertexRange[] ranges; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java similarity index 95% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java index 0072dc54c5..e9c82ea383 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java @@ -1,9 +1,9 @@ -package me.jellysquid.mods.sodium.client.render.chunk.data; +package net.caffeinemc.mods.sodium.client.render.chunk.data; -import me.jellysquid.mods.sodium.client.gl.arena.GlBufferSegment; -import me.jellysquid.mods.sodium.client.gl.util.VertexRange; -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; -import me.jellysquid.mods.sodium.client.render.chunk.region.RenderRegion; +import net.caffeinemc.mods.sodium.client.gl.arena.GlBufferSegment; +import net.caffeinemc.mods.sodium.client.gl.util.VertexRange; +import net.caffeinemc.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import net.caffeinemc.mods.sodium.client.render.chunk.region.RenderRegion; import java.util.Arrays; /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataUnsafe.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/data/SectionRenderDataUnsafe.java similarity index 98% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataUnsafe.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/data/SectionRenderDataUnsafe.java index 6300fe1571..d2bed32167 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/SectionRenderDataUnsafe.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/data/SectionRenderDataUnsafe.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.data; +package net.caffeinemc.mods.sodium.client.render.chunk.data; import org.lwjgl.system.MemoryUtil; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/lists/ChunkRenderList.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/lists/ChunkRenderList.java similarity index 85% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/lists/ChunkRenderList.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/lists/ChunkRenderList.java index dfc74f58c5..75e6757df8 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/lists/ChunkRenderList.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/lists/ChunkRenderList.java @@ -1,11 +1,11 @@ -package me.jellysquid.mods.sodium.client.render.chunk.lists; - -import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; -import me.jellysquid.mods.sodium.client.render.chunk.RenderSectionFlags; -import me.jellysquid.mods.sodium.client.util.iterator.ByteIterator; -import me.jellysquid.mods.sodium.client.util.iterator.ReversibleByteArrayIterator; -import me.jellysquid.mods.sodium.client.util.iterator.ByteArrayIterator; -import me.jellysquid.mods.sodium.client.render.chunk.region.RenderRegion; +package net.caffeinemc.mods.sodium.client.render.chunk.lists; + +import net.caffeinemc.mods.sodium.client.render.chunk.RenderSection; +import net.caffeinemc.mods.sodium.client.render.chunk.RenderSectionFlags; +import net.caffeinemc.mods.sodium.client.util.iterator.ByteIterator; +import net.caffeinemc.mods.sodium.client.util.iterator.ReversibleByteArrayIterator; +import net.caffeinemc.mods.sodium.client.util.iterator.ByteArrayIterator; +import net.caffeinemc.mods.sodium.client.render.chunk.region.RenderRegion; import org.jetbrains.annotations.Nullable; public class ChunkRenderList { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/lists/ChunkRenderListIterable.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/lists/ChunkRenderListIterable.java similarity index 78% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/lists/ChunkRenderListIterable.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/lists/ChunkRenderListIterable.java index 2647b15f6e..544fb785f9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/lists/ChunkRenderListIterable.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/lists/ChunkRenderListIterable.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.lists; +package net.caffeinemc.mods.sodium.client.render.chunk.lists; import java.util.Iterator; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/lists/SortedRenderLists.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/lists/SortedRenderLists.java similarity index 88% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/lists/SortedRenderLists.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/lists/SortedRenderLists.java index c7c499c44c..1837e0ae9d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/lists/SortedRenderLists.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/lists/SortedRenderLists.java @@ -1,9 +1,9 @@ -package me.jellysquid.mods.sodium.client.render.chunk.lists; +package net.caffeinemc.mods.sodium.client.render.chunk.lists; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; -import me.jellysquid.mods.sodium.client.util.iterator.ReversibleObjectArrayIterator; -import me.jellysquid.mods.sodium.client.render.chunk.region.RenderRegion; +import net.caffeinemc.mods.sodium.client.render.chunk.RenderSection; +import net.caffeinemc.mods.sodium.client.util.iterator.ReversibleObjectArrayIterator; +import net.caffeinemc.mods.sodium.client.render.chunk.region.RenderRegion; /** * Stores one render list of sections per region, sorted by the order in which diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/lists/VisibleChunkCollector.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/lists/VisibleChunkCollector.java similarity index 85% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/lists/VisibleChunkCollector.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/lists/VisibleChunkCollector.java index fe07412176..5ed657795f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/lists/VisibleChunkCollector.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/lists/VisibleChunkCollector.java @@ -1,10 +1,10 @@ -package me.jellysquid.mods.sodium.client.render.chunk.lists; +package net.caffeinemc.mods.sodium.client.render.chunk.lists; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import me.jellysquid.mods.sodium.client.render.chunk.ChunkUpdateType; -import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; -import me.jellysquid.mods.sodium.client.render.chunk.occlusion.OcclusionCuller; -import me.jellysquid.mods.sodium.client.render.chunk.region.RenderRegion; +import net.caffeinemc.mods.sodium.client.render.chunk.ChunkUpdateType; +import net.caffeinemc.mods.sodium.client.render.chunk.RenderSection; +import net.caffeinemc.mods.sodium.client.render.chunk.occlusion.OcclusionCuller; +import net.caffeinemc.mods.sodium.client.render.chunk.region.RenderRegion; import java.util.*; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/map/ChunkStatus.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/map/ChunkStatus.java similarity index 78% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/map/ChunkStatus.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/map/ChunkStatus.java index 648486cf3b..272e2317a1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/map/ChunkStatus.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/map/ChunkStatus.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.map; +package net.caffeinemc.mods.sodium.client.render.chunk.map; public class ChunkStatus { public static final int FLAG_HAS_BLOCK_DATA = 1; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/map/ChunkTracker.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/map/ChunkTracker.java similarity index 98% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/map/ChunkTracker.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/map/ChunkTracker.java index 8382be72dd..2687c28cbf 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/map/ChunkTracker.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/map/ChunkTracker.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.map; +package net.caffeinemc.mods.sodium.client.render.chunk.map; import it.unimi.dsi.fastutil.longs.*; import net.minecraft.world.level.ChunkPos; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/map/ChunkTrackerHolder.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/map/ChunkTrackerHolder.java similarity index 80% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/map/ChunkTrackerHolder.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/map/ChunkTrackerHolder.java index 02db46267d..354cfd3a1d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/map/ChunkTrackerHolder.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/map/ChunkTrackerHolder.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.map; +package net.caffeinemc.mods.sodium.client.render.chunk.map; import net.minecraft.client.multiplayer.ClientLevel; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/map/ClientChunkEventListener.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/map/ClientChunkEventListener.java similarity index 81% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/map/ClientChunkEventListener.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/map/ClientChunkEventListener.java index 60e5244269..936a6f68e5 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/map/ClientChunkEventListener.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/map/ClientChunkEventListener.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.map; +package net.caffeinemc.mods.sodium.client.render.chunk.map; public interface ClientChunkEventListener { void updateMapCenter(int chunkX, int chunkZ); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/occlusion/GraphDirection.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/occlusion/GraphDirection.java similarity index 96% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/occlusion/GraphDirection.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/occlusion/GraphDirection.java index 0695fcc865..f8686db2ff 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/occlusion/GraphDirection.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/occlusion/GraphDirection.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.occlusion; +package net.caffeinemc.mods.sodium.client.render.chunk.occlusion; import net.minecraft.core.Direction; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/occlusion/GraphDirectionSet.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/occlusion/GraphDirectionSet.java similarity index 84% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/occlusion/GraphDirectionSet.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/occlusion/GraphDirectionSet.java index c139af6715..b7399f7533 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/occlusion/GraphDirectionSet.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/occlusion/GraphDirectionSet.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.occlusion; +package net.caffeinemc.mods.sodium.client.render.chunk.occlusion; public class GraphDirectionSet { public static final int NONE = 0; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/occlusion/OcclusionCuller.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/occlusion/OcclusionCuller.java similarity index 96% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/occlusion/OcclusionCuller.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/occlusion/OcclusionCuller.java index 62f2a360bf..754d845882 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/occlusion/OcclusionCuller.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/occlusion/OcclusionCuller.java @@ -1,12 +1,12 @@ -package me.jellysquid.mods.sodium.client.render.chunk.occlusion; +package net.caffeinemc.mods.sodium.client.render.chunk.occlusion; import it.unimi.dsi.fastutil.longs.Long2ReferenceMap; -import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; -import me.jellysquid.mods.sodium.client.render.viewport.CameraTransform; -import me.jellysquid.mods.sodium.client.render.viewport.Viewport; -import me.jellysquid.mods.sodium.client.util.collections.DoubleBufferedQueue; -import me.jellysquid.mods.sodium.client.util.collections.ReadQueue; -import me.jellysquid.mods.sodium.client.util.collections.WriteQueue; +import net.caffeinemc.mods.sodium.client.render.chunk.RenderSection; +import net.caffeinemc.mods.sodium.client.render.viewport.CameraTransform; +import net.caffeinemc.mods.sodium.client.render.viewport.Viewport; +import net.caffeinemc.mods.sodium.client.util.collections.DoubleBufferedQueue; +import net.caffeinemc.mods.sodium.client.util.collections.ReadQueue; +import net.caffeinemc.mods.sodium.client.util.collections.WriteQueue; import net.minecraft.core.SectionPos; import net.minecraft.util.Mth; import net.minecraft.world.level.Level; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/occlusion/VisibilityEncoding.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/occlusion/VisibilityEncoding.java similarity index 96% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/occlusion/VisibilityEncoding.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/occlusion/VisibilityEncoding.java index 3072927fa7..db7e9e88f7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/occlusion/VisibilityEncoding.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/occlusion/VisibilityEncoding.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.occlusion; +package net.caffeinemc.mods.sodium.client.render.chunk.occlusion; import net.minecraft.client.renderer.chunk.VisibilitySet; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/region/RenderRegion.java similarity index 90% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/region/RenderRegion.java index 1a5b4ce194..b02b9acfe9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegion.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/region/RenderRegion.java @@ -1,18 +1,18 @@ -package me.jellysquid.mods.sodium.client.render.chunk.region; +package net.caffeinemc.mods.sodium.client.render.chunk.region; import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; -import me.jellysquid.mods.sodium.client.gl.arena.GlBufferArena; -import me.jellysquid.mods.sodium.client.gl.arena.staging.StagingBuffer; -import me.jellysquid.mods.sodium.client.gl.buffer.GlBuffer; -import me.jellysquid.mods.sodium.client.gl.device.CommandList; -import me.jellysquid.mods.sodium.client.gl.tessellation.GlTessellation; -import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; -import me.jellysquid.mods.sodium.client.render.chunk.data.SectionRenderDataStorage; -import me.jellysquid.mods.sodium.client.render.chunk.lists.ChunkRenderList; -import me.jellysquid.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses; -import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; -import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkMeshFormats; -import me.jellysquid.mods.sodium.client.util.MathUtil; +import net.caffeinemc.mods.sodium.client.gl.arena.GlBufferArena; +import net.caffeinemc.mods.sodium.client.gl.arena.staging.StagingBuffer; +import net.caffeinemc.mods.sodium.client.gl.buffer.GlBuffer; +import net.caffeinemc.mods.sodium.client.gl.device.CommandList; +import net.caffeinemc.mods.sodium.client.gl.tessellation.GlTessellation; +import net.caffeinemc.mods.sodium.client.render.chunk.RenderSection; +import net.caffeinemc.mods.sodium.client.render.chunk.data.SectionRenderDataStorage; +import net.caffeinemc.mods.sodium.client.render.chunk.lists.ChunkRenderList; +import net.caffeinemc.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses; +import net.caffeinemc.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; +import net.caffeinemc.mods.sodium.client.render.chunk.vertex.format.ChunkMeshFormats; +import net.caffeinemc.mods.sodium.client.util.MathUtil; import net.minecraft.core.SectionPos; import org.apache.commons.lang3.Validate; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/region/RenderRegionManager.java similarity index 84% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/region/RenderRegionManager.java index d7b338c0ae..28004bf1b9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/RenderRegionManager.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/region/RenderRegionManager.java @@ -1,27 +1,27 @@ -package me.jellysquid.mods.sodium.client.render.chunk.region; +package net.caffeinemc.mods.sodium.client.render.chunk.region; import it.unimi.dsi.fastutil.longs.Long2ReferenceOpenHashMap; import it.unimi.dsi.fastutil.objects.Reference2ReferenceMap; import it.unimi.dsi.fastutil.objects.Reference2ReferenceMap.Entry; import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import me.jellysquid.mods.sodium.client.gl.arena.GlBufferArena; -import me.jellysquid.mods.sodium.client.gl.arena.PendingUpload; -import me.jellysquid.mods.sodium.client.gl.arena.staging.FallbackStagingBuffer; -import me.jellysquid.mods.sodium.client.gl.arena.staging.MappedStagingBuffer; -import me.jellysquid.mods.sodium.client.gl.arena.staging.StagingBuffer; -import me.jellysquid.mods.sodium.client.gl.device.CommandList; -import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; -import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; -import me.jellysquid.mods.sodium.client.render.chunk.compile.BuilderTaskOutput; -import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildOutput; -import me.jellysquid.mods.sodium.client.render.chunk.compile.OutputWithIndexData; -import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; -import me.jellysquid.mods.sodium.client.render.chunk.data.SectionRenderDataStorage; -import me.jellysquid.mods.sodium.client.render.chunk.region.RenderRegion.DeviceResources; -import me.jellysquid.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses; -import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.PresentTranslucentData; +import net.caffeinemc.mods.sodium.client.SodiumClientMod; +import net.caffeinemc.mods.sodium.client.gl.arena.GlBufferArena; +import net.caffeinemc.mods.sodium.client.gl.arena.PendingUpload; +import net.caffeinemc.mods.sodium.client.gl.arena.staging.FallbackStagingBuffer; +import net.caffeinemc.mods.sodium.client.gl.arena.staging.MappedStagingBuffer; +import net.caffeinemc.mods.sodium.client.gl.arena.staging.StagingBuffer; +import net.caffeinemc.mods.sodium.client.gl.device.CommandList; +import net.caffeinemc.mods.sodium.client.gl.device.RenderDevice; +import net.caffeinemc.mods.sodium.client.render.chunk.RenderSection; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.BuilderTaskOutput; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.ChunkBuildOutput; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.OutputWithIndexData; +import net.caffeinemc.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; +import net.caffeinemc.mods.sodium.client.render.chunk.data.SectionRenderDataStorage; +import net.caffeinemc.mods.sodium.client.render.chunk.region.RenderRegion.DeviceResources; +import net.caffeinemc.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses; +import net.caffeinemc.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data.PresentTranslucentData; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkFogMode.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkFogMode.java similarity index 92% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkFogMode.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkFogMode.java index b0f202601b..bf0d6d2be5 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkFogMode.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkFogMode.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.shader; +package net.caffeinemc.mods.sodium.client.render.chunk.shader; import com.google.common.collect.ImmutableList; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkShaderBindingPoints.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkShaderBindingPoints.java similarity index 82% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkShaderBindingPoints.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkShaderBindingPoints.java index 3f87ecf906..9f201c0daa 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkShaderBindingPoints.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkShaderBindingPoints.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.shader; +package net.caffeinemc.mods.sodium.client.render.chunk.shader; public class ChunkShaderBindingPoints { public static final int ATTRIBUTE_POSITION_ID = 1; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkShaderFogComponent.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkShaderFogComponent.java similarity index 88% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkShaderFogComponent.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkShaderFogComponent.java index 8f305870c6..6855970186 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkShaderFogComponent.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkShaderFogComponent.java @@ -1,9 +1,9 @@ -package me.jellysquid.mods.sodium.client.render.chunk.shader; +package net.caffeinemc.mods.sodium.client.render.chunk.shader; import com.mojang.blaze3d.systems.RenderSystem; -import me.jellysquid.mods.sodium.client.gl.shader.uniform.GlUniformFloat; -import me.jellysquid.mods.sodium.client.gl.shader.uniform.GlUniformFloat4v; -import me.jellysquid.mods.sodium.client.gl.shader.uniform.GlUniformInt; +import net.caffeinemc.mods.sodium.client.gl.shader.uniform.GlUniformFloat; +import net.caffeinemc.mods.sodium.client.gl.shader.uniform.GlUniformFloat4v; +import net.caffeinemc.mods.sodium.client.gl.shader.uniform.GlUniformInt; /** * These shader implementations try to remain compatible with the deprecated fixed function pipeline by manually diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkShaderInterface.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkShaderInterface.java similarity index 87% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkShaderInterface.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkShaderInterface.java index e412e8ca78..a5da4ac192 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkShaderInterface.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkShaderInterface.java @@ -1,10 +1,10 @@ -package me.jellysquid.mods.sodium.client.render.chunk.shader; +package net.caffeinemc.mods.sodium.client.render.chunk.shader; import com.mojang.blaze3d.platform.GlStateManager; -import me.jellysquid.mods.sodium.client.gl.shader.uniform.GlUniformFloat3v; -import me.jellysquid.mods.sodium.client.gl.shader.uniform.GlUniformInt; -import me.jellysquid.mods.sodium.client.gl.shader.uniform.GlUniformMatrix4f; -import me.jellysquid.mods.sodium.client.util.TextureUtil; +import net.caffeinemc.mods.sodium.client.gl.shader.uniform.GlUniformFloat3v; +import net.caffeinemc.mods.sodium.client.gl.shader.uniform.GlUniformInt; +import net.caffeinemc.mods.sodium.client.gl.shader.uniform.GlUniformMatrix4f; +import net.caffeinemc.mods.sodium.client.util.TextureUtil; import org.joml.Matrix4fc; import org.lwjgl.opengl.GL32C; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkShaderOptions.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkShaderOptions.java similarity index 73% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkShaderOptions.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkShaderOptions.java index 3ea6b15220..2883b701d3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkShaderOptions.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkShaderOptions.java @@ -1,8 +1,8 @@ -package me.jellysquid.mods.sodium.client.render.chunk.shader; +package net.caffeinemc.mods.sodium.client.render.chunk.shader; -import me.jellysquid.mods.sodium.client.gl.shader.ShaderConstants; -import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; -import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexType; +import net.caffeinemc.mods.sodium.client.gl.shader.ShaderConstants; +import net.caffeinemc.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; +import net.caffeinemc.mods.sodium.client.render.chunk.vertex.format.ChunkVertexType; public record ChunkShaderOptions(ChunkFogMode fog, TerrainRenderPass pass, ChunkVertexType vertexType) { public ShaderConstants constants() { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkShaderTextureSlot.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkShaderTextureSlot.java similarity index 70% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkShaderTextureSlot.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkShaderTextureSlot.java index a9ed3b8077..41a4bd8ab3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkShaderTextureSlot.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkShaderTextureSlot.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.shader; +package net.caffeinemc.mods.sodium.client.render.chunk.shader; public enum ChunkShaderTextureSlot { BLOCK, diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ShaderBindingContext.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ShaderBindingContext.java similarity index 52% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ShaderBindingContext.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ShaderBindingContext.java index ce56cccc82..0797ff5408 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ShaderBindingContext.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ShaderBindingContext.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.client.render.chunk.shader; +package net.caffeinemc.mods.sodium.client.render.chunk.shader; -import me.jellysquid.mods.sodium.client.gl.shader.uniform.GlUniform; -import me.jellysquid.mods.sodium.client.gl.shader.uniform.GlUniformBlock; +import net.caffeinemc.mods.sodium.client.gl.shader.uniform.GlUniform; +import net.caffeinemc.mods.sodium.client.gl.shader.uniform.GlUniformBlock; import java.util.function.IntFunction; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/terrain/DefaultTerrainRenderPasses.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/DefaultTerrainRenderPasses.java similarity index 89% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/terrain/DefaultTerrainRenderPasses.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/DefaultTerrainRenderPasses.java index ce1b4aca42..69f3b3fff7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/terrain/DefaultTerrainRenderPasses.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/DefaultTerrainRenderPasses.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.terrain; +package net.caffeinemc.mods.sodium.client.render.chunk.terrain; import net.minecraft.client.renderer.RenderType; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/terrain/TerrainRenderPass.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/TerrainRenderPass.java similarity index 92% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/terrain/TerrainRenderPass.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/TerrainRenderPass.java index 9e2d7348c3..2d6824690b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/terrain/TerrainRenderPass.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/TerrainRenderPass.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.terrain; +package net.caffeinemc.mods.sodium.client.render.chunk.terrain; import net.minecraft.client.renderer.RenderType; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/terrain/material/DefaultMaterials.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/material/DefaultMaterials.java similarity index 85% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/terrain/material/DefaultMaterials.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/material/DefaultMaterials.java index c2fe2b9d73..f03d4bee2a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/terrain/material/DefaultMaterials.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/material/DefaultMaterials.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.client.render.chunk.terrain.material; +package net.caffeinemc.mods.sodium.client.render.chunk.terrain.material; -import me.jellysquid.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses; -import me.jellysquid.mods.sodium.client.render.chunk.terrain.material.parameters.AlphaCutoffParameter; +import net.caffeinemc.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses; +import net.caffeinemc.mods.sodium.client.render.chunk.terrain.material.parameters.AlphaCutoffParameter; import net.minecraft.client.renderer.ItemBlockRenderTypes; import net.minecraft.client.renderer.RenderType; import net.minecraft.world.level.block.state.BlockState; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/terrain/material/Material.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/material/Material.java similarity index 58% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/terrain/material/Material.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/material/Material.java index 9a073ca7aa..1f312b235b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/terrain/material/Material.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/material/Material.java @@ -1,8 +1,8 @@ -package me.jellysquid.mods.sodium.client.render.chunk.terrain.material; +package net.caffeinemc.mods.sodium.client.render.chunk.terrain.material; -import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; -import me.jellysquid.mods.sodium.client.render.chunk.terrain.material.parameters.AlphaCutoffParameter; -import me.jellysquid.mods.sodium.client.render.chunk.terrain.material.parameters.MaterialParameters; +import net.caffeinemc.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; +import net.caffeinemc.mods.sodium.client.render.chunk.terrain.material.parameters.AlphaCutoffParameter; +import net.caffeinemc.mods.sodium.client.render.chunk.terrain.material.parameters.MaterialParameters; public class Material { public final TerrainRenderPass pass; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/terrain/material/parameters/AlphaCutoffParameter.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/material/parameters/AlphaCutoffParameter.java similarity index 57% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/terrain/material/parameters/AlphaCutoffParameter.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/material/parameters/AlphaCutoffParameter.java index 836a255399..d70fa9cd9f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/terrain/material/parameters/AlphaCutoffParameter.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/material/parameters/AlphaCutoffParameter.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.terrain.material.parameters; +package net.caffeinemc.mods.sodium.client.render.chunk.terrain.material.parameters; public enum AlphaCutoffParameter { ZERO, // 0.0f diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/terrain/material/parameters/MaterialParameters.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/material/parameters/MaterialParameters.java similarity index 80% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/terrain/material/parameters/MaterialParameters.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/material/parameters/MaterialParameters.java index 977a3e3ce5..d0e19c5e11 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/terrain/material/parameters/MaterialParameters.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/material/parameters/MaterialParameters.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.terrain.material.parameters; +package net.caffeinemc.mods.sodium.client.render.chunk.terrain.material.parameters; public class MaterialParameters { public static final int OFFSET_USE_MIP = 0; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AlignableNormal.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/AlignableNormal.java similarity index 94% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AlignableNormal.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/AlignableNormal.java index e9cd62b95c..ef492d0f1a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/AlignableNormal.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/AlignableNormal.java @@ -1,10 +1,10 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; +package net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting; import org.joml.Vector3f; import org.joml.Vector3fc; import it.unimi.dsi.fastutil.floats.FloatArrays; -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import net.caffeinemc.mods.sodium.client.model.quad.properties.ModelQuadFacing; /** * A normal vector that has additional information about its alignment. This is diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SortBehavior.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/SortBehavior.java similarity index 96% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SortBehavior.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/SortBehavior.java index 939714f0a4..055270f7bf 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SortBehavior.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/SortBehavior.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; +package net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting; public enum SortBehavior { OFF("OFF", SortMode.NONE), diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SortType.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/SortType.java similarity index 94% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SortType.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/SortType.java index 90cf8c5c81..d00713259a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/SortType.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/SortType.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; +package net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting; /** * What type of sorting to use for a section. Calculated by a heuristic after diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java similarity index 97% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java index d5dd6b23c7..633ec915a1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java @@ -1,11 +1,11 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; +package net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting; import java.util.Arrays; import org.joml.Vector3f; import org.joml.Vector3fc; -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import net.caffeinemc.mods.sodium.client.model.quad.properties.ModelQuadFacing; import net.caffeinemc.mods.sodium.api.util.NormI8; /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java similarity index 95% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java index 9c7320cd06..ece55d95f7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java @@ -1,17 +1,17 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting; +package net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting; import it.unimi.dsi.fastutil.objects.ReferenceArrayList; -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; -import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildOutput; -import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.FluidRenderer; -import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree.BSPBuildFailureException; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.*; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger.GeometryPlanes; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger.SortTriggering; -import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexEncoder; -import me.jellysquid.mods.sodium.client.util.NativeBuffer; +import net.caffeinemc.mods.sodium.client.SodiumClientMod; +import net.caffeinemc.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.ChunkBuildOutput; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.pipeline.FluidRenderer; +import net.caffeinemc.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree.BSPBuildFailureException; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data.*; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.trigger.GeometryPlanes; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.trigger.SortTriggering; +import net.caffeinemc.mods.sodium.client.render.chunk.vertex.format.ChunkVertexEncoder; +import net.caffeinemc.mods.sodium.client.util.NativeBuffer; import net.caffeinemc.mods.sodium.api.util.NormI8; import net.minecraft.core.SectionPos; import org.joml.Vector3f; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPBuildFailureException.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPBuildFailureException.java similarity index 63% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPBuildFailureException.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPBuildFailureException.java index 5520c22dae..af192ed352 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPBuildFailureException.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPBuildFailureException.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; +package net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; public class BSPBuildFailureException extends RuntimeException { BSPBuildFailureException(String message) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java similarity index 92% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java index 55adac82b7..20a48780d1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java @@ -1,11 +1,11 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; +package net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; import org.joml.Vector3fc; import it.unimi.dsi.fastutil.ints.IntArrayList; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TopoGraphSorting; -import me.jellysquid.mods.sodium.client.util.NativeBuffer; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.TQuad; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data.TopoGraphSorting; +import net.caffeinemc.mods.sodium.client.util.NativeBuffer; import net.caffeinemc.mods.sodium.api.util.NormI8; import net.minecraft.core.SectionPos; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPResult.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPResult.java similarity index 69% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPResult.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPResult.java index 00111e9b10..44911007b9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPResult.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPResult.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; +package net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger.GeometryPlanes; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.trigger.GeometryPlanes; /** * The result of a BSP building operation. Building a BSP returns the root node diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java similarity index 97% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java index a6a2fafd7a..8dec551663 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java @@ -1,12 +1,12 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; +package net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; import java.nio.IntBuffer; import java.lang.Math; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntConsumer; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; -import me.jellysquid.mods.sodium.client.util.NativeBuffer; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; +import net.caffeinemc.mods.sodium.client.util.NativeBuffer; /** * The sort state is passed around the tree (similar to visitor pattern) and diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java similarity index 82% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java index d720323f42..48e30bacc4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; +package net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger.GeometryPlanes; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.TQuad; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.trigger.GeometryPlanes; import net.minecraft.core.SectionPos; /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java similarity index 97% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java index 5345b4f225..4151684714 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; +package net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; import org.joml.Vector3fc; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerMultiPartitionBSPNode.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerMultiPartitionBSPNode.java similarity index 98% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerMultiPartitionBSPNode.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerMultiPartitionBSPNode.java index 4747399fea..8bc3d0beeb 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerMultiPartitionBSPNode.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerMultiPartitionBSPNode.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; +package net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; import org.joml.Vector3fc; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java similarity index 98% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java index 6c71a3720d..44555da511 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java @@ -1,12 +1,12 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; +package net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntConsumer; import it.unimi.dsi.fastutil.longs.LongArrayList; import it.unimi.dsi.fastutil.objects.ReferenceArrayList; -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TopoGraphSorting; +import net.caffeinemc.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.TQuad; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data.TopoGraphSorting; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.joml.Vector3fc; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafDoubleBSPNode.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafDoubleBSPNode.java similarity index 85% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafDoubleBSPNode.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafDoubleBSPNode.java index 24d6c9b152..19f8b1a2d2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafDoubleBSPNode.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafDoubleBSPNode.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; +package net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; import org.joml.Vector3fc; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafMultiBSPNode.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafMultiBSPNode.java similarity index 81% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafMultiBSPNode.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafMultiBSPNode.java index 5bfb17d3ca..0c2ebcc764 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafMultiBSPNode.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafMultiBSPNode.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; +package net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; import org.joml.Vector3fc; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafSingleBSPNode.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafSingleBSPNode.java similarity index 81% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafSingleBSPNode.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafSingleBSPNode.java index fc6ae461b3..68af251ec8 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafSingleBSPNode.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafSingleBSPNode.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; +package net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; import org.joml.Vector3fc; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/Partition.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/Partition.java similarity index 80% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/Partition.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/Partition.java index cf50ddcec4..6a6d69e940 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/Partition.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/Partition.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; +package net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree; import it.unimi.dsi.fastutil.ints.IntArrayList; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/AnyOrderData.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/AnyOrderData.java similarity index 81% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/AnyOrderData.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/AnyOrderData.java index 72806b2e1b..ce29e3a46d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/AnyOrderData.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/AnyOrderData.java @@ -1,10 +1,10 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data; +package net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data; -import me.jellysquid.mods.sodium.client.gl.util.VertexRange; -import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortType; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; -import me.jellysquid.mods.sodium.client.util.NativeBuffer; +import net.caffeinemc.mods.sodium.client.gl.util.VertexRange; +import net.caffeinemc.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.SortType; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.TQuad; +import net.caffeinemc.mods.sodium.client.util.NativeBuffer; import net.minecraft.core.SectionPos; /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java similarity index 80% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java index bfae5637ae..c2fe7f67d4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/BSPDynamicData.java @@ -1,14 +1,14 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data; +package net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data; import org.joml.Vector3dc; import org.joml.Vector3fc; -import me.jellysquid.mods.sodium.client.gl.util.VertexRange; -import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree.BSPNode; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree.BSPResult; -import me.jellysquid.mods.sodium.client.util.NativeBuffer; +import net.caffeinemc.mods.sodium.client.gl.util.VertexRange; +import net.caffeinemc.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.TQuad; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree.BSPNode; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.bsp_tree.BSPResult; +import net.caffeinemc.mods.sodium.client.util.NativeBuffer; import net.minecraft.core.SectionPos; /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/CombinedCameraPos.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/CombinedCameraPos.java similarity index 67% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/CombinedCameraPos.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/CombinedCameraPos.java index 684f57726a..c18980a089 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/CombinedCameraPos.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/CombinedCameraPos.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data; +package net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data; import org.joml.Vector3dc; import org.joml.Vector3fc; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicData.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicData.java similarity index 71% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicData.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicData.java index c353dbd34a..401ba9a1a4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicData.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicData.java @@ -1,11 +1,11 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data; +package net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data; import org.joml.Vector3dc; -import me.jellysquid.mods.sodium.client.gl.util.VertexRange; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortType; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger.GeometryPlanes; -import me.jellysquid.mods.sodium.client.util.NativeBuffer; +import net.caffeinemc.mods.sodium.client.gl.util.VertexRange; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.SortType; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.trigger.GeometryPlanes; +import net.caffeinemc.mods.sodium.client.util.NativeBuffer; import net.minecraft.core.SectionPos; public abstract class DynamicData extends MixedDirectionData { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/MixedDirectionData.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/MixedDirectionData.java similarity index 63% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/MixedDirectionData.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/MixedDirectionData.java index d29649157f..535ec27688 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/MixedDirectionData.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/MixedDirectionData.java @@ -1,8 +1,8 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data; +package net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data; -import me.jellysquid.mods.sodium.client.gl.util.VertexRange; -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; -import me.jellysquid.mods.sodium.client.util.NativeBuffer; +import net.caffeinemc.mods.sodium.client.gl.util.VertexRange; +import net.caffeinemc.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import net.caffeinemc.mods.sodium.client.util.NativeBuffer; import net.minecraft.core.SectionPos; public abstract class MixedDirectionData extends PresentTranslucentData { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/NoData.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/NoData.java similarity index 83% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/NoData.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/NoData.java index ada2a90af5..12a98ee7e1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/NoData.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/NoData.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data; +package net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortType; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.SortType; import net.minecraft.core.SectionPos; /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/PresentTranslucentData.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/PresentTranslucentData.java similarity index 85% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/PresentTranslucentData.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/PresentTranslucentData.java index b15ebb991a..6ae4d9b253 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/PresentTranslucentData.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/PresentTranslucentData.java @@ -1,8 +1,8 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data; +package net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data; -import me.jellysquid.mods.sodium.client.gl.util.VertexRange; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; -import me.jellysquid.mods.sodium.client.util.NativeBuffer; +import net.caffeinemc.mods.sodium.client.gl.util.VertexRange; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.TQuad; +import net.caffeinemc.mods.sodium.client.util.NativeBuffer; import net.minecraft.core.SectionPos; /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/SplitDirectionData.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/SplitDirectionData.java similarity index 75% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/SplitDirectionData.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/SplitDirectionData.java index be946aa0d4..320f0c70e5 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/SplitDirectionData.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/SplitDirectionData.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data; +package net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data; -import me.jellysquid.mods.sodium.client.gl.util.VertexRange; -import me.jellysquid.mods.sodium.client.util.NativeBuffer; +import net.caffeinemc.mods.sodium.client.gl.util.VertexRange; +import net.caffeinemc.mods.sodium.client.util.NativeBuffer; import net.minecraft.core.SectionPos; /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java similarity index 90% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java index 92745d917b..b7b6df5db4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java @@ -1,15 +1,15 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data; +package net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data; import java.nio.IntBuffer; import java.util.Arrays; -import me.jellysquid.mods.sodium.client.gl.util.VertexRange; -import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortType; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; -import me.jellysquid.mods.sodium.client.util.MathUtil; -import me.jellysquid.mods.sodium.client.util.NativeBuffer; -import me.jellysquid.mods.sodium.client.util.sorting.RadixSort; +import net.caffeinemc.mods.sodium.client.gl.util.VertexRange; +import net.caffeinemc.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.SortType; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.TQuad; +import net.caffeinemc.mods.sodium.client.util.MathUtil; +import net.caffeinemc.mods.sodium.client.util.NativeBuffer; +import net.caffeinemc.mods.sodium.client.util.sorting.RadixSort; import net.minecraft.core.SectionPos; /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticTopoAcyclicData.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/StaticTopoAcyclicData.java similarity index 75% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticTopoAcyclicData.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/StaticTopoAcyclicData.java index e85d324bfd..64565520b3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/StaticTopoAcyclicData.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/StaticTopoAcyclicData.java @@ -1,10 +1,10 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data; +package net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data; -import me.jellysquid.mods.sodium.client.gl.util.VertexRange; -import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortType; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; -import me.jellysquid.mods.sodium.client.util.NativeBuffer; +import net.caffeinemc.mods.sodium.client.gl.util.VertexRange; +import net.caffeinemc.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.SortType; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.TQuad; +import net.caffeinemc.mods.sodium.client.util.NativeBuffer; import net.minecraft.core.SectionPos; import java.nio.IntBuffer; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoGraphSorting.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/TopoGraphSorting.java similarity index 97% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoGraphSorting.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/TopoGraphSorting.java index aa395e8c25..fcbe754c97 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoGraphSorting.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/TopoGraphSorting.java @@ -1,10 +1,10 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data; +package net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data; import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.AlignableNormal; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; -import me.jellysquid.mods.sodium.client.util.collections.BitArray; +import net.caffeinemc.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.AlignableNormal; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.TQuad; +import net.caffeinemc.mods.sodium.client.util.collections.BitArray; import org.joml.Vector3fc; import java.util.function.IntConsumer; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java similarity index 94% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java index 37ae88dbef..0f3701f96d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/TopoSortDynamicData.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data; +package net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data; import java.nio.IntBuffer; import java.util.Arrays; @@ -8,12 +8,12 @@ import org.joml.Vector3fc; import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; -import me.jellysquid.mods.sodium.client.gl.util.VertexRange; -import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger.GeometryPlanes; -import me.jellysquid.mods.sodium.client.util.NativeBuffer; -import me.jellysquid.mods.sodium.client.util.sorting.RadixSort; +import net.caffeinemc.mods.sodium.client.gl.util.VertexRange; +import net.caffeinemc.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.TQuad; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.trigger.GeometryPlanes; +import net.caffeinemc.mods.sodium.client.util.NativeBuffer; +import net.caffeinemc.mods.sodium.client.util.sorting.RadixSort; import net.minecraft.core.SectionPos; /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TranslucentData.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/TranslucentData.java similarity index 87% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TranslucentData.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/TranslucentData.java index 9515c2fe52..52fa90d90e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/data/TranslucentData.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/TranslucentData.java @@ -1,13 +1,13 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data; +package net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data; import java.nio.IntBuffer; import org.joml.Vector3fc; -import me.jellysquid.mods.sodium.client.gl.util.VertexRange; -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; -import me.jellysquid.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortType; +import net.caffeinemc.mods.sodium.client.gl.util.VertexRange; +import net.caffeinemc.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import net.caffeinemc.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.SortType; import net.minecraft.core.SectionPos; /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/CameraMovement.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/CameraMovement.java similarity index 68% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/CameraMovement.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/CameraMovement.java index 6d4dfb2d01..dd4eae5b8a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/CameraMovement.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/CameraMovement.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger; +package net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.trigger; import org.joml.Vector3dc; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/DirectTriggers.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/DirectTriggers.java similarity index 96% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/DirectTriggers.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/DirectTriggers.java index 208d21bcd6..6341652792 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/DirectTriggers.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/DirectTriggers.java @@ -1,12 +1,12 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger; +package net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.trigger; import org.joml.Vector3d; import org.joml.Vector3dc; import it.unimi.dsi.fastutil.doubles.Double2ObjectRBTreeMap; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TopoSortDynamicData; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger.SortTriggering.SectionTriggers; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data.TopoSortDynamicData; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.trigger.SortTriggering.SectionTriggers; import net.minecraft.core.SectionPos; /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GFNITriggers.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/GFNITriggers.java similarity index 92% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GFNITriggers.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/GFNITriggers.java index 9f686a4d77..b613243284 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GFNITriggers.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/GFNITriggers.java @@ -1,11 +1,11 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger; +package net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.trigger; import org.joml.Vector3fc; import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.DynamicData; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger.SortTriggering.SectionTriggers; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data.DynamicData; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.trigger.SortTriggering.SectionTriggers; import net.minecraft.core.SectionPos; /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GeometryPlanes.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/GeometryPlanes.java similarity index 94% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GeometryPlanes.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/GeometryPlanes.java index 322c9ed2d8..8f75c2db7d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/GeometryPlanes.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/GeometryPlanes.java @@ -1,12 +1,12 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger; +package net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.trigger; import java.util.Collection; import org.joml.Vector3fc; import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.TQuad; +import net.caffeinemc.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.TQuad; import net.minecraft.core.SectionPos; /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/Group.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/Group.java similarity index 94% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/Group.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/Group.java index 497e9ca555..9be130c7ab 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/Group.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/Group.java @@ -1,8 +1,8 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger; +package net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.trigger; import com.lodborg.intervaltree.DoubleInterval; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.AlignableNormal; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.AlignableNormal; /** * A group represents a set of face planes of the same normal within a section. diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalList.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalList.java similarity index 97% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalList.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalList.java index b74a268f6b..5c08e996ac 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalList.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalList.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger; +package net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.trigger; import java.util.Collection; @@ -13,7 +13,7 @@ import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; import it.unimi.dsi.fastutil.objects.ReferenceArraySet; import it.unimi.dsi.fastutil.objects.ReferenceLinkedOpenHashSet; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.AlignableNormal; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.AlignableNormal; /** * A normal list contains all the face planes that have the same normal. diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalPlanes.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalPlanes.java similarity index 94% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalPlanes.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalPlanes.java index ca6e837cfa..ecd542b619 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalPlanes.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalPlanes.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger; +package net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.trigger; import org.joml.Vector3fc; import java.util.Arrays; @@ -8,7 +8,7 @@ import it.unimi.dsi.fastutil.floats.FloatOpenHashSet; import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.AlignableNormal; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.AlignableNormal; import net.minecraft.core.SectionPos; /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java similarity index 93% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java index fc660803e5..587542ff54 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.trigger; +package net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.trigger; import java.util.List; import java.util.function.BiConsumer; @@ -6,13 +6,13 @@ import org.joml.Vector3dc; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.AlignableNormal; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortBehavior; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.SortType; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.DynamicData; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TopoSortDynamicData; -import me.jellysquid.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; +import net.caffeinemc.mods.sodium.client.SodiumClientMod; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.AlignableNormal; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.SortBehavior; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.SortType; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data.DynamicData; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data.TopoSortDynamicData; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData; import net.minecraft.core.SectionPos; /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/vertex/builder/ChunkMeshBufferBuilder.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/builder/ChunkMeshBufferBuilder.java similarity index 87% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/vertex/builder/ChunkMeshBufferBuilder.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/builder/ChunkMeshBufferBuilder.java index b72a89fd35..445b1ab56d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/vertex/builder/ChunkMeshBufferBuilder.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/builder/ChunkMeshBufferBuilder.java @@ -1,8 +1,8 @@ -package me.jellysquid.mods.sodium.client.render.chunk.vertex.builder; +package net.caffeinemc.mods.sodium.client.render.chunk.vertex.builder; -import me.jellysquid.mods.sodium.client.render.chunk.terrain.material.Material; -import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexEncoder; -import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexType; +import net.caffeinemc.mods.sodium.client.render.chunk.terrain.material.Material; +import net.caffeinemc.mods.sodium.client.render.chunk.vertex.format.ChunkVertexEncoder; +import net.caffeinemc.mods.sodium.client.render.chunk.vertex.format.ChunkVertexType; import org.lwjgl.system.MemoryUtil; import java.nio.ByteBuffer; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/vertex/format/ChunkMeshAttribute.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/format/ChunkMeshAttribute.java similarity index 62% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/vertex/format/ChunkMeshAttribute.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/format/ChunkMeshAttribute.java index 7349ba7af5..cef7ab7e13 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/vertex/format/ChunkMeshAttribute.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/format/ChunkMeshAttribute.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.chunk.vertex.format; +package net.caffeinemc.mods.sodium.client.render.chunk.vertex.format; public enum ChunkMeshAttribute { POSITION_MATERIAL_MESH, diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/format/ChunkMeshFormats.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/format/ChunkMeshFormats.java new file mode 100644 index 0000000000..5a47ba65a1 --- /dev/null +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/format/ChunkMeshFormats.java @@ -0,0 +1,7 @@ +package net.caffeinemc.mods.sodium.client.render.chunk.vertex.format; + +import net.caffeinemc.mods.sodium.client.render.chunk.vertex.format.impl.CompactChunkVertex; + +public class ChunkMeshFormats { + public static final ChunkVertexType COMPACT = new CompactChunkVertex(); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/vertex/format/ChunkVertexEncoder.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/format/ChunkVertexEncoder.java similarity index 78% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/vertex/format/ChunkVertexEncoder.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/format/ChunkVertexEncoder.java index 49cb583229..465f8b1853 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/vertex/format/ChunkVertexEncoder.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/format/ChunkVertexEncoder.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.client.render.chunk.vertex.format; +package net.caffeinemc.mods.sodium.client.render.chunk.vertex.format; -import me.jellysquid.mods.sodium.client.render.chunk.terrain.material.Material; +import net.caffeinemc.mods.sodium.client.render.chunk.terrain.material.Material; public interface ChunkVertexEncoder { long write(long ptr, Material material, Vertex vertex, int sectionIndex); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/vertex/format/ChunkVertexType.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/format/ChunkVertexType.java similarity index 76% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/vertex/format/ChunkVertexType.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/format/ChunkVertexType.java index 75bd2bf7de..d920b3eb8e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/vertex/format/ChunkVertexType.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/format/ChunkVertexType.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.client.render.chunk.vertex.format; +package net.caffeinemc.mods.sodium.client.render.chunk.vertex.format; -import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexFormat; +import net.caffeinemc.mods.sodium.client.gl.attribute.GlVertexFormat; public interface ChunkVertexType { /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/vertex/format/impl/CompactChunkVertex.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/format/impl/CompactChunkVertex.java similarity index 84% rename from src/main/java/me/jellysquid/mods/sodium/client/render/chunk/vertex/format/impl/CompactChunkVertex.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/format/impl/CompactChunkVertex.java index 77f52dccad..3224f8ca3e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/vertex/format/impl/CompactChunkVertex.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/format/impl/CompactChunkVertex.java @@ -1,10 +1,10 @@ -package me.jellysquid.mods.sodium.client.render.chunk.vertex.format.impl; +package net.caffeinemc.mods.sodium.client.render.chunk.vertex.format.impl; -import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexAttributeFormat; -import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexFormat; -import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkMeshAttribute; -import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexEncoder; -import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexType; +import net.caffeinemc.mods.sodium.client.gl.attribute.GlVertexAttributeFormat; +import net.caffeinemc.mods.sodium.client.gl.attribute.GlVertexFormat; +import net.caffeinemc.mods.sodium.client.render.chunk.vertex.format.ChunkMeshAttribute; +import net.caffeinemc.mods.sodium.client.render.chunk.vertex.format.ChunkVertexEncoder; +import net.caffeinemc.mods.sodium.client.render.chunk.vertex.format.ChunkVertexType; import org.lwjgl.system.MemoryUtil; public class CompactChunkVertex implements ChunkVertexType { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/immediate/CloudRenderer.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/immediate/CloudRenderer.java similarity index 99% rename from src/main/java/me/jellysquid/mods/sodium/client/render/immediate/CloudRenderer.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/immediate/CloudRenderer.java index be749d02c3..376fb3aeaf 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/immediate/CloudRenderer.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/immediate/CloudRenderer.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.immediate; +package net.caffeinemc.mods.sodium.client.render.immediate; import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.platform.NativeImage; @@ -12,7 +12,7 @@ import com.mojang.blaze3d.vertex.VertexFormat; import net.caffeinemc.mods.sodium.api.vertex.format.common.ColorVertex; import net.caffeinemc.mods.sodium.api.vertex.buffer.VertexBufferWriter; -import me.jellysquid.mods.sodium.client.util.MathUtil; +import net.caffeinemc.mods.sodium.client.util.MathUtil; import net.caffeinemc.mods.sodium.api.util.ColorABGR; import net.caffeinemc.mods.sodium.api.util.ColorARGB; import net.caffeinemc.mods.sodium.api.util.ColorMixer; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/immediate/model/BakedModelEncoder.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/immediate/model/BakedModelEncoder.java similarity index 96% rename from src/main/java/me/jellysquid/mods/sodium/client/render/immediate/model/BakedModelEncoder.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/immediate/model/BakedModelEncoder.java index 8efeedadac..e6c8d2cc90 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/immediate/model/BakedModelEncoder.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/immediate/model/BakedModelEncoder.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.client.render.immediate.model; +package net.caffeinemc.mods.sodium.client.render.immediate.model; import com.mojang.blaze3d.vertex.PoseStack; -import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; +import net.caffeinemc.mods.sodium.client.model.quad.ModelQuadView; import net.caffeinemc.mods.sodium.api.math.MatrixHelper; import net.caffeinemc.mods.sodium.api.util.ColorABGR; import net.caffeinemc.mods.sodium.api.util.ColorU8; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/immediate/model/EntityRenderer.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/immediate/model/EntityRenderer.java similarity index 99% rename from src/main/java/me/jellysquid/mods/sodium/client/render/immediate/model/EntityRenderer.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/immediate/model/EntityRenderer.java index 989e6a11cc..b49c4e18cb 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/immediate/model/EntityRenderer.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/immediate/model/EntityRenderer.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.immediate.model; +package net.caffeinemc.mods.sodium.client.render.immediate.model; import com.mojang.blaze3d.vertex.PoseStack; import net.caffeinemc.mods.sodium.api.math.MatrixHelper; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/immediate/model/ModelCuboid.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/immediate/model/ModelCuboid.java similarity index 96% rename from src/main/java/me/jellysquid/mods/sodium/client/render/immediate/model/ModelCuboid.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/immediate/model/ModelCuboid.java index 95b948f5b9..b08a1deeb6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/immediate/model/ModelCuboid.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/immediate/model/ModelCuboid.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.immediate.model; +package net.caffeinemc.mods.sodium.client.render.immediate.model; import org.joml.*; import java.util.Set; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/immediate/model/ModelPartData.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/immediate/model/ModelPartData.java similarity index 82% rename from src/main/java/me/jellysquid/mods/sodium/client/render/immediate/model/ModelPartData.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/immediate/model/ModelPartData.java index 00ab9145fb..a76a7c33be 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/immediate/model/ModelPartData.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/immediate/model/ModelPartData.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.immediate.model; +package net.caffeinemc.mods.sodium.client.render.immediate.model; import net.minecraft.client.model.geom.ModelPart; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/texture/SpriteContentsExtended.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/texture/SpriteContentsExtended.java similarity index 72% rename from src/main/java/me/jellysquid/mods/sodium/client/render/texture/SpriteContentsExtended.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/texture/SpriteContentsExtended.java index 97114fb3c6..5405c0b114 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/texture/SpriteContentsExtended.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/texture/SpriteContentsExtended.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.texture; +package net.caffeinemc.mods.sodium.client.render.texture; public interface SpriteContentsExtended { void sodium$setActive(boolean value); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/texture/SpriteUtil.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/texture/SpriteUtil.java similarity index 92% rename from src/main/java/me/jellysquid/mods/sodium/client/render/texture/SpriteUtil.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/texture/SpriteUtil.java index 2e059411f1..0f40213291 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/texture/SpriteUtil.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/texture/SpriteUtil.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.texture; +package net.caffeinemc.mods.sodium.client.render.texture; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/util/DeferredRenderTask.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/util/DeferredRenderTask.java similarity index 94% rename from src/main/java/me/jellysquid/mods/sodium/client/render/util/DeferredRenderTask.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/util/DeferredRenderTask.java index 83eeba3561..514c32a6d8 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/util/DeferredRenderTask.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/util/DeferredRenderTask.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.util; +package net.caffeinemc.mods.sodium.client.render.util; import java.util.concurrent.ConcurrentLinkedDeque; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/util/RenderAsserts.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/util/RenderAsserts.java similarity index 93% rename from src/main/java/me/jellysquid/mods/sodium/client/render/util/RenderAsserts.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/util/RenderAsserts.java index 2c744291b3..ea1ba9021c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/util/RenderAsserts.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/util/RenderAsserts.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.util; +package net.caffeinemc.mods.sodium.client.render.util; import com.mojang.blaze3d.systems.RenderSystem; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/vertex/VertexConsumerTracker.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/VertexConsumerTracker.java similarity index 88% rename from src/main/java/me/jellysquid/mods/sodium/client/render/vertex/VertexConsumerTracker.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/VertexConsumerTracker.java index abb9d02584..48a5fdb399 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/vertex/VertexConsumerTracker.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/VertexConsumerTracker.java @@ -1,10 +1,10 @@ -package me.jellysquid.mods.sodium.client.render.vertex; +package net.caffeinemc.mods.sodium.client.render.vertex; import com.mojang.blaze3d.vertex.VertexConsumer; import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; import it.unimi.dsi.fastutil.objects.ReferenceSet; import it.unimi.dsi.fastutil.objects.ReferenceSets; -import me.jellysquid.mods.sodium.client.SodiumClientMod; +import net.caffeinemc.mods.sodium.client.SodiumClientMod; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/vertex/VertexConsumerUtils.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/VertexConsumerUtils.java similarity index 92% rename from src/main/java/me/jellysquid/mods/sodium/client/render/vertex/VertexConsumerUtils.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/VertexConsumerUtils.java index ec795d0dd6..6118d3df41 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/vertex/VertexConsumerUtils.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/VertexConsumerUtils.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.vertex; +package net.caffeinemc.mods.sodium.client.render.vertex; import com.mojang.blaze3d.vertex.VertexConsumer; import net.caffeinemc.mods.sodium.api.vertex.buffer.VertexBufferWriter; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/vertex/VertexFormatDescriptionImpl.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/VertexFormatDescriptionImpl.java similarity index 95% rename from src/main/java/me/jellysquid/mods/sodium/client/render/vertex/VertexFormatDescriptionImpl.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/VertexFormatDescriptionImpl.java index 000d96890e..d0c878076a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/vertex/VertexFormatDescriptionImpl.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/VertexFormatDescriptionImpl.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.client.render.vertex; +package net.caffeinemc.mods.sodium.client.render.vertex; -import me.jellysquid.mods.sodium.mixin.core.render.VertexFormatAccessor; +import net.caffeinemc.mods.sodium.mixin.core.render.VertexFormatAccessor; import net.caffeinemc.mods.sodium.api.vertex.attributes.CommonVertexAttribute; import net.caffeinemc.mods.sodium.api.vertex.format.VertexFormatDescription; import com.google.common.collect.ImmutableList; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/vertex/VertexFormatRegistryImpl.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/VertexFormatRegistryImpl.java similarity index 96% rename from src/main/java/me/jellysquid/mods/sodium/client/render/vertex/VertexFormatRegistryImpl.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/VertexFormatRegistryImpl.java index 4fb3a4d5aa..d538a78b39 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/vertex/VertexFormatRegistryImpl.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/VertexFormatRegistryImpl.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.vertex; +package net.caffeinemc.mods.sodium.client.render.vertex; import com.mojang.blaze3d.vertex.VertexFormat; import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/vertex/buffer/ExtendedBufferBuilder.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/buffer/ExtendedBufferBuilder.java similarity index 88% rename from src/main/java/me/jellysquid/mods/sodium/client/render/vertex/buffer/ExtendedBufferBuilder.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/buffer/ExtendedBufferBuilder.java index 5caf3d12ef..3c05cde52f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/vertex/buffer/ExtendedBufferBuilder.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/buffer/ExtendedBufferBuilder.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.vertex.buffer; +package net.caffeinemc.mods.sodium.client.render.vertex.buffer; import net.caffeinemc.mods.sodium.api.vertex.buffer.VertexBufferWriter; import net.caffeinemc.mods.sodium.api.vertex.format.VertexFormatDescription; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/vertex/buffer/SodiumBufferBuilder.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/buffer/SodiumBufferBuilder.java similarity index 99% rename from src/main/java/me/jellysquid/mods/sodium/client/render/vertex/buffer/SodiumBufferBuilder.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/buffer/SodiumBufferBuilder.java index bab08e76da..f6fc5ad183 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/vertex/buffer/SodiumBufferBuilder.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/buffer/SodiumBufferBuilder.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.vertex.buffer; +package net.caffeinemc.mods.sodium.client.render.vertex.buffer; import com.mojang.blaze3d.vertex.BufferBuilder; import com.mojang.blaze3d.vertex.VertexConsumer; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/vertex/serializers/VertexSerializerRegistryImpl.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/serializers/VertexSerializerRegistryImpl.java similarity index 96% rename from src/main/java/me/jellysquid/mods/sodium/client/render/vertex/serializers/VertexSerializerRegistryImpl.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/serializers/VertexSerializerRegistryImpl.java index 52902f7239..ff85ca4f34 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/vertex/serializers/VertexSerializerRegistryImpl.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/serializers/VertexSerializerRegistryImpl.java @@ -1,8 +1,8 @@ -package me.jellysquid.mods.sodium.client.render.vertex.serializers; +package net.caffeinemc.mods.sodium.client.render.vertex.serializers; import it.unimi.dsi.fastutil.longs.Long2ReferenceMap; import it.unimi.dsi.fastutil.longs.Long2ReferenceOpenHashMap; -import me.jellysquid.mods.sodium.client.render.vertex.serializers.generated.VertexSerializerFactory; +import net.caffeinemc.mods.sodium.client.render.vertex.serializers.generated.VertexSerializerFactory; import net.caffeinemc.mods.sodium.api.vertex.format.VertexFormatDescription; import net.caffeinemc.mods.sodium.api.vertex.serializer.VertexSerializer; import net.caffeinemc.mods.sodium.api.vertex.serializer.VertexSerializerRegistry; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/vertex/serializers/generated/VertexSerializerFactory.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/serializers/generated/VertexSerializerFactory.java similarity index 99% rename from src/main/java/me/jellysquid/mods/sodium/client/render/vertex/serializers/generated/VertexSerializerFactory.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/serializers/generated/VertexSerializerFactory.java index 3903f3c1fe..517d7182c1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/vertex/serializers/generated/VertexSerializerFactory.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/serializers/generated/VertexSerializerFactory.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.vertex.serializers.generated; +package net.caffeinemc.mods.sodium.client.render.vertex.serializers.generated; import net.caffeinemc.mods.sodium.api.vertex.attributes.CommonVertexAttribute; import net.caffeinemc.mods.sodium.api.vertex.format.VertexFormatDescription; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/viewport/CameraTransform.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/viewport/CameraTransform.java similarity index 90% rename from src/main/java/me/jellysquid/mods/sodium/client/render/viewport/CameraTransform.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/viewport/CameraTransform.java index ca7bed4b98..9a18e0bd7d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/viewport/CameraTransform.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/viewport/CameraTransform.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.client.render.viewport; +package net.caffeinemc.mods.sodium.client.render.viewport; -import me.jellysquid.mods.sodium.client.render.chunk.region.RenderRegion; +import net.caffeinemc.mods.sodium.client.render.chunk.region.RenderRegion; public class CameraTransform { // We want to reduce the precision of the deltas to avoid seams along chunk/region boundaries. This is done by diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/viewport/Viewport.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/viewport/Viewport.java similarity index 92% rename from src/main/java/me/jellysquid/mods/sodium/client/render/viewport/Viewport.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/viewport/Viewport.java index 4ef000ef5e..0c10cc5025 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/viewport/Viewport.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/viewport/Viewport.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.client.render.viewport; +package net.caffeinemc.mods.sodium.client.render.viewport; -import me.jellysquid.mods.sodium.client.render.viewport.frustum.Frustum; +import net.caffeinemc.mods.sodium.client.render.viewport.frustum.Frustum; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; import org.joml.Vector3d; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/viewport/ViewportProvider.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/viewport/ViewportProvider.java similarity index 56% rename from src/main/java/me/jellysquid/mods/sodium/client/render/viewport/ViewportProvider.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/viewport/ViewportProvider.java index c501962cd6..2ccf98c343 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/viewport/ViewportProvider.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/viewport/ViewportProvider.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.viewport; +package net.caffeinemc.mods.sodium.client.render.viewport; public interface ViewportProvider { Viewport sodium$createViewport(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/viewport/frustum/Frustum.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/viewport/frustum/Frustum.java similarity index 64% rename from src/main/java/me/jellysquid/mods/sodium/client/render/viewport/frustum/Frustum.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/viewport/frustum/Frustum.java index e1e8a61284..3ec8d16aa6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/viewport/frustum/Frustum.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/viewport/frustum/Frustum.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.viewport.frustum; +package net.caffeinemc.mods.sodium.client.render.viewport.frustum; public interface Frustum { boolean testAab(float minX, float minY, float minZ, float maxX, float maxY, float maxZ); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/viewport/frustum/SimpleFrustum.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/viewport/frustum/SimpleFrustum.java similarity index 87% rename from src/main/java/me/jellysquid/mods/sodium/client/render/viewport/frustum/SimpleFrustum.java rename to src/main/java/net/caffeinemc/mods/sodium/client/render/viewport/frustum/SimpleFrustum.java index da4b828c18..88ff3b7738 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/viewport/frustum/SimpleFrustum.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/viewport/frustum/SimpleFrustum.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.render.viewport.frustum; +package net.caffeinemc.mods.sodium.client.render.viewport.frustum; import org.joml.FrustumIntersection; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/BitwiseMath.java b/src/main/java/net/caffeinemc/mods/sodium/client/util/BitwiseMath.java similarity index 88% rename from src/main/java/me/jellysquid/mods/sodium/client/util/BitwiseMath.java rename to src/main/java/net/caffeinemc/mods/sodium/client/util/BitwiseMath.java index 13664d9779..0aaf2a8816 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/BitwiseMath.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/util/BitwiseMath.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.util; +package net.caffeinemc.mods.sodium.client.util; public class BitwiseMath { // returns (1) if (a < b), otherwise (0) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/Dim2i.java b/src/main/java/net/caffeinemc/mods/sodium/client/util/Dim2i.java similarity index 91% rename from src/main/java/me/jellysquid/mods/sodium/client/util/Dim2i.java rename to src/main/java/net/caffeinemc/mods/sodium/client/util/Dim2i.java index 3ef2af1cc3..2ce45dd3c6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/Dim2i.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/util/Dim2i.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.util; +package net.caffeinemc.mods.sodium.client.util; public record Dim2i(int x, int y, int width, int height) { public int getLimitX() { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/DirectionUtil.java b/src/main/java/net/caffeinemc/mods/sodium/client/util/DirectionUtil.java similarity index 94% rename from src/main/java/me/jellysquid/mods/sodium/client/util/DirectionUtil.java rename to src/main/java/net/caffeinemc/mods/sodium/client/util/DirectionUtil.java index 13c1daecd8..1ecce88151 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/DirectionUtil.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/util/DirectionUtil.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.util; +package net.caffeinemc.mods.sodium.client.util; import java.util.Arrays; import net.minecraft.core.Direction; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/FileUtil.java b/src/main/java/net/caffeinemc/mods/sodium/client/util/FileUtil.java similarity index 93% rename from src/main/java/me/jellysquid/mods/sodium/client/util/FileUtil.java rename to src/main/java/net/caffeinemc/mods/sodium/client/util/FileUtil.java index 6ec2278e58..89a2d8084c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/FileUtil.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/util/FileUtil.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.util; +package net.caffeinemc.mods.sodium.client.util; import java.io.IOException; import java.nio.file.Files; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/FlawlessFrames.java b/src/main/java/net/caffeinemc/mods/sodium/client/util/FlawlessFrames.java similarity index 96% rename from src/main/java/me/jellysquid/mods/sodium/client/util/FlawlessFrames.java rename to src/main/java/net/caffeinemc/mods/sodium/client/util/FlawlessFrames.java index f13da8e713..ed42b33fca 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/FlawlessFrames.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/util/FlawlessFrames.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.util; +package net.caffeinemc.mods.sodium.client.util; import net.fabricmc.loader.api.FabricLoader; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/ListUtil.java b/src/main/java/net/caffeinemc/mods/sodium/client/util/ListUtil.java similarity index 87% rename from src/main/java/me/jellysquid/mods/sodium/client/util/ListUtil.java rename to src/main/java/net/caffeinemc/mods/sodium/client/util/ListUtil.java index 90e0a5e0dd..2e886edc0b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/ListUtil.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/util/ListUtil.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.util; +package net.caffeinemc.mods.sodium.client.util; import java.util.Collection; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/MathUtil.java b/src/main/java/net/caffeinemc/mods/sodium/client/util/MathUtil.java similarity index 96% rename from src/main/java/me/jellysquid/mods/sodium/client/util/MathUtil.java rename to src/main/java/net/caffeinemc/mods/sodium/client/util/MathUtil.java index 85a5390083..8c41de06ec 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/MathUtil.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/util/MathUtil.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.util; +package net.caffeinemc.mods.sodium.client.util; public class MathUtil { /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/ModelQuadUtil.java b/src/main/java/net/caffeinemc/mods/sodium/client/util/ModelQuadUtil.java similarity index 97% rename from src/main/java/me/jellysquid/mods/sodium/client/util/ModelQuadUtil.java rename to src/main/java/net/caffeinemc/mods/sodium/client/util/ModelQuadUtil.java index 8fa692bea4..a2cd31a62d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/ModelQuadUtil.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/util/ModelQuadUtil.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.util; +package net.caffeinemc.mods.sodium.client.util; /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/NativeBuffer.java b/src/main/java/net/caffeinemc/mods/sodium/client/util/NativeBuffer.java similarity index 97% rename from src/main/java/me/jellysquid/mods/sodium/client/util/NativeBuffer.java rename to src/main/java/net/caffeinemc/mods/sodium/client/util/NativeBuffer.java index 4786055b1e..ad047c2018 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/NativeBuffer.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/util/NativeBuffer.java @@ -1,9 +1,9 @@ -package me.jellysquid.mods.sodium.client.util; +package net.caffeinemc.mods.sodium.client.util; import it.unimi.dsi.fastutil.objects.Reference2ReferenceMap; import it.unimi.dsi.fastutil.objects.Reference2ReferenceMaps; import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; -import me.jellysquid.mods.sodium.client.SodiumClientMod; +import net.caffeinemc.mods.sodium.client.SodiumClientMod; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.lwjgl.system.MemoryUtil; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/NativeImageHelper.java b/src/main/java/net/caffeinemc/mods/sodium/client/util/NativeImageHelper.java similarity index 82% rename from src/main/java/me/jellysquid/mods/sodium/client/util/NativeImageHelper.java rename to src/main/java/net/caffeinemc/mods/sodium/client/util/NativeImageHelper.java index 625f1961af..6f7d846c4c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/NativeImageHelper.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/util/NativeImageHelper.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.client.util; +package net.caffeinemc.mods.sodium.client.util; -import me.jellysquid.mods.sodium.mixin.features.textures.NativeImageAccessor; +import net.caffeinemc.mods.sodium.mixin.features.textures.NativeImageAccessor; import com.mojang.blaze3d.platform.NativeImage; import java.util.Locale; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/TextureUtil.java b/src/main/java/net/caffeinemc/mods/sodium/client/util/TextureUtil.java similarity index 89% rename from src/main/java/me/jellysquid/mods/sodium/client/util/TextureUtil.java rename to src/main/java/net/caffeinemc/mods/sodium/client/util/TextureUtil.java index a32bf609c3..29ab22ceb2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/TextureUtil.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/util/TextureUtil.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.util; +package net.caffeinemc.mods.sodium.client.util; import com.mojang.blaze3d.systems.RenderSystem; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/collections/BitArray.java b/src/main/java/net/caffeinemc/mods/sodium/client/util/collections/BitArray.java similarity index 99% rename from src/main/java/me/jellysquid/mods/sodium/client/util/collections/BitArray.java rename to src/main/java/net/caffeinemc/mods/sodium/client/util/collections/BitArray.java index 659952dc7a..333282a930 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/collections/BitArray.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/util/collections/BitArray.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.util.collections; +package net.caffeinemc.mods.sodium.client.util.collections; import java.util.Arrays; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/collections/DoubleBufferedQueue.java b/src/main/java/net/caffeinemc/mods/sodium/client/util/collections/DoubleBufferedQueue.java similarity index 97% rename from src/main/java/me/jellysquid/mods/sodium/client/util/collections/DoubleBufferedQueue.java rename to src/main/java/net/caffeinemc/mods/sodium/client/util/collections/DoubleBufferedQueue.java index 2aa30f4c7e..605623eb66 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/collections/DoubleBufferedQueue.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/util/collections/DoubleBufferedQueue.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.util.collections; +package net.caffeinemc.mods.sodium.client.util.collections; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/collections/ReadQueue.java b/src/main/java/net/caffeinemc/mods/sodium/client/util/collections/ReadQueue.java similarity index 63% rename from src/main/java/me/jellysquid/mods/sodium/client/util/collections/ReadQueue.java rename to src/main/java/net/caffeinemc/mods/sodium/client/util/collections/ReadQueue.java index 86827a4231..835525c7d9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/collections/ReadQueue.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/util/collections/ReadQueue.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.util.collections; +package net.caffeinemc.mods.sodium.client.util.collections; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/collections/WriteQueue.java b/src/main/java/net/caffeinemc/mods/sodium/client/util/collections/WriteQueue.java similarity index 71% rename from src/main/java/me/jellysquid/mods/sodium/client/util/collections/WriteQueue.java rename to src/main/java/net/caffeinemc/mods/sodium/client/util/collections/WriteQueue.java index 1a2cac5f4c..061ebd16cc 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/collections/WriteQueue.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/util/collections/WriteQueue.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.util.collections; +package net.caffeinemc.mods.sodium.client.util.collections; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/color/BoxBlur.java b/src/main/java/net/caffeinemc/mods/sodium/client/util/color/BoxBlur.java similarity index 98% rename from src/main/java/me/jellysquid/mods/sodium/client/util/color/BoxBlur.java rename to src/main/java/net/caffeinemc/mods/sodium/client/util/color/BoxBlur.java index 2058e1c01e..f3b2d70640 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/color/BoxBlur.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/util/color/BoxBlur.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.util.color; +package net.caffeinemc.mods.sodium.client.util.color; import net.caffeinemc.mods.sodium.api.util.ColorARGB; import net.minecraft.util.Mth; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/color/ColorSRGB.java b/src/main/java/net/caffeinemc/mods/sodium/client/util/color/ColorSRGB.java similarity index 99% rename from src/main/java/me/jellysquid/mods/sodium/client/util/color/ColorSRGB.java rename to src/main/java/net/caffeinemc/mods/sodium/client/util/color/ColorSRGB.java index 519d1387a7..1c5a1aef67 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/color/ColorSRGB.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/util/color/ColorSRGB.java @@ -1,5 +1,5 @@ -package me.jellysquid.mods.sodium.client.util.color; +package net.caffeinemc.mods.sodium.client.util.color; import net.minecraft.util.FastColor; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/color/FastCubicSampler.java b/src/main/java/net/caffeinemc/mods/sodium/client/util/color/FastCubicSampler.java similarity index 98% rename from src/main/java/me/jellysquid/mods/sodium/client/util/color/FastCubicSampler.java rename to src/main/java/net/caffeinemc/mods/sodium/client/util/color/FastCubicSampler.java index b9e68cd450..251a1feb2a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/color/FastCubicSampler.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/util/color/FastCubicSampler.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.util.color; +package net.caffeinemc.mods.sodium.client.util.color; import java.util.function.Function; import net.minecraft.util.Mth; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/iterator/ByteArrayIterator.java b/src/main/java/net/caffeinemc/mods/sodium/client/util/iterator/ByteArrayIterator.java similarity index 92% rename from src/main/java/me/jellysquid/mods/sodium/client/util/iterator/ByteArrayIterator.java rename to src/main/java/net/caffeinemc/mods/sodium/client/util/iterator/ByteArrayIterator.java index 4e705413d0..44fcf15b87 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/iterator/ByteArrayIterator.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/util/iterator/ByteArrayIterator.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.util.iterator; +package net.caffeinemc.mods.sodium.client.util.iterator; import java.util.NoSuchElementException; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/iterator/ByteIterator.java b/src/main/java/net/caffeinemc/mods/sodium/client/util/iterator/ByteIterator.java similarity index 59% rename from src/main/java/me/jellysquid/mods/sodium/client/util/iterator/ByteIterator.java rename to src/main/java/net/caffeinemc/mods/sodium/client/util/iterator/ByteIterator.java index 4b2d3aba03..83936061e7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/iterator/ByteIterator.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/util/iterator/ByteIterator.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.util.iterator; +package net.caffeinemc.mods.sodium.client.util.iterator; public interface ByteIterator { boolean hasNext(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/iterator/ReversibleByteArrayIterator.java b/src/main/java/net/caffeinemc/mods/sodium/client/util/iterator/ReversibleByteArrayIterator.java similarity index 93% rename from src/main/java/me/jellysquid/mods/sodium/client/util/iterator/ReversibleByteArrayIterator.java rename to src/main/java/net/caffeinemc/mods/sodium/client/util/iterator/ReversibleByteArrayIterator.java index 672de899a0..09b1e4fedd 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/iterator/ReversibleByteArrayIterator.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/util/iterator/ReversibleByteArrayIterator.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.util.iterator; +package net.caffeinemc.mods.sodium.client.util.iterator; import java.util.NoSuchElementException; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/iterator/ReversibleObjectArrayIterator.java b/src/main/java/net/caffeinemc/mods/sodium/client/util/iterator/ReversibleObjectArrayIterator.java similarity index 94% rename from src/main/java/me/jellysquid/mods/sodium/client/util/iterator/ReversibleObjectArrayIterator.java rename to src/main/java/net/caffeinemc/mods/sodium/client/util/iterator/ReversibleObjectArrayIterator.java index 26e617d213..ea8010a003 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/iterator/ReversibleObjectArrayIterator.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/util/iterator/ReversibleObjectArrayIterator.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.util.iterator; +package net.caffeinemc.mods.sodium.client.util.iterator; import it.unimi.dsi.fastutil.objects.ObjectArrayList; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/AbstractSort.java b/src/main/java/net/caffeinemc/mods/sodium/client/util/sorting/AbstractSort.java similarity index 81% rename from src/main/java/me/jellysquid/mods/sodium/client/util/sorting/AbstractSort.java rename to src/main/java/net/caffeinemc/mods/sodium/client/util/sorting/AbstractSort.java index 7fb51b5efd..93fd652f6e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/AbstractSort.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/util/sorting/AbstractSort.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.util.sorting; +package net.caffeinemc.mods.sodium.client.util.sorting; public class AbstractSort { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/InsertionSort.java b/src/main/java/net/caffeinemc/mods/sodium/client/util/sorting/InsertionSort.java similarity index 91% rename from src/main/java/me/jellysquid/mods/sodium/client/util/sorting/InsertionSort.java rename to src/main/java/net/caffeinemc/mods/sodium/client/util/sorting/InsertionSort.java index 52ab97bdf7..08dfbc4ef9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/InsertionSort.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/util/sorting/InsertionSort.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.util.sorting; +package net.caffeinemc.mods.sodium.client.util.sorting; public class InsertionSort extends AbstractSort { public static void insertionSort(final int[] indices, final int fromIndex, final int toIndex, final float[] keys) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/MergeSort.java b/src/main/java/net/caffeinemc/mods/sodium/client/util/sorting/MergeSort.java similarity index 98% rename from src/main/java/me/jellysquid/mods/sodium/client/util/sorting/MergeSort.java rename to src/main/java/net/caffeinemc/mods/sodium/client/util/sorting/MergeSort.java index bdc3ad456c..5083da0274 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/MergeSort.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/util/sorting/MergeSort.java @@ -27,7 +27,7 @@ * suitability of this software for any purpose. It is provided "as is" * without expressed or implied warranty. */ -package me.jellysquid.mods.sodium.client.util.sorting; +package net.caffeinemc.mods.sodium.client.util.sorting; /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/RadixSort.java b/src/main/java/net/caffeinemc/mods/sodium/client/util/sorting/RadixSort.java similarity index 97% rename from src/main/java/me/jellysquid/mods/sodium/client/util/sorting/RadixSort.java rename to src/main/java/net/caffeinemc/mods/sodium/client/util/sorting/RadixSort.java index 9ce87308f6..00aedcb426 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/RadixSort.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/util/sorting/RadixSort.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.util.sorting; +package net.caffeinemc.mods.sodium.client.util.sorting; public class RadixSort extends AbstractSort { public static final int RADIX_SORT_THRESHOLD = 64; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/VertexSorters.java b/src/main/java/net/caffeinemc/mods/sodium/client/util/sorting/VertexSorters.java similarity index 95% rename from src/main/java/me/jellysquid/mods/sodium/client/util/sorting/VertexSorters.java rename to src/main/java/net/caffeinemc/mods/sodium/client/util/sorting/VertexSorters.java index 55590591e6..c612d3cca3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/sorting/VertexSorters.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/util/sorting/VertexSorters.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.util.sorting; +package net.caffeinemc.mods.sodium.client.util.sorting; import com.mojang.blaze3d.vertex.VertexSorting; import org.joml.Vector3f; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/task/CancellationToken.java b/src/main/java/net/caffeinemc/mods/sodium/client/util/task/CancellationToken.java similarity index 63% rename from src/main/java/me/jellysquid/mods/sodium/client/util/task/CancellationToken.java rename to src/main/java/net/caffeinemc/mods/sodium/client/util/task/CancellationToken.java index 22be14957c..7ebe731d18 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/task/CancellationToken.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/util/task/CancellationToken.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.util.task; +package net.caffeinemc.mods.sodium.client.util.task; public interface CancellationToken { boolean isCancelled(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/BiomeSeedProvider.java b/src/main/java/net/caffeinemc/mods/sodium/client/world/BiomeSeedProvider.java similarity index 83% rename from src/main/java/me/jellysquid/mods/sodium/client/world/BiomeSeedProvider.java rename to src/main/java/net/caffeinemc/mods/sodium/client/world/BiomeSeedProvider.java index 596dd37728..b4f4a49dfc 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/BiomeSeedProvider.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/world/BiomeSeedProvider.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.world; +package net.caffeinemc.mods.sodium.client.world; import net.minecraft.client.multiplayer.ClientLevel; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/PaletteStorageExtended.java b/src/main/java/net/caffeinemc/mods/sodium/client/world/PaletteStorageExtended.java similarity index 75% rename from src/main/java/me/jellysquid/mods/sodium/client/world/PaletteStorageExtended.java rename to src/main/java/net/caffeinemc/mods/sodium/client/world/PaletteStorageExtended.java index 412ab28ee7..ef4e2405ee 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/PaletteStorageExtended.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/world/PaletteStorageExtended.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.world; +package net.caffeinemc.mods.sodium.client.world; import net.minecraft.world.level.chunk.Palette; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/ReadableContainerExtended.java b/src/main/java/net/caffeinemc/mods/sodium/client/world/ReadableContainerExtended.java similarity index 93% rename from src/main/java/me/jellysquid/mods/sodium/client/world/ReadableContainerExtended.java rename to src/main/java/net/caffeinemc/mods/sodium/client/world/ReadableContainerExtended.java index 13b6f1e723..e1260f6e8f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/ReadableContainerExtended.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/world/ReadableContainerExtended.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.world; +package net.caffeinemc.mods.sodium.client.world; import net.minecraft.world.level.chunk.PalettedContainerRO; diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/world/WorldRendererExtended.java b/src/main/java/net/caffeinemc/mods/sodium/client/world/WorldRendererExtended.java new file mode 100644 index 0000000000..981966720b --- /dev/null +++ b/src/main/java/net/caffeinemc/mods/sodium/client/world/WorldRendererExtended.java @@ -0,0 +1,7 @@ +package net.caffeinemc.mods.sodium.client.world; + +import net.caffeinemc.mods.sodium.client.render.SodiumWorldRenderer; + +public interface WorldRendererExtended { + SodiumWorldRenderer sodium$getWorldRenderer(); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java b/src/main/java/net/caffeinemc/mods/sodium/client/world/WorldSlice.java similarity index 96% rename from src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java rename to src/main/java/net/caffeinemc/mods/sodium/client/world/WorldSlice.java index f3eef1e245..b0b4b62007 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/world/WorldSlice.java @@ -1,13 +1,13 @@ -package me.jellysquid.mods.sodium.client.world; +package net.caffeinemc.mods.sodium.client.world; import it.unimi.dsi.fastutil.ints.Int2ReferenceMap; -import me.jellysquid.mods.sodium.client.world.biome.BiomeColorCache; -import me.jellysquid.mods.sodium.client.world.biome.BiomeColorSource; -import me.jellysquid.mods.sodium.client.world.biome.BiomeColorView; -import me.jellysquid.mods.sodium.client.world.biome.BiomeSlice; -import me.jellysquid.mods.sodium.client.world.cloned.ChunkRenderContext; -import me.jellysquid.mods.sodium.client.world.cloned.ClonedChunkSection; -import me.jellysquid.mods.sodium.client.world.cloned.ClonedChunkSectionCache; +import net.caffeinemc.mods.sodium.client.world.biome.BiomeColorCache; +import net.caffeinemc.mods.sodium.client.world.biome.BiomeColorSource; +import net.caffeinemc.mods.sodium.client.world.biome.BiomeColorView; +import net.caffeinemc.mods.sodium.client.world.biome.BiomeSlice; +import net.caffeinemc.mods.sodium.client.world.cloned.ChunkRenderContext; +import net.caffeinemc.mods.sodium.client.world.cloned.ClonedChunkSection; +import net.caffeinemc.mods.sodium.client.world.cloned.ClonedChunkSectionCache; import net.fabricmc.fabric.api.rendering.data.v1.RenderAttachedBlockView; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientLevel; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeColorCache.java b/src/main/java/net/caffeinemc/mods/sodium/client/world/biome/BiomeColorCache.java similarity index 94% rename from src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeColorCache.java rename to src/main/java/net/caffeinemc/mods/sodium/client/world/biome/BiomeColorCache.java index 0a5e3a9577..bfed67b0ae 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeColorCache.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/world/biome/BiomeColorCache.java @@ -1,9 +1,9 @@ -package me.jellysquid.mods.sodium.client.world.biome; +package net.caffeinemc.mods.sodium.client.world.biome; import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; -import me.jellysquid.mods.sodium.client.util.color.BoxBlur; -import me.jellysquid.mods.sodium.client.util.color.BoxBlur.ColorBuffer; -import me.jellysquid.mods.sodium.client.world.cloned.ChunkRenderContext; +import net.caffeinemc.mods.sodium.client.util.color.BoxBlur; +import net.caffeinemc.mods.sodium.client.util.color.BoxBlur.ColorBuffer; +import net.caffeinemc.mods.sodium.client.world.cloned.ChunkRenderContext; import net.minecraft.client.renderer.BiomeColors; import net.minecraft.util.Mth; import net.minecraft.world.level.ColorResolver; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeColorMaps.java b/src/main/java/net/caffeinemc/mods/sodium/client/world/biome/BiomeColorMaps.java similarity index 95% rename from src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeColorMaps.java rename to src/main/java/net/caffeinemc/mods/sodium/client/world/biome/BiomeColorMaps.java index c89a326078..0e3ff9f521 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeColorMaps.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/world/biome/BiomeColorMaps.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.world.biome; +package net.caffeinemc.mods.sodium.client.world.biome; import net.minecraft.world.level.FoliageColor; import net.minecraft.world.level.GrassColor; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeColorSource.java b/src/main/java/net/caffeinemc/mods/sodium/client/world/biome/BiomeColorSource.java similarity index 92% rename from src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeColorSource.java rename to src/main/java/net/caffeinemc/mods/sodium/client/world/biome/BiomeColorSource.java index f7777a2ba2..c8c13129dd 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeColorSource.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/world/biome/BiomeColorSource.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.world.biome; +package net.caffeinemc.mods.sodium.client.world.biome; import net.minecraft.client.renderer.BiomeColors; import net.minecraft.world.level.ColorResolver; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeColorView.java b/src/main/java/net/caffeinemc/mods/sodium/client/world/biome/BiomeColorView.java similarity index 68% rename from src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeColorView.java rename to src/main/java/net/caffeinemc/mods/sodium/client/world/biome/BiomeColorView.java index 6bfdd2a43b..e064e75476 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeColorView.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/world/biome/BiomeColorView.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.world.biome; +package net.caffeinemc.mods.sodium.client.world.biome; public interface BiomeColorView { int getColor(BiomeColorSource resolver, int blockX, int blockY, int blockZ); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeSlice.java b/src/main/java/net/caffeinemc/mods/sodium/client/world/biome/BiomeSlice.java similarity index 96% rename from src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeSlice.java rename to src/main/java/net/caffeinemc/mods/sodium/client/world/biome/BiomeSlice.java index 088e20edb9..223d58c94d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeSlice.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/world/biome/BiomeSlice.java @@ -1,9 +1,9 @@ -package me.jellysquid.mods.sodium.client.world.biome; +package net.caffeinemc.mods.sodium.client.world.biome; -import me.jellysquid.mods.sodium.client.world.BiomeSeedProvider; -import me.jellysquid.mods.sodium.client.world.WorldSlice; -import me.jellysquid.mods.sodium.client.world.cloned.ChunkRenderContext; -import me.jellysquid.mods.sodium.client.world.cloned.ClonedChunkSection; +import net.caffeinemc.mods.sodium.client.world.BiomeSeedProvider; +import net.caffeinemc.mods.sodium.client.world.WorldSlice; +import net.caffeinemc.mods.sodium.client.world.cloned.ChunkRenderContext; +import net.caffeinemc.mods.sodium.client.world.cloned.ClonedChunkSection; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.core.Holder; import net.minecraft.core.Holder.Reference; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ChunkRenderContext.java b/src/main/java/net/caffeinemc/mods/sodium/client/world/cloned/ChunkRenderContext.java similarity index 92% rename from src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ChunkRenderContext.java rename to src/main/java/net/caffeinemc/mods/sodium/client/world/cloned/ChunkRenderContext.java index ffcad4d750..0866e4e2b9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ChunkRenderContext.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/world/cloned/ChunkRenderContext.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.world.cloned; +package net.caffeinemc.mods.sodium.client.world.cloned; import net.minecraft.core.SectionPos; import net.minecraft.world.level.levelgen.structure.BoundingBox; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java b/src/main/java/net/caffeinemc/mods/sodium/client/world/cloned/ClonedChunkSection.java similarity index 97% rename from src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java rename to src/main/java/net/caffeinemc/mods/sodium/client/world/cloned/ClonedChunkSection.java index 16df518764..13a69b6d51 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/world/cloned/ClonedChunkSection.java @@ -1,11 +1,11 @@ -package me.jellysquid.mods.sodium.client.world.cloned; +package net.caffeinemc.mods.sodium.client.world.cloned; import it.unimi.dsi.fastutil.ints.Int2ReferenceMap; import it.unimi.dsi.fastutil.ints.Int2ReferenceMap.Entry; import it.unimi.dsi.fastutil.ints.Int2ReferenceMaps; import it.unimi.dsi.fastutil.ints.Int2ReferenceOpenHashMap; -import me.jellysquid.mods.sodium.client.world.ReadableContainerExtended; -import me.jellysquid.mods.sodium.client.world.WorldSlice; +import net.caffeinemc.mods.sodium.client.world.ReadableContainerExtended; +import net.caffeinemc.mods.sodium.client.world.WorldSlice; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.SectionPos; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSectionCache.java b/src/main/java/net/caffeinemc/mods/sodium/client/world/cloned/ClonedChunkSectionCache.java similarity index 97% rename from src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSectionCache.java rename to src/main/java/net/caffeinemc/mods/sodium/client/world/cloned/ClonedChunkSectionCache.java index aa46f27df3..e7a60946ad 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSectionCache.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/world/cloned/ClonedChunkSectionCache.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.client.world.cloned; +package net.caffeinemc.mods.sodium.client.world.cloned; import it.unimi.dsi.fastutil.longs.Long2ReferenceLinkedOpenHashMap; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/MixinOption.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/MixinOption.java similarity index 97% rename from src/main/java/me/jellysquid/mods/sodium/mixin/MixinOption.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/MixinOption.java index 1741cca50a..9bd7483af2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/MixinOption.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/MixinOption.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.mixin; +package net.caffeinemc.mods.sodium.mixin; import java.util.Collection; import java.util.Collections; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/SodiumMixinPlugin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/SodiumMixinPlugin.java similarity index 93% rename from src/main/java/me/jellysquid/mods/sodium/mixin/SodiumMixinPlugin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/SodiumMixinPlugin.java index cdd27181c5..8405d2ba23 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/SodiumMixinPlugin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/SodiumMixinPlugin.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.mixin; +package net.caffeinemc.mods.sodium.mixin; -import me.jellysquid.mods.sodium.client.data.config.MixinConfig; +import net.caffeinemc.mods.sodium.client.data.config.MixinConfig; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.objectweb.asm.tree.ClassNode; @@ -13,7 +13,7 @@ @SuppressWarnings("unused") public class SodiumMixinPlugin implements IMixinConfigPlugin { - private static final String MIXIN_PACKAGE_ROOT = "me.jellysquid.mods.sodium.mixin."; + private static final String MIXIN_PACKAGE_ROOT = "net.caffeinemc.mods.sodium.mixin."; private final Logger logger = LogManager.getLogger("Sodium"); private MixinConfig config; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/MinecraftClientMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/MinecraftClientMixin.java similarity index 94% rename from src/main/java/me/jellysquid/mods/sodium/mixin/core/MinecraftClientMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/core/MinecraftClientMixin.java index 8a9d843a20..7fada66ab5 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/MinecraftClientMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/MinecraftClientMixin.java @@ -1,12 +1,12 @@ -package me.jellysquid.mods.sodium.mixin.core; +package net.caffeinemc.mods.sodium.mixin.core; import it.unimi.dsi.fastutil.longs.LongArrayFIFOQueue; -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import me.jellysquid.mods.sodium.client.gui.screen.ConfigCorruptedScreen; +import net.caffeinemc.mods.sodium.client.SodiumClientMod; +import net.caffeinemc.mods.sodium.client.gui.screen.ConfigCorruptedScreen; import net.minecraft.client.Minecraft; import net.minecraft.server.packs.resources.ReloadableResourceManager; import net.minecraft.util.profiling.ProfilerFiller; -import me.jellysquid.mods.sodium.client.compatibility.checks.ResourcePackScanner; +import net.caffeinemc.mods.sodium.client.compatibility.checks.ResourcePackScanner; import org.lwjgl.opengl.GL32C; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/WindowMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/WindowMixin.java similarity index 81% rename from src/main/java/me/jellysquid/mods/sodium/mixin/core/WindowMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/core/WindowMixin.java index 63aece3fe9..8cc6e9619b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/WindowMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/WindowMixin.java @@ -1,8 +1,8 @@ -package me.jellysquid.mods.sodium.mixin.core; +package net.caffeinemc.mods.sodium.mixin.core; import com.mojang.blaze3d.platform.Window; -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import me.jellysquid.mods.sodium.client.compatibility.workarounds.Workarounds; +import net.caffeinemc.mods.sodium.client.SodiumClientMod; +import net.caffeinemc.mods.sodium.client.compatibility.workarounds.Workarounds; import org.lwjgl.glfw.GLFW; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/gui/WorldLoadingStateMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/gui/WorldLoadingStateMixin.java similarity index 95% rename from src/main/java/me/jellysquid/mods/sodium/mixin/core/gui/WorldLoadingStateMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/core/gui/WorldLoadingStateMixin.java index 0795a9fa24..a61bbdbd88 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/gui/WorldLoadingStateMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/gui/WorldLoadingStateMixin.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.mixin.core.gui; +package net.caffeinemc.mods.sodium.mixin.core.gui; import net.minecraft.client.multiplayer.LevelLoadStatusManager; import net.minecraft.client.player.LocalPlayer; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/model/colors/BlockColorsMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/model/colors/BlockColorsMixin.java similarity index 90% rename from src/main/java/me/jellysquid/mods/sodium/mixin/core/model/colors/BlockColorsMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/core/model/colors/BlockColorsMixin.java index 7aabba754a..618c875859 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/model/colors/BlockColorsMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/model/colors/BlockColorsMixin.java @@ -1,8 +1,8 @@ -package me.jellysquid.mods.sodium.mixin.core.model.colors; +package net.caffeinemc.mods.sodium.mixin.core.model.colors; import it.unimi.dsi.fastutil.objects.*; -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import me.jellysquid.mods.sodium.client.model.color.interop.BlockColorsExtended; +import net.caffeinemc.mods.sodium.client.SodiumClientMod; +import net.caffeinemc.mods.sodium.client.model.color.interop.BlockColorsExtended; import net.minecraft.client.color.block.BlockColor; import net.minecraft.client.color.block.BlockColors; import net.minecraft.core.registries.BuiltInRegistries; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/model/colors/ItemColorsMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/model/colors/ItemColorsMixin.java similarity index 89% rename from src/main/java/me/jellysquid/mods/sodium/mixin/core/model/colors/ItemColorsMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/core/model/colors/ItemColorsMixin.java index 46e0cea3b3..6dbed38591 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/model/colors/ItemColorsMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/model/colors/ItemColorsMixin.java @@ -1,8 +1,8 @@ -package me.jellysquid.mods.sodium.mixin.core.model.colors; +package net.caffeinemc.mods.sodium.mixin.core.model.colors; import it.unimi.dsi.fastutil.objects.Reference2ReferenceMap; import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; -import me.jellysquid.mods.sodium.client.model.color.interop.ItemColorsExtended; +import net.caffeinemc.mods.sodium.client.model.color.interop.ItemColorsExtended; import net.minecraft.client.color.item.ItemColor; import net.minecraft.client.color.item.ItemColors; import net.minecraft.world.item.ItemStack; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/model/quad/BakedQuadMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/model/quad/BakedQuadMixin.java similarity index 89% rename from src/main/java/me/jellysquid/mods/sodium/mixin/core/model/quad/BakedQuadMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/core/model/quad/BakedQuadMixin.java index f1fd6ff40b..72c7162650 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/model/quad/BakedQuadMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/model/quad/BakedQuadMixin.java @@ -1,8 +1,8 @@ -package me.jellysquid.mods.sodium.mixin.core.model.quad; +package net.caffeinemc.mods.sodium.mixin.core.model.quad; -import me.jellysquid.mods.sodium.client.model.quad.BakedQuadView; -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFlags; +import net.caffeinemc.mods.sodium.client.model.quad.BakedQuadView; +import net.caffeinemc.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import net.caffeinemc.mods.sodium.client.model.quad.properties.ModelQuadFlags; import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.core.Direction; @@ -14,7 +14,7 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import static me.jellysquid.mods.sodium.client.util.ModelQuadUtil.*; +import static net.caffeinemc.mods.sodium.client.util.ModelQuadUtil.*; @Mixin(BakedQuad.class) public class BakedQuadMixin implements BakedQuadView { diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/VertexFormatAccessor.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/render/VertexFormatAccessor.java similarity index 84% rename from src/main/java/me/jellysquid/mods/sodium/mixin/core/render/VertexFormatAccessor.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/core/render/VertexFormatAccessor.java index 9b1086e70d..b84d94950d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/VertexFormatAccessor.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/render/VertexFormatAccessor.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.mixin.core.render; +package net.caffeinemc.mods.sodium.mixin.core.render; import com.mojang.blaze3d.vertex.VertexFormat; import it.unimi.dsi.fastutil.ints.IntList; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/frustum/FrustumMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/render/frustum/FrustumMixin.java similarity index 70% rename from src/main/java/me/jellysquid/mods/sodium/mixin/core/render/frustum/FrustumMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/core/render/frustum/FrustumMixin.java index 36639b6ba4..f0968021e7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/frustum/FrustumMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/render/frustum/FrustumMixin.java @@ -1,9 +1,9 @@ -package me.jellysquid.mods.sodium.mixin.core.render.frustum; +package net.caffeinemc.mods.sodium.mixin.core.render.frustum; -import me.jellysquid.mods.sodium.client.render.viewport.frustum.SimpleFrustum; +import net.caffeinemc.mods.sodium.client.render.viewport.frustum.SimpleFrustum; import net.minecraft.client.renderer.culling.Frustum; -import me.jellysquid.mods.sodium.client.render.viewport.Viewport; -import me.jellysquid.mods.sodium.client.render.viewport.ViewportProvider; +import net.caffeinemc.mods.sodium.client.render.viewport.Viewport; +import net.caffeinemc.mods.sodium.client.render.viewport.ViewportProvider; import org.joml.FrustumIntersection; import org.joml.Vector3d; import org.spongepowered.asm.mixin.Final; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/BufferBuilderMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/render/immediate/consumer/BufferBuilderMixin.java similarity index 95% rename from src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/BufferBuilderMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/core/render/immediate/consumer/BufferBuilderMixin.java index 00633532d0..ed529d7a17 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/BufferBuilderMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/render/immediate/consumer/BufferBuilderMixin.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.mixin.core.render.immediate.consumer; +package net.caffeinemc.mods.sodium.mixin.core.render.immediate.consumer; -import me.jellysquid.mods.sodium.client.render.vertex.buffer.ExtendedBufferBuilder; -import me.jellysquid.mods.sodium.client.render.vertex.buffer.SodiumBufferBuilder; +import net.caffeinemc.mods.sodium.client.render.vertex.buffer.ExtendedBufferBuilder; +import net.caffeinemc.mods.sodium.client.render.vertex.buffer.SodiumBufferBuilder; import net.caffeinemc.mods.sodium.api.memory.MemoryIntrinsics; import net.caffeinemc.mods.sodium.api.util.ColorABGR; import net.caffeinemc.mods.sodium.api.util.ColorARGB; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/OutlineVertexConsumerMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/render/immediate/consumer/OutlineVertexConsumerMixin.java similarity index 97% rename from src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/OutlineVertexConsumerMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/core/render/immediate/consumer/OutlineVertexConsumerMixin.java index 246fb0e285..d072b54e54 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/OutlineVertexConsumerMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/render/immediate/consumer/OutlineVertexConsumerMixin.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.mixin.core.render.immediate.consumer; +package net.caffeinemc.mods.sodium.mixin.core.render.immediate.consumer; import com.mojang.blaze3d.vertex.DefaultedVertexConsumer; import com.mojang.blaze3d.vertex.VertexConsumer; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/OverlayVertexConsumerMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/render/immediate/consumer/OverlayVertexConsumerMixin.java similarity index 98% rename from src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/OverlayVertexConsumerMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/core/render/immediate/consumer/OverlayVertexConsumerMixin.java index 322d65a8bf..1befb8d597 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/OverlayVertexConsumerMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/render/immediate/consumer/OverlayVertexConsumerMixin.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.mixin.core.render.immediate.consumer; +package net.caffeinemc.mods.sodium.mixin.core.render.immediate.consumer; import com.mojang.blaze3d.vertex.SheetedDecalTextureGenerator; import com.mojang.blaze3d.vertex.VertexConsumer; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/SpriteTexturedVertexConsumerMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/render/immediate/consumer/SpriteTexturedVertexConsumerMixin.java similarity index 97% rename from src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/SpriteTexturedVertexConsumerMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/core/render/immediate/consumer/SpriteTexturedVertexConsumerMixin.java index 8d732c1051..521b187dff 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/SpriteTexturedVertexConsumerMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/render/immediate/consumer/SpriteTexturedVertexConsumerMixin.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.mixin.core.render.immediate.consumer; +package net.caffeinemc.mods.sodium.mixin.core.render.immediate.consumer; import com.mojang.blaze3d.vertex.VertexConsumer; import net.caffeinemc.mods.sodium.api.vertex.attributes.CommonVertexAttribute; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/VertexConsumerProviderImmediateMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/render/immediate/consumer/VertexConsumerProviderImmediateMixin.java similarity index 84% rename from src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/VertexConsumerProviderImmediateMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/core/render/immediate/consumer/VertexConsumerProviderImmediateMixin.java index 55bde3c952..8e89d06f61 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/VertexConsumerProviderImmediateMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/render/immediate/consumer/VertexConsumerProviderImmediateMixin.java @@ -1,8 +1,8 @@ -package me.jellysquid.mods.sodium.mixin.core.render.immediate.consumer; +package net.caffeinemc.mods.sodium.mixin.core.render.immediate.consumer; import com.mojang.blaze3d.vertex.VertexConsumer; -import me.jellysquid.mods.sodium.client.render.vertex.buffer.ExtendedBufferBuilder; -import me.jellysquid.mods.sodium.client.render.vertex.buffer.SodiumBufferBuilder; +import net.caffeinemc.mods.sodium.client.render.vertex.buffer.ExtendedBufferBuilder; +import net.caffeinemc.mods.sodium.client.render.vertex.buffer.SodiumBufferBuilder; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/VertexConsumersMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/render/immediate/consumer/VertexConsumersMixin.java similarity index 97% rename from src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/VertexConsumersMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/core/render/immediate/consumer/VertexConsumersMixin.java index 9d4146fdc9..bd293a76c6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/immediate/consumer/VertexConsumersMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/render/immediate/consumer/VertexConsumersMixin.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.mixin.core.render.immediate.consumer; +package net.caffeinemc.mods.sodium.mixin.core.render.immediate.consumer; import net.caffeinemc.mods.sodium.api.vertex.format.VertexFormatDescription; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/world/BufferBuilderStorageMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/render/world/BufferBuilderStorageMixin.java similarity index 82% rename from src/main/java/me/jellysquid/mods/sodium/mixin/core/render/world/BufferBuilderStorageMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/core/render/world/BufferBuilderStorageMixin.java index 7127417040..fe40fbfa30 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/world/BufferBuilderStorageMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/render/world/BufferBuilderStorageMixin.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.mixin.core.render.world; +package net.caffeinemc.mods.sodium.mixin.core.render.world; -import me.jellysquid.mods.sodium.client.render.chunk.NonStoringBuilderPool; +import net.caffeinemc.mods.sodium.client.render.chunk.NonStoringBuilderPool; import net.minecraft.client.renderer.RenderBuffers; import net.minecraft.client.renderer.SectionBufferBuilderPool; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/world/WorldRendererMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/render/world/WorldRendererMixin.java similarity index 93% rename from src/main/java/me/jellysquid/mods/sodium/mixin/core/render/world/WorldRendererMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/core/render/world/WorldRendererMixin.java index ba1270a078..dbcf349c29 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/render/world/WorldRendererMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/render/world/WorldRendererMixin.java @@ -1,13 +1,13 @@ -package me.jellysquid.mods.sodium.mixin.core.render.world; +package net.caffeinemc.mods.sodium.mixin.core.render.world; import com.mojang.blaze3d.vertex.PoseStack; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; -import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; -import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; -import me.jellysquid.mods.sodium.client.render.viewport.Viewport; -import me.jellysquid.mods.sodium.client.render.viewport.ViewportProvider; -import me.jellysquid.mods.sodium.client.util.FlawlessFrames; -import me.jellysquid.mods.sodium.client.world.WorldRendererExtended; +import net.caffeinemc.mods.sodium.client.gl.device.RenderDevice; +import net.caffeinemc.mods.sodium.client.render.SodiumWorldRenderer; +import net.caffeinemc.mods.sodium.client.render.viewport.Viewport; +import net.caffeinemc.mods.sodium.client.render.viewport.ViewportProvider; +import net.caffeinemc.mods.sodium.client.util.FlawlessFrames; +import net.caffeinemc.mods.sodium.client.world.WorldRendererExtended; import net.minecraft.client.Camera; import net.minecraft.client.Minecraft; import net.minecraft.client.Options; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/biome/ClientWorldMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/world/biome/ClientWorldMixin.java similarity index 92% rename from src/main/java/me/jellysquid/mods/sodium/mixin/core/world/biome/ClientWorldMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/core/world/biome/ClientWorldMixin.java index eb8b47a1ef..dc92d30a16 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/biome/ClientWorldMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/world/biome/ClientWorldMixin.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.mixin.core.world.biome; +package net.caffeinemc.mods.sodium.mixin.core.world.biome; -import me.jellysquid.mods.sodium.client.world.BiomeSeedProvider; +import net.caffeinemc.mods.sodium.client.world.BiomeSeedProvider; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.multiplayer.ClientPacketListener; import net.minecraft.client.renderer.LevelRenderer; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/chunk/EmptyPaletteStorageMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/world/chunk/EmptyPaletteStorageMixin.java similarity index 85% rename from src/main/java/me/jellysquid/mods/sodium/mixin/core/world/chunk/EmptyPaletteStorageMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/core/world/chunk/EmptyPaletteStorageMixin.java index 5eeca64b47..b8942a4c63 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/chunk/EmptyPaletteStorageMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/world/chunk/EmptyPaletteStorageMixin.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.mixin.core.world.chunk; +package net.caffeinemc.mods.sodium.mixin.core.world.chunk; -import me.jellysquid.mods.sodium.client.world.PaletteStorageExtended; +import net.caffeinemc.mods.sodium.client.world.PaletteStorageExtended; import net.minecraft.util.ZeroBitStorage; import net.minecraft.world.level.chunk.Palette; import org.spongepowered.asm.mixin.Final; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/chunk/PackedIntegerArrayMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/world/chunk/PackedIntegerArrayMixin.java similarity index 89% rename from src/main/java/me/jellysquid/mods/sodium/mixin/core/world/chunk/PackedIntegerArrayMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/core/world/chunk/PackedIntegerArrayMixin.java index b942dbaeb2..0b00449294 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/chunk/PackedIntegerArrayMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/world/chunk/PackedIntegerArrayMixin.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.mixin.core.world.chunk; +package net.caffeinemc.mods.sodium.mixin.core.world.chunk; -import me.jellysquid.mods.sodium.client.world.PaletteStorageExtended; +import net.caffeinemc.mods.sodium.client.world.PaletteStorageExtended; import net.minecraft.util.SimpleBitStorage; import net.minecraft.world.level.chunk.Palette; import org.spongepowered.asm.mixin.Final; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/chunk/PalettedContainerMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/world/chunk/PalettedContainerMixin.java similarity index 91% rename from src/main/java/me/jellysquid/mods/sodium/mixin/core/world/chunk/PalettedContainerMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/core/world/chunk/PalettedContainerMixin.java index b0af79ef27..b49983236b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/chunk/PalettedContainerMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/world/chunk/PalettedContainerMixin.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.mixin.core.world.chunk; +package net.caffeinemc.mods.sodium.mixin.core.world.chunk; -import me.jellysquid.mods.sodium.client.world.PaletteStorageExtended; -import me.jellysquid.mods.sodium.client.world.ReadableContainerExtended; +import net.caffeinemc.mods.sodium.client.world.PaletteStorageExtended; +import net.caffeinemc.mods.sodium.client.world.ReadableContainerExtended; import net.minecraft.util.BitStorage; import net.minecraft.world.level.chunk.Palette; import net.minecraft.world.level.chunk.PalettedContainer; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/map/ClientChunkManagerMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/world/map/ClientChunkManagerMixin.java similarity index 91% rename from src/main/java/me/jellysquid/mods/sodium/mixin/core/world/map/ClientChunkManagerMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/core/world/map/ClientChunkManagerMixin.java index ce0749ff68..06aa46d88f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/map/ClientChunkManagerMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/world/map/ClientChunkManagerMixin.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.mixin.core.world.map; +package net.caffeinemc.mods.sodium.mixin.core.world.map; -import me.jellysquid.mods.sodium.client.render.chunk.map.ChunkStatus; -import me.jellysquid.mods.sodium.client.render.chunk.map.ChunkTrackerHolder; +import net.caffeinemc.mods.sodium.client.render.chunk.map.ChunkStatus; +import net.caffeinemc.mods.sodium.client.render.chunk.map.ChunkTrackerHolder; import net.minecraft.client.multiplayer.ClientChunkCache; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.nbt.CompoundTag; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/map/ClientPlayNetworkHandlerMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/world/map/ClientPlayNetworkHandlerMixin.java similarity index 86% rename from src/main/java/me/jellysquid/mods/sodium/mixin/core/world/map/ClientPlayNetworkHandlerMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/core/world/map/ClientPlayNetworkHandlerMixin.java index 7599400a1a..c064fd9a2b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/map/ClientPlayNetworkHandlerMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/world/map/ClientPlayNetworkHandlerMixin.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.mixin.core.world.map; +package net.caffeinemc.mods.sodium.mixin.core.world.map; -import me.jellysquid.mods.sodium.client.render.chunk.map.ChunkStatus; -import me.jellysquid.mods.sodium.client.render.chunk.map.ChunkTrackerHolder; +import net.caffeinemc.mods.sodium.client.render.chunk.map.ChunkStatus; +import net.caffeinemc.mods.sodium.client.render.chunk.map.ChunkTrackerHolder; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.multiplayer.ClientPacketListener; import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/map/ClientWorldMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/world/map/ClientWorldMixin.java similarity index 69% rename from src/main/java/me/jellysquid/mods/sodium/mixin/core/world/map/ClientWorldMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/core/world/map/ClientWorldMixin.java index 8d71cf6660..408e5dd308 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/world/map/ClientWorldMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/core/world/map/ClientWorldMixin.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.mixin.core.world.map; +package net.caffeinemc.mods.sodium.mixin.core.world.map; -import me.jellysquid.mods.sodium.client.render.chunk.map.ChunkTracker; -import me.jellysquid.mods.sodium.client.render.chunk.map.ChunkTrackerHolder; +import net.caffeinemc.mods.sodium.client.render.chunk.map.ChunkTracker; +import net.caffeinemc.mods.sodium.client.render.chunk.map.ChunkTrackerHolder; import net.minecraft.client.multiplayer.ClientLevel; import org.apache.commons.lang3.Validate; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/AbstractTextureMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/AbstractTextureMixin.java similarity index 86% rename from src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/AbstractTextureMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/AbstractTextureMixin.java index b40c9d53c4..562bd216ad 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/AbstractTextureMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/AbstractTextureMixin.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.mixin.debug.checks; +package net.caffeinemc.mods.sodium.mixin.debug.checks; -import me.jellysquid.mods.sodium.client.render.util.RenderAsserts; +import net.caffeinemc.mods.sodium.client.render.util.RenderAsserts; import net.minecraft.client.renderer.texture.AbstractTexture; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/AsyncTextureMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/AsyncTextureMixin.java similarity index 79% rename from src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/AsyncTextureMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/AsyncTextureMixin.java index e999772803..0ec17fdde3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/AsyncTextureMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/AsyncTextureMixin.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.mixin.debug.checks; +package net.caffeinemc.mods.sodium.mixin.debug.checks; -import me.jellysquid.mods.sodium.client.render.util.DeferredRenderTask; +import net.caffeinemc.mods.sodium.client.render.util.DeferredRenderTask; import net.minecraft.client.renderer.texture.PreloadedTexture; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/BufferRendererMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/BufferRendererMixin.java similarity index 81% rename from src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/BufferRendererMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/BufferRendererMixin.java index 94f8534ef4..dfe77895ad 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/BufferRendererMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/BufferRendererMixin.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.mixin.debug.checks; +package net.caffeinemc.mods.sodium.mixin.debug.checks; import com.mojang.blaze3d.vertex.BufferUploader; -import me.jellysquid.mods.sodium.client.render.util.RenderAsserts; +import net.caffeinemc.mods.sodium.client.render.util.RenderAsserts; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/FramebufferMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/FramebufferMixin.java similarity index 87% rename from src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/FramebufferMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/FramebufferMixin.java index ee42acc98f..06d42904a8 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/FramebufferMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/FramebufferMixin.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.mixin.debug.checks; +package net.caffeinemc.mods.sodium.mixin.debug.checks; import com.mojang.blaze3d.pipeline.RenderTarget; -import me.jellysquid.mods.sodium.client.render.util.RenderAsserts; +import net.caffeinemc.mods.sodium.client.render.util.RenderAsserts; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/GlStateManagerMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/GlStateManagerMixin.java similarity index 82% rename from src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/GlStateManagerMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/GlStateManagerMixin.java index 3f1ab9be7b..61447200b1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/GlStateManagerMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/GlStateManagerMixin.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.mixin.debug.checks; +package net.caffeinemc.mods.sodium.mixin.debug.checks; import com.mojang.blaze3d.platform.GlStateManager; -import me.jellysquid.mods.sodium.client.render.util.RenderAsserts; +import net.caffeinemc.mods.sodium.client.render.util.RenderAsserts; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/NativeImageBackedTextureMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/NativeImageBackedTextureMixin.java similarity index 82% rename from src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/NativeImageBackedTextureMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/NativeImageBackedTextureMixin.java index 3349b66a7a..07837ad014 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/NativeImageBackedTextureMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/NativeImageBackedTextureMixin.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.mixin.debug.checks; +package net.caffeinemc.mods.sodium.mixin.debug.checks; -import me.jellysquid.mods.sodium.client.render.util.RenderAsserts; +import net.caffeinemc.mods.sodium.client.render.util.RenderAsserts; import net.minecraft.client.renderer.texture.DynamicTexture; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/NativeImageMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/NativeImageMixin.java similarity index 81% rename from src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/NativeImageMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/NativeImageMixin.java index b2fce65cde..c92c680742 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/NativeImageMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/NativeImageMixin.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.mixin.debug.checks; +package net.caffeinemc.mods.sodium.mixin.debug.checks; import com.mojang.blaze3d.platform.NativeImage; -import me.jellysquid.mods.sodium.client.render.util.RenderAsserts; +import net.caffeinemc.mods.sodium.client.render.util.RenderAsserts; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/PlayerSkinTextureMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/PlayerSkinTextureMixin.java similarity index 94% rename from src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/PlayerSkinTextureMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/PlayerSkinTextureMixin.java index 942106d51c..e8cc1feada 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/PlayerSkinTextureMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/PlayerSkinTextureMixin.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.mixin.debug.checks; +package net.caffeinemc.mods.sodium.mixin.debug.checks; import com.mojang.blaze3d.platform.NativeImage; import net.minecraft.client.Minecraft; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/RenderSystemMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/RenderSystemMixin.java similarity index 90% rename from src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/RenderSystemMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/RenderSystemMixin.java index aee88f7acb..1954a4a29a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/RenderSystemMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/RenderSystemMixin.java @@ -1,9 +1,9 @@ -package me.jellysquid.mods.sodium.mixin.debug.checks; +package net.caffeinemc.mods.sodium.mixin.debug.checks; import com.mojang.blaze3d.pipeline.RenderCall; import com.mojang.blaze3d.systems.RenderSystem; -import me.jellysquid.mods.sodium.client.render.util.DeferredRenderTask; -import me.jellysquid.mods.sodium.client.render.util.RenderAsserts; +import net.caffeinemc.mods.sodium.client.render.util.DeferredRenderTask; +import net.caffeinemc.mods.sodium.client.render.util.RenderAsserts; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.injection.At; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/SpriteAtlasTextureMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/SpriteAtlasTextureMixin.java similarity index 81% rename from src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/SpriteAtlasTextureMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/SpriteAtlasTextureMixin.java index e6f01b77b7..f8687ba83a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/SpriteAtlasTextureMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/SpriteAtlasTextureMixin.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.mixin.debug.checks; +package net.caffeinemc.mods.sodium.mixin.debug.checks; -import me.jellysquid.mods.sodium.client.render.util.RenderAsserts; +import net.caffeinemc.mods.sodium.client.render.util.RenderAsserts; import net.minecraft.client.renderer.texture.TextureAtlas; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/SpriteContentsAnimatorImplMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/SpriteContentsAnimatorImplMixin.java similarity index 82% rename from src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/SpriteContentsAnimatorImplMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/SpriteContentsAnimatorImplMixin.java index a5e0a97d21..819a9c77bf 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/SpriteContentsAnimatorImplMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/SpriteContentsAnimatorImplMixin.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.mixin.debug.checks; +package net.caffeinemc.mods.sodium.mixin.debug.checks; -import me.jellysquid.mods.sodium.client.render.util.RenderAsserts; +import net.caffeinemc.mods.sodium.client.render.util.RenderAsserts; import net.minecraft.client.renderer.texture.SpriteContents; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/TextureManagerMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/TextureManagerMixin.java similarity index 87% rename from src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/TextureManagerMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/TextureManagerMixin.java index 136337719d..e0aaa1b14f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/TextureManagerMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/TextureManagerMixin.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.mixin.debug.checks; +package net.caffeinemc.mods.sodium.mixin.debug.checks; -import me.jellysquid.mods.sodium.client.render.util.DeferredRenderTask; -import me.jellysquid.mods.sodium.client.render.util.RenderAsserts; +import net.caffeinemc.mods.sodium.client.render.util.DeferredRenderTask; +import net.caffeinemc.mods.sodium.client.render.util.RenderAsserts; import net.minecraft.client.renderer.texture.TextureManager; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/VertexBufferMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/VertexBufferMixin.java similarity index 83% rename from src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/VertexBufferMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/VertexBufferMixin.java index cca9268649..2057f8ee00 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/VertexBufferMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/VertexBufferMixin.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.mixin.debug.checks; +package net.caffeinemc.mods.sodium.mixin.debug.checks; import com.mojang.blaze3d.vertex.VertexBuffer; -import me.jellysquid.mods.sodium.client.render.util.RenderAsserts; +import net.caffeinemc.mods.sodium.client.render.util.RenderAsserts; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/VertexFormatMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/VertexFormatMixin.java similarity index 82% rename from src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/VertexFormatMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/VertexFormatMixin.java index 0e0d5405ac..79dce4739e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/VertexFormatMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/VertexFormatMixin.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.mixin.debug.checks; +package net.caffeinemc.mods.sodium.mixin.debug.checks; import com.mojang.blaze3d.vertex.VertexFormat; -import me.jellysquid.mods.sodium.client.render.util.RenderAsserts; +import net.caffeinemc.mods.sodium.client.render.util.RenderAsserts; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/WindowFramebufferMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/WindowFramebufferMixin.java similarity index 81% rename from src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/WindowFramebufferMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/WindowFramebufferMixin.java index 48c66f09f3..ec98a49eb1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/debug/checks/WindowFramebufferMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/debug/checks/WindowFramebufferMixin.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.mixin.debug.checks; +package net.caffeinemc.mods.sodium.mixin.debug.checks; import com.mojang.blaze3d.pipeline.MainTarget; -import me.jellysquid.mods.sodium.client.render.util.RenderAsserts; +import net.caffeinemc.mods.sodium.client.render.util.RenderAsserts; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/hooks/console/GameRendererMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/gui/hooks/console/GameRendererMixin.java similarity index 92% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/hooks/console/GameRendererMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/gui/hooks/console/GameRendererMixin.java index 7c876acd87..6b90eb4874 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/hooks/console/GameRendererMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/gui/hooks/console/GameRendererMixin.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.mixin.features.gui.hooks.console; +package net.caffeinemc.mods.sodium.mixin.features.gui.hooks.console; -import me.jellysquid.mods.sodium.client.gui.console.ConsoleHooks; +import net.caffeinemc.mods.sodium.client.gui.console.ConsoleHooks; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.renderer.GameRenderer; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/hooks/debug/DebugHudMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/gui/hooks/debug/DebugHudMixin.java similarity index 87% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/hooks/debug/DebugHudMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/gui/hooks/debug/DebugHudMixin.java index 583a1de70e..601324cfbc 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/hooks/debug/DebugHudMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/gui/hooks/debug/DebugHudMixin.java @@ -1,10 +1,10 @@ -package me.jellysquid.mods.sodium.mixin.features.gui.hooks.debug; +package net.caffeinemc.mods.sodium.mixin.features.gui.hooks.debug; import com.google.common.collect.Lists; -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; -import me.jellysquid.mods.sodium.client.util.MathUtil; -import me.jellysquid.mods.sodium.client.util.NativeBuffer; +import net.caffeinemc.mods.sodium.client.SodiumClientMod; +import net.caffeinemc.mods.sodium.client.render.SodiumWorldRenderer; +import net.caffeinemc.mods.sodium.client.util.MathUtil; +import net.caffeinemc.mods.sodium.client.util.NativeBuffer; import net.minecraft.ChatFormatting; import net.minecraft.client.gui.components.DebugScreenOverlay; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/hooks/settings/OptionsScreenMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/gui/hooks/settings/OptionsScreenMixin.java similarity index 85% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/hooks/settings/OptionsScreenMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/gui/hooks/settings/OptionsScreenMixin.java index 19aa44f88e..7b545c846d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/hooks/settings/OptionsScreenMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/gui/hooks/settings/OptionsScreenMixin.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.mixin.features.gui.hooks.settings; +package net.caffeinemc.mods.sodium.mixin.features.gui.hooks.settings; -import me.jellysquid.mods.sodium.client.gui.SodiumOptionsGUI; +import net.caffeinemc.mods.sodium.client.gui.SodiumOptionsGUI; import net.minecraft.client.gui.screens.OptionsScreen; import net.minecraft.client.gui.screens.Screen; import net.minecraft.network.chat.Component; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/screen/LevelLoadingScreenMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/gui/screen/LevelLoadingScreenMixin.java similarity index 98% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/screen/LevelLoadingScreenMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/gui/screen/LevelLoadingScreenMixin.java index fb22afe3ee..a05aaaf25b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/screen/LevelLoadingScreenMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/gui/screen/LevelLoadingScreenMixin.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.mixin.features.gui.screen; +package net.caffeinemc.mods.sodium.mixin.features.gui.screen; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.BufferBuilder; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/model/MultipartBakedModelMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/model/MultipartBakedModelMixin.java similarity index 97% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/model/MultipartBakedModelMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/model/MultipartBakedModelMixin.java index 6c6906cc26..16d06a7e9a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/model/MultipartBakedModelMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/model/MultipartBakedModelMixin.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.mixin.features.model; +package net.caffeinemc.mods.sodium.mixin.features.model; import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; import org.apache.commons.lang3.tuple.Pair; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/model/WeightedBakedModelMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/model/WeightedBakedModelMixin.java similarity index 96% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/model/WeightedBakedModelMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/model/WeightedBakedModelMixin.java index 6b9a55fa46..eb16d5d3c6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/model/WeightedBakedModelMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/model/WeightedBakedModelMixin.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.mixin.features.model; +package net.caffeinemc.mods.sodium.mixin.features.model; import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.*; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/overlays/InGameHudMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/options/overlays/InGameHudMixin.java similarity index 79% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/options/overlays/InGameHudMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/options/overlays/InGameHudMixin.java index f854c08dcf..ed87041dc0 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/overlays/InGameHudMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/options/overlays/InGameHudMixin.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.mixin.features.options.overlays; +package net.caffeinemc.mods.sodium.mixin.features.options.overlays; -import me.jellysquid.mods.sodium.client.SodiumClientMod; +import net.caffeinemc.mods.sodium.client.SodiumClientMod; import net.minecraft.client.gui.Gui; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/render_layers/LeavesBlockMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/options/render_layers/LeavesBlockMixin.java similarity index 88% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/options/render_layers/LeavesBlockMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/options/render_layers/LeavesBlockMixin.java index e508b48278..27decf8d8a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/render_layers/LeavesBlockMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/options/render_layers/LeavesBlockMixin.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.mixin.features.options.render_layers; +package net.caffeinemc.mods.sodium.mixin.features.options.render_layers; -import me.jellysquid.mods.sodium.client.SodiumClientMod; +import net.caffeinemc.mods.sodium.client.SodiumClientMod; import net.minecraft.client.Minecraft; import net.minecraft.core.Direction; import net.minecraft.world.level.block.Block; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/render_layers/RenderLayersMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/options/render_layers/RenderLayersMixin.java similarity index 89% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/options/render_layers/RenderLayersMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/options/render_layers/RenderLayersMixin.java index 07d76d4eff..ced76d1db1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/render_layers/RenderLayersMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/options/render_layers/RenderLayersMixin.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.mixin.features.options.render_layers; +package net.caffeinemc.mods.sodium.mixin.features.options.render_layers; -import me.jellysquid.mods.sodium.client.SodiumClientMod; +import net.caffeinemc.mods.sodium.client.SodiumClientMod; import net.minecraft.client.GraphicsStatus; import net.minecraft.client.renderer.ItemBlockRenderTypes; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/weather/WorldRendererMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/options/weather/WorldRendererMixin.java similarity index 83% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/options/weather/WorldRendererMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/options/weather/WorldRendererMixin.java index 8225cb9962..b2f8a4bc28 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/weather/WorldRendererMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/options/weather/WorldRendererMixin.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.mixin.features.options.weather; +package net.caffeinemc.mods.sodium.mixin.features.options.weather; -import me.jellysquid.mods.sodium.client.SodiumClientMod; +import net.caffeinemc.mods.sodium.client.SodiumClientMod; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.LevelRenderer; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/entity/CuboidMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/entity/CuboidMixin.java similarity index 86% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/render/entity/CuboidMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/entity/CuboidMixin.java index 982099afdd..96d230dd70 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/entity/CuboidMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/entity/CuboidMixin.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.mixin.features.render.entity; +package net.caffeinemc.mods.sodium.mixin.features.render.entity; -import me.jellysquid.mods.sodium.client.model.ModelCuboidAccessor; -import me.jellysquid.mods.sodium.client.render.immediate.model.ModelCuboid; +import net.caffeinemc.mods.sodium.client.model.ModelCuboidAccessor; +import net.caffeinemc.mods.sodium.client.render.immediate.model.ModelCuboid; import net.minecraft.client.model.geom.ModelPart; import net.minecraft.core.Direction; import org.objectweb.asm.Opcodes; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/entity/ModelPartMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/entity/ModelPartMixin.java similarity index 89% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/render/entity/ModelPartMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/entity/ModelPartMixin.java index ebba2d11c1..5e24a89b9b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/entity/ModelPartMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/entity/ModelPartMixin.java @@ -1,10 +1,10 @@ -package me.jellysquid.mods.sodium.mixin.features.render.entity; +package net.caffeinemc.mods.sodium.mixin.features.render.entity; -import me.jellysquid.mods.sodium.client.model.ModelCuboidAccessor; -import me.jellysquid.mods.sodium.client.render.immediate.model.EntityRenderer; -import me.jellysquid.mods.sodium.client.render.immediate.model.ModelCuboid; -import me.jellysquid.mods.sodium.client.render.immediate.model.ModelPartData; -import me.jellysquid.mods.sodium.client.render.vertex.VertexConsumerUtils; +import net.caffeinemc.mods.sodium.client.model.ModelCuboidAccessor; +import net.caffeinemc.mods.sodium.client.render.immediate.model.EntityRenderer; +import net.caffeinemc.mods.sodium.client.render.immediate.model.ModelCuboid; +import net.caffeinemc.mods.sodium.client.render.immediate.model.ModelPartData; +import net.caffeinemc.mods.sodium.client.render.vertex.VertexConsumerUtils; import net.caffeinemc.mods.sodium.api.math.MatrixHelper; import net.caffeinemc.mods.sodium.api.util.ColorABGR; import net.caffeinemc.mods.sodium.api.vertex.buffer.VertexBufferWriter; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/entity/cull/EntityRendererMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/entity/cull/EntityRendererMixin.java similarity index 89% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/render/entity/cull/EntityRendererMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/entity/cull/EntityRendererMixin.java index 4c900bbb42..6a4a00ae1c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/entity/cull/EntityRendererMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/entity/cull/EntityRendererMixin.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.mixin.features.render.entity.cull; +package net.caffeinemc.mods.sodium.mixin.features.render.entity.cull; -import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; +import net.caffeinemc.mods.sodium.client.render.SodiumWorldRenderer; import net.minecraft.client.renderer.culling.Frustum; import net.minecraft.client.renderer.entity.EntityRenderer; import net.minecraft.world.entity.Entity; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/entity/shadows/EntityRenderDispatcherMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/entity/shadows/EntityRenderDispatcherMixin.java similarity index 97% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/render/entity/shadows/EntityRenderDispatcherMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/entity/shadows/EntityRenderDispatcherMixin.java index 130a1c2e8d..4554d4d54c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/entity/shadows/EntityRenderDispatcherMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/entity/shadows/EntityRenderDispatcherMixin.java @@ -1,8 +1,8 @@ -package me.jellysquid.mods.sodium.mixin.features.render.entity.shadows; +package net.caffeinemc.mods.sodium.mixin.features.render.entity.shadows; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; -import me.jellysquid.mods.sodium.client.render.vertex.VertexConsumerUtils; +import net.caffeinemc.mods.sodium.client.render.vertex.VertexConsumerUtils; import net.caffeinemc.mods.sodium.api.vertex.buffer.VertexBufferWriter; import net.caffeinemc.mods.sodium.api.vertex.format.common.ModelVertex; import net.minecraft.client.renderer.LightTexture; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/gui/font/GlyphRendererMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/gui/font/GlyphRendererMixin.java similarity index 95% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/render/gui/font/GlyphRendererMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/gui/font/GlyphRendererMixin.java index c681a40e1c..b21455620e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/gui/font/GlyphRendererMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/gui/font/GlyphRendererMixin.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.mixin.features.render.gui.font; +package net.caffeinemc.mods.sodium.mixin.features.render.gui.font; import com.mojang.blaze3d.vertex.VertexConsumer; -import me.jellysquid.mods.sodium.client.render.vertex.VertexConsumerUtils; +import net.caffeinemc.mods.sodium.client.render.vertex.VertexConsumerUtils; import net.caffeinemc.mods.sodium.api.vertex.format.common.GlyphVertex; import net.minecraft.client.gui.font.glyphs.BakedGlyph; import net.caffeinemc.mods.sodium.api.vertex.buffer.VertexBufferWriter; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/gui/outlines/WorldRendererMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/gui/outlines/WorldRendererMixin.java similarity index 98% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/render/gui/outlines/WorldRendererMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/gui/outlines/WorldRendererMixin.java index b3fd807527..e889093e40 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/gui/outlines/WorldRendererMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/gui/outlines/WorldRendererMixin.java @@ -1,8 +1,8 @@ -package me.jellysquid.mods.sodium.mixin.features.render.gui.outlines; +package net.caffeinemc.mods.sodium.mixin.features.render.gui.outlines; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; -import me.jellysquid.mods.sodium.client.render.vertex.VertexConsumerUtils; +import net.caffeinemc.mods.sodium.client.render.vertex.VertexConsumerUtils; import net.caffeinemc.mods.sodium.api.vertex.format.common.LineVertex; import net.minecraft.client.renderer.LevelRenderer; import net.caffeinemc.mods.sodium.api.vertex.buffer.VertexBufferWriter; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/DirectionMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/immediate/DirectionMixin.java similarity index 93% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/DirectionMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/immediate/DirectionMixin.java index 50b950cc84..cfd556e4ea 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/DirectionMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/immediate/DirectionMixin.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.mixin.features.render.immediate; +package net.caffeinemc.mods.sodium.mixin.features.render.immediate; import com.mojang.blaze3d.vertex.SheetedDecalTextureGenerator; -import me.jellysquid.mods.sodium.mixin.core.render.immediate.consumer.OverlayVertexConsumerMixin; +import net.caffeinemc.mods.sodium.mixin.core.render.immediate.consumer.OverlayVertexConsumerMixin; import net.minecraft.client.renderer.block.model.BlockModel; import net.minecraft.client.renderer.block.model.FaceBakery; import net.minecraft.core.Direction; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/buffer_builder/intrinsics/BufferBuilderMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/immediate/buffer_builder/intrinsics/BufferBuilderMixin.java similarity index 88% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/buffer_builder/intrinsics/BufferBuilderMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/immediate/buffer_builder/intrinsics/BufferBuilderMixin.java index d36dadd954..9428982f3b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/buffer_builder/intrinsics/BufferBuilderMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/immediate/buffer_builder/intrinsics/BufferBuilderMixin.java @@ -1,11 +1,11 @@ -package me.jellysquid.mods.sodium.mixin.features.render.immediate.buffer_builder.intrinsics; +package net.caffeinemc.mods.sodium.mixin.features.render.immediate.buffer_builder.intrinsics; import com.mojang.blaze3d.vertex.BufferBuilder; import com.mojang.blaze3d.vertex.DefaultedVertexConsumer; import com.mojang.blaze3d.vertex.PoseStack; -import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; -import me.jellysquid.mods.sodium.client.render.immediate.model.BakedModelEncoder; -import me.jellysquid.mods.sodium.client.render.texture.SpriteUtil; +import net.caffeinemc.mods.sodium.client.model.quad.ModelQuadView; +import net.caffeinemc.mods.sodium.client.render.immediate.model.BakedModelEncoder; +import net.caffeinemc.mods.sodium.client.render.texture.SpriteUtil; import net.caffeinemc.mods.sodium.api.util.ColorABGR; import net.caffeinemc.mods.sodium.api.vertex.buffer.VertexBufferWriter; import net.minecraft.client.renderer.block.model.BakedQuad; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/buffer_builder/sorting/BufferBuilderMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/immediate/buffer_builder/sorting/BufferBuilderMixin.java similarity index 97% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/buffer_builder/sorting/BufferBuilderMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/immediate/buffer_builder/sorting/BufferBuilderMixin.java index d23c35fa72..6438cc14c0 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/buffer_builder/sorting/BufferBuilderMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/immediate/buffer_builder/sorting/BufferBuilderMixin.java @@ -1,5 +1,5 @@ -package me.jellysquid.mods.sodium.mixin.features.render.immediate.buffer_builder.sorting; +package net.caffeinemc.mods.sodium.mixin.features.render.immediate.buffer_builder.sorting; import org.jetbrains.annotations.Nullable; import org.joml.Vector3f; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/buffer_builder/sorting/VertexSorterMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/immediate/buffer_builder/sorting/VertexSorterMixin.java similarity index 74% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/buffer_builder/sorting/VertexSorterMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/immediate/buffer_builder/sorting/VertexSorterMixin.java index 86621396cb..509383ea20 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/buffer_builder/sorting/VertexSorterMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/immediate/buffer_builder/sorting/VertexSorterMixin.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.mixin.features.render.immediate.buffer_builder.sorting; +package net.caffeinemc.mods.sodium.mixin.features.render.immediate.buffer_builder.sorting; import com.mojang.blaze3d.vertex.VertexSorting; -import me.jellysquid.mods.sodium.client.util.sorting.VertexSorters; +import net.caffeinemc.mods.sodium.client.util.sorting.VertexSorters; import org.joml.Vector3f; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/matrix_stack/MatrixStackMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/immediate/matrix_stack/MatrixStackMixin.java similarity index 93% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/matrix_stack/MatrixStackMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/immediate/matrix_stack/MatrixStackMixin.java index 9149a9fde9..ba0f4a1a41 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/matrix_stack/MatrixStackMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/immediate/matrix_stack/MatrixStackMixin.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.mixin.features.render.immediate.matrix_stack; +package net.caffeinemc.mods.sodium.mixin.features.render.immediate.matrix_stack; import org.joml.Matrix3f; import org.joml.Matrix4f; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/matrix_stack/VertexConsumerMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/immediate/matrix_stack/VertexConsumerMixin.java similarity index 94% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/matrix_stack/VertexConsumerMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/immediate/matrix_stack/VertexConsumerMixin.java index 8e648f14b1..a670a787d7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/immediate/matrix_stack/VertexConsumerMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/immediate/matrix_stack/VertexConsumerMixin.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.mixin.features.render.immediate.matrix_stack; +package net.caffeinemc.mods.sodium.mixin.features.render.immediate.matrix_stack; import com.mojang.blaze3d.vertex.VertexConsumer; import net.caffeinemc.mods.sodium.api.math.MatrixHelper; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/model/RenderLayersMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/model/RenderLayersMixin.java similarity index 94% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/render/model/RenderLayersMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/model/RenderLayersMixin.java index 239f6445e7..9eba8299d7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/model/RenderLayersMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/model/RenderLayersMixin.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.mixin.features.render.model; +package net.caffeinemc.mods.sodium.mixin.features.render.model; import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; import org.spongepowered.asm.mixin.Final; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/model/block/BlockModelRendererMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/model/block/BlockModelRendererMixin.java similarity index 88% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/render/model/block/BlockModelRendererMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/model/block/BlockModelRendererMixin.java index 900f446e3b..a9f10ef2c8 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/model/block/BlockModelRendererMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/model/block/BlockModelRendererMixin.java @@ -1,10 +1,10 @@ -package me.jellysquid.mods.sodium.mixin.features.render.model.block; +package net.caffeinemc.mods.sodium.mixin.features.render.model.block; -import me.jellysquid.mods.sodium.client.model.quad.BakedQuadView; -import me.jellysquid.mods.sodium.client.render.immediate.model.BakedModelEncoder; -import me.jellysquid.mods.sodium.client.render.texture.SpriteUtil; -import me.jellysquid.mods.sodium.client.render.vertex.VertexConsumerUtils; -import me.jellysquid.mods.sodium.client.util.DirectionUtil; +import net.caffeinemc.mods.sodium.client.model.quad.BakedQuadView; +import net.caffeinemc.mods.sodium.client.render.immediate.model.BakedModelEncoder; +import net.caffeinemc.mods.sodium.client.render.texture.SpriteUtil; +import net.caffeinemc.mods.sodium.client.render.vertex.VertexConsumerUtils; +import net.caffeinemc.mods.sodium.client.util.DirectionUtil; import net.caffeinemc.mods.sodium.api.util.ColorABGR; import net.caffeinemc.mods.sodium.api.vertex.buffer.VertexBufferWriter; import net.minecraft.client.renderer.block.ModelBlockRenderer; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/model/item/ItemRendererMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/model/item/ItemRendererMixin.java similarity index 87% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/render/model/item/ItemRendererMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/model/item/ItemRendererMixin.java index f26f964e18..c9c865abdd 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/model/item/ItemRendererMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/model/item/ItemRendererMixin.java @@ -1,11 +1,11 @@ -package me.jellysquid.mods.sodium.mixin.features.render.model.item; - -import me.jellysquid.mods.sodium.client.model.quad.BakedQuadView; -import me.jellysquid.mods.sodium.client.render.immediate.model.BakedModelEncoder; -import me.jellysquid.mods.sodium.client.render.texture.SpriteUtil; -import me.jellysquid.mods.sodium.client.render.vertex.VertexConsumerUtils; -import me.jellysquid.mods.sodium.client.model.color.interop.ItemColorsExtended; -import me.jellysquid.mods.sodium.client.util.DirectionUtil; +package net.caffeinemc.mods.sodium.mixin.features.render.model.item; + +import net.caffeinemc.mods.sodium.client.model.quad.BakedQuadView; +import net.caffeinemc.mods.sodium.client.render.immediate.model.BakedModelEncoder; +import net.caffeinemc.mods.sodium.client.render.texture.SpriteUtil; +import net.caffeinemc.mods.sodium.client.render.vertex.VertexConsumerUtils; +import net.caffeinemc.mods.sodium.client.model.color.interop.ItemColorsExtended; +import net.caffeinemc.mods.sodium.client.util.DirectionUtil; import net.caffeinemc.mods.sodium.api.util.ColorARGB; import net.caffeinemc.mods.sodium.api.vertex.buffer.VertexBufferWriter; import net.minecraft.client.color.item.ItemColor; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/particle/BillboardParticleMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/particle/BillboardParticleMixin.java similarity index 98% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/render/particle/BillboardParticleMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/particle/BillboardParticleMixin.java index 3b6f2de0d8..e4686d4bc7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/particle/BillboardParticleMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/particle/BillboardParticleMixin.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.mixin.features.render.particle; +package net.caffeinemc.mods.sodium.mixin.features.render.particle; import net.caffeinemc.mods.sodium.api.vertex.format.common.ParticleVertex; import net.caffeinemc.mods.sodium.api.vertex.buffer.VertexBufferWriter; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/world/clouds/WorldRendererMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/world/clouds/WorldRendererMixin.java similarity index 93% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/render/world/clouds/WorldRendererMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/world/clouds/WorldRendererMixin.java index 6d5462e3c4..b293ecdcb4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/world/clouds/WorldRendererMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/world/clouds/WorldRendererMixin.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.mixin.features.render.world.clouds; +package net.caffeinemc.mods.sodium.mixin.features.render.world.clouds; import com.mojang.blaze3d.vertex.PoseStack; -import me.jellysquid.mods.sodium.client.render.immediate.CloudRenderer; +import net.caffeinemc.mods.sodium.client.render.immediate.CloudRenderer; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.renderer.LevelRenderer; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/world/sky/BackgroundRendererMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/world/sky/BackgroundRendererMixin.java similarity index 89% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/render/world/sky/BackgroundRendererMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/world/sky/BackgroundRendererMixin.java index 4b8e03e2e4..dbd8afd074 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/world/sky/BackgroundRendererMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/world/sky/BackgroundRendererMixin.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.mixin.features.render.world.sky; +package net.caffeinemc.mods.sodium.mixin.features.render.world.sky; -import me.jellysquid.mods.sodium.client.util.color.FastCubicSampler; +import net.caffeinemc.mods.sodium.client.util.color.FastCubicSampler; import net.minecraft.client.Camera; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.renderer.FogRenderer; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/world/sky/ClientWorldMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/world/sky/ClientWorldMixin.java similarity index 87% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/render/world/sky/ClientWorldMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/world/sky/ClientWorldMixin.java index fa914a1d05..9d63a5634e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/world/sky/ClientWorldMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/world/sky/ClientWorldMixin.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.mixin.features.render.world.sky; +package net.caffeinemc.mods.sodium.mixin.features.render.world.sky; -import me.jellysquid.mods.sodium.client.util.color.FastCubicSampler; +import net.caffeinemc.mods.sodium.client.util.color.FastCubicSampler; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.util.CubicSampler; import net.minecraft.world.level.Level; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/world/sky/WorldRendererMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/world/sky/WorldRendererMixin.java similarity index 97% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/render/world/sky/WorldRendererMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/world/sky/WorldRendererMixin.java index 65574f6ba6..f14d1393f7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render/world/sky/WorldRendererMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/render/world/sky/WorldRendererMixin.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.mixin.features.render.world.sky; +package net.caffeinemc.mods.sodium.mixin.features.render.world.sky; import com.mojang.blaze3d.vertex.PoseStack; import net.minecraft.client.Camera; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/shader/uniform/ShaderProgramMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/shader/uniform/ShaderProgramMixin.java similarity index 97% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/shader/uniform/ShaderProgramMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/shader/uniform/ShaderProgramMixin.java index e37efc6527..61bbaaf4ae 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/shader/uniform/ShaderProgramMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/shader/uniform/ShaderProgramMixin.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.mixin.features.shader.uniform; +package net.caffeinemc.mods.sodium.mixin.features.shader.uniform; import com.mojang.blaze3d.shaders.Uniform; import com.mojang.blaze3d.vertex.VertexFormat; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/NativeImageAccessor.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/NativeImageAccessor.java similarity index 80% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/NativeImageAccessor.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/NativeImageAccessor.java index 8a0c60401a..325176fded 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/NativeImageAccessor.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/NativeImageAccessor.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.mixin.features.textures; +package net.caffeinemc.mods.sodium.mixin.features.textures; import com.mojang.blaze3d.platform.NativeImage; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/SpriteContentsInvoker.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/SpriteContentsInvoker.java similarity index 86% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/SpriteContentsInvoker.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/SpriteContentsInvoker.java index af96061856..66d3dfbff1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/SpriteContentsInvoker.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/SpriteContentsInvoker.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.mixin.features.textures; +package net.caffeinemc.mods.sodium.mixin.features.textures; import com.mojang.blaze3d.platform.NativeImage; import net.minecraft.client.renderer.texture.SpriteContents; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/BlockModelRendererMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/animations/tracking/BlockModelRendererMixin.java similarity index 89% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/BlockModelRendererMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/animations/tracking/BlockModelRendererMixin.java index 6b8fc13aa3..801384351f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/BlockModelRendererMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/animations/tracking/BlockModelRendererMixin.java @@ -1,8 +1,8 @@ -package me.jellysquid.mods.sodium.mixin.features.textures.animations.tracking; +package net.caffeinemc.mods.sodium.mixin.features.textures.animations.tracking; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; -import me.jellysquid.mods.sodium.client.render.texture.SpriteUtil; +import net.caffeinemc.mods.sodium.client.render.texture.SpriteUtil; import net.minecraft.client.renderer.block.ModelBlockRenderer; import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.core.BlockPos; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/DrawContextMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/animations/tracking/DrawContextMixin.java similarity index 89% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/DrawContextMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/animations/tracking/DrawContextMixin.java index 72dae5af4d..6213543649 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/DrawContextMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/animations/tracking/DrawContextMixin.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.mixin.features.textures.animations.tracking; +package net.caffeinemc.mods.sodium.mixin.features.textures.animations.tracking; -import me.jellysquid.mods.sodium.client.render.texture.SpriteUtil; +import net.caffeinemc.mods.sodium.client.render.texture.SpriteUtil; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteAtlasTextureMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/animations/tracking/SpriteAtlasTextureMixin.java similarity index 82% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteAtlasTextureMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/animations/tracking/SpriteAtlasTextureMixin.java index cca072563b..a2181969bc 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteAtlasTextureMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/animations/tracking/SpriteAtlasTextureMixin.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.mixin.features.textures.animations.tracking; +package net.caffeinemc.mods.sodium.mixin.features.textures.animations.tracking; -import me.jellysquid.mods.sodium.client.render.texture.SpriteUtil; +import net.caffeinemc.mods.sodium.client.render.texture.SpriteUtil; import net.minecraft.client.renderer.texture.TextureAtlas; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteBillboardParticleMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/animations/tracking/SpriteBillboardParticleMixin.java similarity index 91% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteBillboardParticleMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/animations/tracking/SpriteBillboardParticleMixin.java index de54c58797..97ee37c0d0 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteBillboardParticleMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/animations/tracking/SpriteBillboardParticleMixin.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.mixin.features.textures.animations.tracking; +package net.caffeinemc.mods.sodium.mixin.features.textures.animations.tracking; import com.mojang.blaze3d.vertex.VertexConsumer; -import me.jellysquid.mods.sodium.client.render.texture.SpriteUtil; +import net.caffeinemc.mods.sodium.client.render.texture.SpriteUtil; import net.minecraft.client.Camera; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.particle.SingleQuadParticle; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsAnimationAccessor.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsAnimationAccessor.java similarity index 81% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsAnimationAccessor.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsAnimationAccessor.java index 7e63653e78..e5b5ef9e33 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsAnimationAccessor.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsAnimationAccessor.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.mixin.features.textures.animations.tracking; +package net.caffeinemc.mods.sodium.mixin.features.textures.animations.tracking; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsAnimationFrameAccessor.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsAnimationFrameAccessor.java similarity index 78% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsAnimationFrameAccessor.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsAnimationFrameAccessor.java index de8a9bcc21..262004466e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsAnimationFrameAccessor.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsAnimationFrameAccessor.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.mixin.features.textures.animations.tracking; +package net.caffeinemc.mods.sodium.mixin.features.textures.animations.tracking; import net.minecraft.client.renderer.texture.SpriteContents; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsAnimatorImplMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsAnimatorImplMixin.java similarity index 90% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsAnimatorImplMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsAnimatorImplMixin.java index 5b8b40f926..9cbcad38c5 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsAnimatorImplMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsAnimatorImplMixin.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.mixin.features.textures.animations.tracking; +package net.caffeinemc.mods.sodium.mixin.features.textures.animations.tracking; -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import me.jellysquid.mods.sodium.client.render.texture.SpriteContentsExtended; +import net.caffeinemc.mods.sodium.client.SodiumClientMod; +import net.caffeinemc.mods.sodium.client.render.texture.SpriteContentsExtended; import net.minecraft.client.renderer.texture.SpriteContents; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsMixin.java similarity index 83% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsMixin.java index 1d9d306a28..6f04f13e5a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/animations/tracking/SpriteContentsMixin.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.mixin.features.textures.animations.tracking; +package net.caffeinemc.mods.sodium.mixin.features.textures.animations.tracking; -import me.jellysquid.mods.sodium.client.render.texture.SpriteContentsExtended; +import net.caffeinemc.mods.sodium.client.render.texture.SpriteContentsExtended; import net.minecraft.client.renderer.texture.SpriteContents; import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Final; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAccessor.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAccessor.java similarity index 81% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAccessor.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAccessor.java index 662ba1bec2..3b524bf3b0 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAccessor.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAccessor.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.mixin.features.textures.animations.upload; +package net.caffeinemc.mods.sodium.mixin.features.textures.animations.upload; import com.mojang.blaze3d.platform.NativeImage; import net.minecraft.client.renderer.texture.SpriteContents; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAnimationAccessor.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAnimationAccessor.java similarity index 82% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAnimationAccessor.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAnimationAccessor.java index cbe0eecd20..bbf8e0efcc 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAnimationAccessor.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAnimationAccessor.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.mixin.features.textures.animations.upload; +package net.caffeinemc.mods.sodium.mixin.features.textures.animations.upload; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAnimationFrameAccessor.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAnimationFrameAccessor.java similarity index 80% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAnimationFrameAccessor.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAnimationFrameAccessor.java index 6f2c0801e0..a559af12e4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAnimationFrameAccessor.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAnimationFrameAccessor.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.mixin.features.textures.animations.upload; +package net.caffeinemc.mods.sodium.mixin.features.textures.animations.upload; import net.minecraft.client.renderer.texture.SpriteContents; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAnimatorImplAccessor.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAnimatorImplAccessor.java similarity index 84% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAnimatorImplAccessor.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAnimatorImplAccessor.java index b1e773ee59..2dbb95f952 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAnimatorImplAccessor.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsAnimatorImplAccessor.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.mixin.features.textures.animations.upload; +package net.caffeinemc.mods.sodium.mixin.features.textures.animations.upload; import net.minecraft.client.renderer.texture.SpriteContents; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsInterpolationMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsInterpolationMixin.java similarity index 94% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsInterpolationMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsInterpolationMixin.java index d4496e5794..d58b6f389f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsInterpolationMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/animations/upload/SpriteContentsInterpolationMixin.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.mixin.features.textures.animations.upload; +package net.caffeinemc.mods.sodium.mixin.features.textures.animations.upload; -import me.jellysquid.mods.sodium.client.util.NativeImageHelper; -import me.jellysquid.mods.sodium.mixin.features.textures.SpriteContentsInvoker; +import net.caffeinemc.mods.sodium.client.util.NativeImageHelper; +import net.caffeinemc.mods.sodium.mixin.features.textures.SpriteContentsInvoker; import net.caffeinemc.mods.sodium.api.util.ColorMixer; import net.minecraft.client.renderer.texture.SpriteContents; import org.lwjgl.system.MemoryUtil; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/mipmaps/MipmapHelperMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/mipmaps/MipmapHelperMixin.java similarity index 97% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/mipmaps/MipmapHelperMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/mipmaps/MipmapHelperMixin.java index 658a3eef1a..c6ba4ca546 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/mipmaps/MipmapHelperMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/mipmaps/MipmapHelperMixin.java @@ -1,6 +1,6 @@ -package me.jellysquid.mods.sodium.mixin.features.textures.mipmaps; +package net.caffeinemc.mods.sodium.mixin.features.textures.mipmaps; -import me.jellysquid.mods.sodium.client.util.color.ColorSRGB; +import net.caffeinemc.mods.sodium.client.util.color.ColorSRGB; import net.minecraft.client.renderer.texture.MipmapGenerator; import net.minecraft.util.FastColor; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/mipmaps/SpriteContentsMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/mipmaps/SpriteContentsMixin.java similarity index 96% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/mipmaps/SpriteContentsMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/mipmaps/SpriteContentsMixin.java index 96d967b5c7..c59a26dec7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/textures/mipmaps/SpriteContentsMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/textures/mipmaps/SpriteContentsMixin.java @@ -1,8 +1,8 @@ -package me.jellysquid.mods.sodium.mixin.features.textures.mipmaps; +package net.caffeinemc.mods.sodium.mixin.features.textures.mipmaps; import com.mojang.blaze3d.platform.NativeImage; -import me.jellysquid.mods.sodium.client.util.NativeImageHelper; -import me.jellysquid.mods.sodium.client.util.color.ColorSRGB; +import net.caffeinemc.mods.sodium.client.util.NativeImageHelper; +import net.caffeinemc.mods.sodium.client.util.color.ColorSRGB; import net.minecraft.client.renderer.texture.SpriteContents; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.FastColor; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/world/biome/BiomeMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/world/biome/BiomeMixin.java similarity index 95% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/world/biome/BiomeMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/world/biome/BiomeMixin.java index 12ab3ea0bb..717d9ac701 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/world/biome/BiomeMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/world/biome/BiomeMixin.java @@ -1,7 +1,7 @@ -package me.jellysquid.mods.sodium.mixin.features.world.biome; +package net.caffeinemc.mods.sodium.mixin.features.world.biome; import java.util.Optional; -import me.jellysquid.mods.sodium.client.world.biome.BiomeColorMaps; +import net.caffeinemc.mods.sodium.client.world.biome.BiomeColorMaps; import net.minecraft.util.Mth; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.BiomeSpecialEffects; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/world/storage/ClientChunkMapMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/world/storage/ClientChunkMapMixin.java similarity index 96% rename from src/main/java/me/jellysquid/mods/sodium/mixin/features/world/storage/ClientChunkMapMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/features/world/storage/ClientChunkMapMixin.java index 7449ed72e4..6e146be745 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/world/storage/ClientChunkMapMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/features/world/storage/ClientChunkMapMixin.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.mixin.features.world.storage; +package net.caffeinemc.mods.sodium.mixin.features.world.storage; import org.spongepowered.asm.mixin.*; import org.spongepowered.asm.mixin.injection.At; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/workarounds/context_creation/WindowMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/workarounds/context_creation/WindowMixin.java similarity index 89% rename from src/main/java/me/jellysquid/mods/sodium/mixin/workarounds/context_creation/WindowMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/workarounds/context_creation/WindowMixin.java index 49f30b325e..d7fe94db3e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/workarounds/context_creation/WindowMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/workarounds/context_creation/WindowMixin.java @@ -1,13 +1,13 @@ -package me.jellysquid.mods.sodium.mixin.workarounds.context_creation; +package net.caffeinemc.mods.sodium.mixin.workarounds.context_creation; -import me.jellysquid.mods.sodium.client.compatibility.checks.ModuleScanner; +import net.caffeinemc.mods.sodium.client.compatibility.checks.ModuleScanner; import com.mojang.blaze3d.platform.DisplayData; import com.mojang.blaze3d.platform.ScreenManager; import com.mojang.blaze3d.platform.Window; import com.mojang.blaze3d.platform.WindowEventHandler; -import me.jellysquid.mods.sodium.client.compatibility.checks.LateDriverScanner; -import me.jellysquid.mods.sodium.client.compatibility.workarounds.Workarounds; -import me.jellysquid.mods.sodium.client.compatibility.workarounds.nvidia.NvidiaWorkarounds; +import net.caffeinemc.mods.sodium.client.compatibility.checks.LateDriverScanner; +import net.caffeinemc.mods.sodium.client.compatibility.workarounds.Workarounds; +import net.caffeinemc.mods.sodium.client.compatibility.workarounds.nvidia.NvidiaWorkarounds; import net.minecraft.Util; import org.lwjgl.glfw.GLFW; import org.lwjgl.opengl.WGL; diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/workarounds/event_loop/RenderSystemMixin.java b/src/main/java/net/caffeinemc/mods/sodium/mixin/workarounds/event_loop/RenderSystemMixin.java similarity index 90% rename from src/main/java/me/jellysquid/mods/sodium/mixin/workarounds/event_loop/RenderSystemMixin.java rename to src/main/java/net/caffeinemc/mods/sodium/mixin/workarounds/event_loop/RenderSystemMixin.java index ffd669ae2e..b4459c7058 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/workarounds/event_loop/RenderSystemMixin.java +++ b/src/main/java/net/caffeinemc/mods/sodium/mixin/workarounds/event_loop/RenderSystemMixin.java @@ -1,4 +1,4 @@ -package me.jellysquid.mods.sodium.mixin.workarounds.event_loop; +package net.caffeinemc.mods.sodium.mixin.workarounds.event_loop; import com.mojang.blaze3d.systems.RenderSystem; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 06409e9694..e2466ffb5c 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -45,10 +45,10 @@ "environment": "client", "entrypoints": { "client": [ - "me.jellysquid.mods.sodium.client.SodiumClientMod" + "net.caffeinemc.mods.sodium.client.SodiumClientMod" ], "preLaunch": [ - "me.jellysquid.mods.sodium.client.SodiumPreLaunch" + "net.caffeinemc.mods.sodium.client.SodiumPreLaunch" ] }, "custom": { diff --git a/src/main/resources/sodium.mixins.json b/src/main/resources/sodium.mixins.json index 8f0769414c..35737ff6df 100644 --- a/src/main/resources/sodium.mixins.json +++ b/src/main/resources/sodium.mixins.json @@ -1,8 +1,8 @@ { - "package": "me.jellysquid.mods.sodium.mixin", + "package": "net.caffeinemc.mods.sodium.mixin", "required": true, "compatibilityLevel": "JAVA_17", - "plugin": "me.jellysquid.mods.sodium.mixin.SodiumMixinPlugin", + "plugin": "net.caffeinemc.mods.sodium.mixin.SodiumMixinPlugin", "injectors": { "defaultRequire": 1 }, From bb1a2410cb7c1e79f23e24bc40f2a3d47c52637e Mon Sep 17 00:00:00 2001 From: douira Date: Wed, 14 Feb 2024 04:30:28 +0100 Subject: [PATCH 255/256] reintroduce quadCount tracking in topo sort that went missing in the last refactor --- .../bsp_tree/InnerPartitionBSPNode.java | 2 +- .../data/TopoGraphSorting.java | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java index 44555da511..ce76d939a6 100644 --- a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java @@ -428,7 +428,7 @@ static private BSPNode buildTopoMultiLeafNode(BSPWorkspace workspace, IntArrayLi } var indexWriter = new QuadIndexConsumerIntoArray(quadCount); - if (!TopoGraphSorting.topoGraphSort(indexWriter, quads, activeToRealIndex, null, null)) { + if (!TopoGraphSorting.topoGraphSort(indexWriter, quads, quads.length, activeToRealIndex, null, null)) { return null; } diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/TopoGraphSorting.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/TopoGraphSorting.java index fcbe754c97..d45af2c756 100644 --- a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/TopoGraphSorting.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/TopoGraphSorting.java @@ -197,22 +197,25 @@ public static boolean topoGraphSort( // if enabled, check for visibility and produce a mapping of indices TQuad[] quads; int[] activeToRealIndex = null; + + // keep track of the number of quads to be processed, this is possibly less than quads.length + int quadCount = 0; + if (cameraPos != null) { // allocate the working quads and index map at the full size to avoid needing to // iterate the quads again after checking visibility quads = new TQuad[allQuads.length]; activeToRealIndex = new int[allQuads.length]; - int activeQuads = 0; for (int i = 0; i < allQuads.length; i++) { TQuad quad = allQuads[i]; // NOTE: This approximation may introduce wrong sorting if the real and the // quantized normal aren't the same. A quad may be ignored with the quantized // normal, but it's actually visible in camera. if (pointOutsideHalfSpace(quad.getDotProduct(), quad.getQuantizedNormal(), cameraPos)) { - activeToRealIndex[activeQuads] = i; - quads[activeQuads] = quad; - activeQuads++; + activeToRealIndex[quadCount] = i; + quads[quadCount] = quad; + quadCount++; } else { // write the invisible quads right away indexConsumer.accept(i); @@ -220,14 +223,13 @@ public static boolean topoGraphSort( } } else { quads = allQuads; + quadCount = allQuads.length; } - return topoGraphSort(indexConsumer, quads, activeToRealIndex, distancesByNormal, cameraPos); + return topoGraphSort(indexConsumer, quads, quadCount, activeToRealIndex, distancesByNormal, cameraPos); } - public static boolean topoGraphSort(IntConsumer indexConsumer, TQuad[] quads, int[] activeToRealIndex, Object2ReferenceOpenHashMap distancesByNormal, Vector3fc cameraPos) { - int quadCount = quads.length; - + public static boolean topoGraphSort(IntConsumer indexConsumer, TQuad[] quads, int quadCount, int[] activeToRealIndex, Object2ReferenceOpenHashMap distancesByNormal, Vector3fc cameraPos) { // special case for 0 to 2 quads if (quadCount == 0) { return true; From 4176843e136e1b19319ddead300d367399be7890 Mon Sep 17 00:00:00 2001 From: JellySquid Date: Wed, 14 Feb 2024 19:39:37 -0600 Subject: [PATCH 256/256] Clean-up handling of chunk draw command generation --- .../render/chunk/DefaultChunkRenderer.java | 98 +++++++++++---- .../chunk/data/SectionRenderDataStorage.java | 113 +++++++++++------- .../chunk/data/SectionRenderDataUnsafe.java | 40 +++++-- 3 files changed, 172 insertions(+), 79 deletions(-) diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/DefaultChunkRenderer.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/DefaultChunkRenderer.java index ab9bf9e590..8a83eb6ba7 100644 --- a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/DefaultChunkRenderer.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/DefaultChunkRenderer.java @@ -53,9 +53,8 @@ public void render(ChunkRenderMatrices matrices, CameraTransform camera) { super.begin(renderPass); - boolean isTranslucent = renderPass == DefaultTerrainRenderPasses.TRANSLUCENT - && SodiumClientMod.options().performance.getSortBehavior() != SortBehavior.OFF; - boolean useBlockFaceCulling = SodiumClientMod.options().performance.useBlockFaceCulling; + final boolean useBlockFaceCulling = SodiumClientMod.options().performance.useBlockFaceCulling; + final boolean useIndexedTessellation = isTranslucentRenderPass(renderPass); ChunkShaderInterface shader = this.activeProgram.getInterface(); shader.setProjectionMatrix(matrices.projection()); @@ -79,11 +78,17 @@ public void render(ChunkRenderMatrices matrices, continue; } + // When the shared index buffer is being used, we must ensure the storage has been allocated *before* + // the tessellation is prepared. + if (!useIndexedTessellation) { + this.sharedIndexBuffer.ensureCapacity(commandList, this.batch.getIndexBufferSize()); + } + GlTessellation tessellation; - if (isTranslucent) { + + if (useIndexedTessellation) { tessellation = this.prepareIndexedTessellation(commandList, region); } else { - this.sharedIndexBuffer.ensureCapacity(commandList, this.batch.getIndexBufferSize()); tessellation = this.prepareTessellation(commandList, region); } @@ -94,6 +99,11 @@ public void render(ChunkRenderMatrices matrices, super.end(renderPass); } + private static boolean isTranslucentRenderPass(TerrainRenderPass renderPass) { + return renderPass == DefaultTerrainRenderPasses.TRANSLUCENT + && SodiumClientMod.options().performance.getSortBehavior() != SortBehavior.OFF; + } + private static void fillCommandBuffer(MultiDrawBatch batch, RenderRegion renderRegion, SectionRenderDataStorage renderDataStorage, @@ -109,6 +119,7 @@ private static void fillCommandBuffer(MultiDrawBatch batch, return; } + // The origin of the chunk in world space int originX = renderRegion.getChunkX(); int originY = renderRegion.getChunkY(); int originZ = renderRegion.getChunkZ(); @@ -116,12 +127,13 @@ private static void fillCommandBuffer(MultiDrawBatch batch, while (iterator.hasNext()) { int sectionIndex = iterator.nextByteAsInt(); + var pMeshData = renderDataStorage.getDataPointer(sectionIndex); + int chunkX = originX + LocalSectionIndex.unpackX(sectionIndex); int chunkY = originY + LocalSectionIndex.unpackY(sectionIndex); int chunkZ = originZ + LocalSectionIndex.unpackZ(sectionIndex); - var pMeshData = renderDataStorage.getDataPointer(sectionIndex); - + // The bit field of "visible" geometry sets which should be rendered int slices; if (useBlockFaceCulling) { @@ -130,11 +142,15 @@ private static void fillCommandBuffer(MultiDrawBatch batch, slices = ModelQuadFacing.ALL; } + // Mask off any geometry sets which are empty (contain no geometry) slices &= SectionRenderDataUnsafe.getSliceMask(pMeshData); - if (slices != 0) { - addDrawCommands(batch, pMeshData, slices); + // If there are no geometry sets to render, don't try to build a draw command buffer for this section + if (slices == 0) { + continue; } + + addDrawCommands(batch, pMeshData, slices); } } @@ -146,34 +162,66 @@ private static void fillCommandBuffer(MultiDrawBatch batch, * draw batch provides pointers to arrays where each of the section's data is * stored. The batch's size counts how many commands it contains. */ - @SuppressWarnings("IntegerMultiplicationImplicitCastToLong") private static void addDrawCommands(MultiDrawBatch batch, long pMeshData, int mask) { + int elementOffset = SectionRenderDataUnsafe.getBaseElement(pMeshData); + + // If high bit is set, the indices should be sourced from the arena's index buffer + if ((elementOffset & SectionRenderDataUnsafe.BASE_ELEMENT_MSB) != 0) { + addIndexedDrawCommands(batch, pMeshData, mask); + } else { + addNonIndexedDrawCommands(batch, pMeshData, mask); + } + } + + /** + * Generates the draw commands for a chunk's meshes using the shared index buffer. + */ + @SuppressWarnings("IntegerMultiplicationImplicitCastToLong") + private static void addNonIndexedDrawCommands(MultiDrawBatch batch, long pMeshData, int mask) { final var pElementPointer = batch.pElementPointer; final var pBaseVertex = batch.pBaseVertex; final var pElementCount = batch.pElementCount; int size = batch.size; - int indexDataOffset = SectionRenderDataUnsafe.getIndexOffset(pMeshData); for (int facing = 0; facing < ModelQuadFacing.COUNT; facing++) { MemoryUtil.memPutInt(pBaseVertex + (size << 2), SectionRenderDataUnsafe.getVertexOffset(pMeshData, facing)); - var elementCount = SectionRenderDataUnsafe.getElementCount(pMeshData, facing); - MemoryUtil.memPutInt(pElementCount + (size << 2), elementCount); + MemoryUtil.memPutInt(pElementCount + (size << 2), SectionRenderDataUnsafe.getElementCount(pMeshData, facing)); + MemoryUtil.memPutAddress(pElementPointer + (size << 3), 0 /* using a shared index buffer */); - // zero check for when we're not rendering any translucent data - // TODO: unclear if the offset can naturally be zero sometimes - if (indexDataOffset != 0) { - // * 4 to convert to bytes (the buffer contains ints) - // the section render data storage for the indices stores the offset in indices (also called elements) - // the << 3 is * 8 to convert to 8 byte offsets - MemoryUtil.memPutAddress(pElementPointer + (size << 3), indexDataOffset << 2); + size += (mask >> facing) & 1; + } - // adding the number of elements works because the index data has one index per element (which are the indices) - indexDataOffset += elementCount; - } else { - MemoryUtil.memPutAddress(pElementPointer + (size << 3), 0); - } + batch.size = size; + } + + /** + * Generates the draw commands for a chunk's meshes, where each mesh has a separate index buffer. This is used + * when rendering translucent geometry, as each geometry set needs a sorted index buffer. + */ + @SuppressWarnings("IntegerMultiplicationImplicitCastToLong") + private static void addIndexedDrawCommands(MultiDrawBatch batch, long pMeshData, int mask) { + final var pElementPointer = batch.pElementPointer; + final var pBaseVertex = batch.pBaseVertex; + final var pElementCount = batch.pElementCount; + + int size = batch.size; + + int elementOffset = SectionRenderDataUnsafe.getBaseElement(pMeshData) + & ~SectionRenderDataUnsafe.BASE_ELEMENT_MSB; + + for (int facing = 0; facing < ModelQuadFacing.COUNT; facing++) { + final var elementCount = SectionRenderDataUnsafe.getElementCount(pMeshData, facing); + + MemoryUtil.memPutInt(pBaseVertex + (size << 2), SectionRenderDataUnsafe.getVertexOffset(pMeshData, facing)); + MemoryUtil.memPutInt(pElementCount + (size << 2), elementCount); + + // * 4 to convert to bytes (the buffer contains 32-bit integers) + // the section render data storage for the indices stores the offset in indices (also called elements) + MemoryUtil.memPutAddress(pElementPointer + (size << 3), elementOffset << 2); + // adding the number of elements works because the index data has one index per element (which are the indices) + elementOffset += elementCount; size += (mask >> facing) & 1; } diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java index e47c138d43..e677e36803 100644 --- a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java @@ -4,6 +4,8 @@ import net.caffeinemc.mods.sodium.client.gl.util.VertexRange; import net.caffeinemc.mods.sodium.client.model.quad.properties.ModelQuadFacing; import net.caffeinemc.mods.sodium.client.render.chunk.region.RenderRegion; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.Arrays; @@ -27,26 +29,32 @@ * updated independently of each other (in both directions). */ public class SectionRenderDataStorage { - private final GlBufferSegment[] allocations; + private final @Nullable GlBufferSegment[] vertexAllocations; + private final @Nullable GlBufferSegment @Nullable[] elementAllocations; private final long pMeshDataArray; - private final boolean storesIndices; public SectionRenderDataStorage(boolean storesIndices) { - var allocationCount = RenderRegion.REGION_SIZE * (storesIndices ? 2 : 1); - this.allocations = new GlBufferSegment[allocationCount]; + this.vertexAllocations = new GlBufferSegment[RenderRegion.REGION_SIZE]; + + if (storesIndices) { + this.elementAllocations = new GlBufferSegment[RenderRegion.REGION_SIZE]; + } else { + this.elementAllocations = null; + } + this.pMeshDataArray = SectionRenderDataUnsafe.allocateHeap(RenderRegion.REGION_SIZE); - this.storesIndices = storesIndices; } public void setVertexData(int localSectionIndex, GlBufferSegment allocation, VertexRange[] ranges) { - if (this.allocations[localSectionIndex] != null) { - this.allocations[localSectionIndex].delete(); - this.allocations[localSectionIndex] = null; + GlBufferSegment prev = this.vertexAllocations[localSectionIndex]; + + if (prev != null) { + prev.delete(); } - this.allocations[localSectionIndex] = allocation; + this.vertexAllocations[localSectionIndex] = allocation; var pMeshData = this.getDataPointer(localSectionIndex); @@ -77,26 +85,28 @@ public void setVertexData(int localSectionIndex, } public void setIndexData(int localSectionIndex, GlBufferSegment allocation) { - if (!this.storesIndices) { + if (this.elementAllocations == null) { throw new IllegalStateException("Cannot set index data when storesIndices is false"); } - var indexAllocationIndex = localSectionIndex + RenderRegion.REGION_SIZE; - if (this.allocations[indexAllocationIndex] != null) { - this.allocations[indexAllocationIndex].delete(); - this.allocations[indexAllocationIndex] = null; + GlBufferSegment prev = this.elementAllocations[localSectionIndex]; + + if (prev != null) { + prev.delete(); } - this.allocations[indexAllocationIndex] = allocation; + this.elementAllocations[localSectionIndex] = allocation; var pMeshData = this.getDataPointer(localSectionIndex); - SectionRenderDataUnsafe.setIndexOffset(pMeshData, allocation.getOffset()); + SectionRenderDataUnsafe.setBaseElement(pMeshData, + allocation.getOffset() | SectionRenderDataUnsafe.BASE_ELEMENT_MSB); } public void removeData(int localSectionIndex) { this.removeVertexData(localSectionIndex, false); - if (this.storesIndices) { + + if (this.elementAllocations != null) { this.removeIndexData(localSectionIndex); } } @@ -106,28 +116,40 @@ public void removeVertexData(int localSectionIndex) { } private void removeVertexData(int localSectionIndex, boolean retainIndexData) { - if (this.allocations[localSectionIndex] == null) { + GlBufferSegment prev = this.vertexAllocations[localSectionIndex]; + + if (prev == null) { return; } - this.allocations[localSectionIndex].delete(); - this.allocations[localSectionIndex] = null; + prev.delete(); + + this.vertexAllocations[localSectionIndex] = null; var pMeshData = this.getDataPointer(localSectionIndex); - var indexOffset = SectionRenderDataUnsafe.getIndexOffset(pMeshData); + + var baseElement = SectionRenderDataUnsafe.getBaseElement(pMeshData); SectionRenderDataUnsafe.clear(pMeshData); - SectionRenderDataUnsafe.setIndexOffset(pMeshData, indexOffset); + + if (retainIndexData) { + SectionRenderDataUnsafe.setBaseElement(pMeshData, baseElement); + } } public void removeIndexData(int localSectionIndex) { - if (!this.storesIndices) { + final GlBufferSegment[] allocations = this.elementAllocations; + + if (allocations == null) { throw new IllegalStateException("Cannot remove index data when storesIndices is false"); } - var indexAllocationIndex = localSectionIndex + RenderRegion.REGION_SIZE; - if (this.allocations[indexAllocationIndex] != null) { - this.allocations[indexAllocationIndex].delete(); - this.allocations[indexAllocationIndex] = null; + + GlBufferSegment prev = allocations[localSectionIndex]; + + if (prev != null) { + prev.delete(); } + + allocations[localSectionIndex] = null; } public void onBufferResized() { @@ -137,7 +159,7 @@ public void onBufferResized() { } private void updateMeshes(int sectionIndex) { - var allocation = this.allocations[sectionIndex]; + var allocation = this.vertexAllocations[sectionIndex]; if (allocation == null) { return; @@ -155,18 +177,17 @@ private void updateMeshes(int sectionIndex) { } public void onIndexBufferResized() { - if (this.storesIndices) { - for (int sectionIndex = 0; sectionIndex < RenderRegion.REGION_SIZE; sectionIndex++) { - this.updateIndexes(sectionIndex); - } + if (this.elementAllocations == null) { + return; } - } - private void updateIndexes(int sectionIndex) { - var data = this.getDataPointer(sectionIndex); - var indexAllocation = this.allocations[sectionIndex + RenderRegion.REGION_SIZE]; - if (indexAllocation != null) { - SectionRenderDataUnsafe.setIndexOffset(data, indexAllocation.getOffset()); + for (int sectionIndex = 0; sectionIndex < RenderRegion.REGION_SIZE; sectionIndex++) { + var allocation = this.elementAllocations[sectionIndex]; + + if (allocation != null) { + SectionRenderDataUnsafe.setBaseElement(this.getDataPointer(sectionIndex), + allocation.getOffset() | SectionRenderDataUnsafe.BASE_ELEMENT_MSB); + } } } @@ -175,14 +196,22 @@ public long getDataPointer(int sectionIndex) { } public void delete() { - for (var allocation : this.allocations) { + deleteAllocations(this.vertexAllocations); + + if (this.elementAllocations != null) { + deleteAllocations(this.elementAllocations); + } + + SectionRenderDataUnsafe.freeHeap(this.pMeshDataArray); + } + + private static void deleteAllocations(GlBufferSegment @NotNull [] allocations) { + for (var allocation : allocations) { if (allocation != null) { allocation.delete(); } } - Arrays.fill(this.allocations, null); - - SectionRenderDataUnsafe.freeHeap(this.pMeshDataArray); + Arrays.fill(allocations, null); } } diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/data/SectionRenderDataUnsafe.java b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/data/SectionRenderDataUnsafe.java index 0fec99b963..cf483e1227 100644 --- a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/data/SectionRenderDataUnsafe.java +++ b/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/data/SectionRenderDataUnsafe.java @@ -15,29 +15,45 @@ // Please never try to write performance critical code in Java. This is what it will do to you. And you will still be // three times slower than the most naive solution in literally any other language that LLVM can compile. -// the structure is roughly as follows: -// struct SectionRenderData { // 68 bytes +// struct SectionRenderData { // 64 bytes +// base_element: u32 // mask: u32, -// index_offset: u32 // ranges: [VertexRange; 7] // } +// // struct VertexRange { // 8 bytes // offset: u32, // count: u32 // } + public class SectionRenderDataUnsafe { - private static final long OFFSET_SLICE_MASK = 0; - private static final long OFFSET_SLICE_INDEX_OFFSETS = 4; + public static final int BASE_ELEMENT_MSB = 1 << 31; + + /** + * When the "base element" field is not specified (indicated by setting the MSB to 0), the indices for the geometry set + * should be sourced from a monotonic sequence (see {@link net.caffeinemc.mods.sodium.client.render.chunk.SharedQuadIndexBuffer}). + * + * Otherwise, indices should be sourced from the index buffer for the render region using the specified offset. + */ + private static final long OFFSET_BASE_ELEMENT = 0; + + private static final long OFFSET_SLICE_MASK = 4; private static final long OFFSET_SLICE_RANGES = 8; - private static final long STRIDE = 64; + private static final long ALIGNMENT = 64; + private static final long STRIDE = 64; // cache-line friendly! :) public static long allocateHeap(int count) { - return MemoryUtil.nmemCalloc(count, STRIDE); + final var bytes = STRIDE * count; + + final var ptr = MemoryUtil.nmemAlignedAlloc(ALIGNMENT, bytes); + MemoryUtil.memSet(ptr, 0, bytes); + + return ptr; } public static void freeHeap(long pointer) { - MemoryUtil.nmemFree(pointer); + MemoryUtil.nmemAlignedFree(pointer); } public static void clear(long pointer) { @@ -56,12 +72,12 @@ public static int getSliceMask(long ptr) { return MemoryUtil.memGetInt(ptr + OFFSET_SLICE_MASK); } - public static void setIndexOffset(long ptr, int value) { - MemoryUtil.memPutInt(ptr + OFFSET_SLICE_INDEX_OFFSETS, value); + public static void setBaseElement(long ptr, int value) { + MemoryUtil.memPutInt(ptr + OFFSET_BASE_ELEMENT, value); } - public static int getIndexOffset(long ptr) { - return MemoryUtil.memGetInt(ptr + OFFSET_SLICE_INDEX_OFFSETS); + public static int getBaseElement(long ptr) { + return MemoryUtil.memGetInt(ptr + OFFSET_BASE_ELEMENT); } public static void setVertexOffset(long ptr, int facing, int value) {