From 2311649c2e2f353328736b94a4d64e786e8027f6 Mon Sep 17 00:00:00 2001 From: IMS212 Date: Sat, 28 Sep 2024 05:59:30 -0700 Subject: [PATCH] Extremely complicated code --- .../compat/sodium/mixin/MixinBakedModel.java | 85 ++++++ .../sodium/mixin/MixinEntityRenderer.java | 204 ++++++++++++++ .../sodium/mixin/MixinSingleQuadParticle.java | 126 +++++++++ .../iris/gl/shader/ProgramCreator.java | 1 + .../net/irisshaders/iris/helpers/Float16.java | 256 ++++++++++++++++++ .../iris/mixin/MixinBakedQuad.java | 38 +++ .../irisshaders/iris/mixin/MixinEntity.java | 41 +++ .../iris/mixin/MixinModelCuboid.java | 34 +++ .../iris/mixin/MixinVertexFormatType.java | 31 +++ .../iris/mixin/VertexTypeAccessor.java | 14 + .../MixinEntityRenderDispatcher.java | 4 + .../mixin/vertices/MixinBufferBuilder.java | 8 + .../mixin/vertices/MixinVertexFormat.java | 8 + .../iris/mixinterface/EntityUniqueId.java | 5 + .../iris/mixinterface/ModelPartAccess.java | 7 + .../iris/mixinterface/QuadPositionAccess.java | 7 + .../iris/pathways/EntityIdStorage.java | 7 + .../iris/pipeline/CubePositions.java | 40 +++ .../iris/pipeline/QuadPositions.java | 40 +++ .../iris/pipeline/programs/ShaderKey.java | 8 +- .../iris/uniforms/CapturedRenderingState.java | 9 + .../iris/vertices/IrisFormatTypes.java | 7 + .../iris/vertices/IrisVertexFormats.java | 14 + .../vertices/sodium/IrisEntityVertex.java | 48 ++++ .../vertices/sodium/IrisParticleVertex.java | 31 +++ .../resources/mixins.iris.compat.sodium.json | 3 + common/src/main/resources/mixins.iris.json | 5 + fabric/src/main/resources/fabric.mod.json | 3 +- 28 files changed, 1079 insertions(+), 5 deletions(-) create mode 100644 common/src/main/java/net/irisshaders/iris/compat/sodium/mixin/MixinBakedModel.java create mode 100644 common/src/main/java/net/irisshaders/iris/compat/sodium/mixin/MixinEntityRenderer.java create mode 100644 common/src/main/java/net/irisshaders/iris/compat/sodium/mixin/MixinSingleQuadParticle.java create mode 100644 common/src/main/java/net/irisshaders/iris/helpers/Float16.java create mode 100644 common/src/main/java/net/irisshaders/iris/mixin/MixinBakedQuad.java create mode 100644 common/src/main/java/net/irisshaders/iris/mixin/MixinEntity.java create mode 100644 common/src/main/java/net/irisshaders/iris/mixin/MixinModelCuboid.java create mode 100644 common/src/main/java/net/irisshaders/iris/mixin/MixinVertexFormatType.java create mode 100644 common/src/main/java/net/irisshaders/iris/mixin/VertexTypeAccessor.java create mode 100644 common/src/main/java/net/irisshaders/iris/mixinterface/EntityUniqueId.java create mode 100644 common/src/main/java/net/irisshaders/iris/mixinterface/ModelPartAccess.java create mode 100644 common/src/main/java/net/irisshaders/iris/mixinterface/QuadPositionAccess.java create mode 100644 common/src/main/java/net/irisshaders/iris/pathways/EntityIdStorage.java create mode 100644 common/src/main/java/net/irisshaders/iris/pipeline/CubePositions.java create mode 100644 common/src/main/java/net/irisshaders/iris/pipeline/QuadPositions.java create mode 100644 common/src/main/java/net/irisshaders/iris/vertices/IrisFormatTypes.java create mode 100644 common/src/main/java/net/irisshaders/iris/vertices/sodium/IrisEntityVertex.java create mode 100644 common/src/main/java/net/irisshaders/iris/vertices/sodium/IrisParticleVertex.java diff --git a/common/src/main/java/net/irisshaders/iris/compat/sodium/mixin/MixinBakedModel.java b/common/src/main/java/net/irisshaders/iris/compat/sodium/mixin/MixinBakedModel.java new file mode 100644 index 0000000000..10de2100e3 --- /dev/null +++ b/common/src/main/java/net/irisshaders/iris/compat/sodium/mixin/MixinBakedModel.java @@ -0,0 +1,85 @@ +package net.irisshaders.iris.compat.sodium.mixin; + +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.EntityVertex; +import net.caffeinemc.mods.sodium.client.model.quad.ModelQuadView; +import net.caffeinemc.mods.sodium.client.render.frapi.helper.ColorHelper; +import net.caffeinemc.mods.sodium.client.render.immediate.model.BakedModelEncoder; +import net.irisshaders.iris.Iris; +import net.irisshaders.iris.mixinterface.QuadPositionAccess; +import net.irisshaders.iris.pipeline.QuadPositions; +import net.irisshaders.iris.uniforms.CapturedRenderingState; +import net.irisshaders.iris.uniforms.SystemTimeUniforms; +import net.irisshaders.iris.vertices.sodium.IrisEntityVertex; +import org.joml.Matrix3f; +import org.joml.Matrix4f; +import org.lwjgl.system.MemoryStack; +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(BakedModelEncoder.class) +public abstract class MixinBakedModel { + @Shadow + private static int mergeLighting(int stored, int calculated) { + return 0; + } + + @Inject(method = "writeQuadVertices(Lnet/caffeinemc/mods/sodium/api/vertex/buffer/VertexBufferWriter;Lcom/mojang/blaze3d/vertex/PoseStack$Pose;Lnet/caffeinemc/mods/sodium/client/model/quad/ModelQuadView;IIIZ)V", at = @At("HEAD"), cancellable = true) + private static void redirectToIris(VertexBufferWriter writer, PoseStack.Pose matrices, ModelQuadView quad, int color, int light, int overlay, boolean colorize, CallbackInfo ci) { + if (Iris.isPackInUseQuick()) { + ci.cancel(); + writeIris(writer, matrices, quad, color, light, overlay, colorize); + } + } + + private static void writeIris(VertexBufferWriter writer, PoseStack.Pose matrices, ModelQuadView quad, int color, int light, int overlay, boolean colorize) { + Matrix3f matNormal = matrices.normal(); + Matrix4f matPosition = matrices.pose(); + + QuadPositions quadPositions = ((QuadPositionAccess) quad).getQuadPosition(CapturedRenderingState.INSTANCE.getEntityRollingId()); + + try (MemoryStack stack = MemoryStack.stackPush()) { + long buffer = stack.nmalloc(4 * IrisEntityVertex.STRIDE); + long ptr = buffer; + + float midU = (quad.getTexU(0) + quad.getTexU(1) + quad.getTexU(2) + quad.getTexU(3)) * 0.25f; + float midV = (quad.getTexV(0) + quad.getTexV(1) + quad.getTexV(2) + quad.getTexV(3)) * 0.25f; + + for (int i = 0; i < 4; i++) { + // The position vector + float x = quad.getX(i); + float y = quad.getY(i); + float z = quad.getZ(i); + + int newLight = mergeLighting(quad.getLight(i), light); + + int newColor = color; + + if (colorize) { + newColor = ColorHelper.multiplyColor(newColor, quad.getColor(i)); + } + + // The packed transformed normal vector + int normal = MatrixHelper.transformNormal(matNormal, matrices.trustedNormals, quad.getAccurateNormal(i)); + + // The transformed position vector + float xt = MatrixHelper.transformPositionX(matPosition, x, y, z); + float yt = MatrixHelper.transformPositionY(matPosition, x, y, z); + float zt = MatrixHelper.transformPositionZ(matPosition, x, y, z); + + quadPositions.setAndUpdate(SystemTimeUniforms.COUNTER.getAsInt(), i, xt, yt, zt); + + // TODO TANGENT + IrisEntityVertex.write(ptr, xt, yt, zt, quadPositions.velocityX[i], quadPositions.velocityY[i], quadPositions.velocityZ[i], newColor, quad.getTexU(i), quad.getTexV(i), overlay, newLight, normal, 0, midU, midV); + ptr += IrisEntityVertex.STRIDE; + } + + writer.push(stack, buffer, 4, IrisEntityVertex.FORMAT); + } + } +} diff --git a/common/src/main/java/net/irisshaders/iris/compat/sodium/mixin/MixinEntityRenderer.java b/common/src/main/java/net/irisshaders/iris/compat/sodium/mixin/MixinEntityRenderer.java new file mode 100644 index 0000000000..2b2c52bee7 --- /dev/null +++ b/common/src/main/java/net/irisshaders/iris/compat/sodium/mixin/MixinEntityRenderer.java @@ -0,0 +1,204 @@ +package net.irisshaders.iris.compat.sodium.mixin; + +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.client.render.immediate.model.EntityRenderer; +import net.caffeinemc.mods.sodium.client.render.immediate.model.ModelCuboid; +import net.irisshaders.iris.Iris; +import net.irisshaders.iris.mixinterface.ModelPartAccess; +import net.irisshaders.iris.pipeline.CubePositions; +import net.irisshaders.iris.uniforms.CapturedRenderingState; +import net.irisshaders.iris.uniforms.SystemTimeUniforms; +import net.irisshaders.iris.vertices.NormI8; +import net.irisshaders.iris.vertices.NormalHelper; +import net.irisshaders.iris.vertices.sodium.IrisEntityVertex; +import net.minecraft.core.Direction; +import org.joml.Matrix3f; +import org.joml.Matrix4f; +import org.joml.Vector2f; +import org.joml.Vector3f; +import org.joml.Vector4f; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.system.MemoryUtil; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +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; + +@Mixin(EntityRenderer.class) +public abstract class MixinEntityRenderer { + @Shadow + public static void prepareNormalsIfChanged(PoseStack.Pose matrices) { + } + + @Shadow + protected static void prepareVertices(PoseStack.Pose matrices, ModelCuboid cuboid) { + } + + @Shadow + @Final + private static int NUM_CUBE_FACES; + + @Shadow + @Final + private static int NUM_CUBE_VERTICES; + + @Shadow + @Final + private static Vector3f[][] VERTEX_POSITIONS_MIRRORED; + @Shadow + @Final + private static Vector3f[][] VERTEX_POSITIONS; + @Shadow + @Final + private static Vector2f[][] VERTEX_TEXTURES_MIRRORED; + @Shadow + @Final + private static Vector2f[][] VERTEX_TEXTURES; + @Shadow + @Final + private static int[] CUBE_NORMALS; + @Shadow + @Final + private static int[] CUBE_NORMALS_MIRRORED; + + @Unique + private static int[] CUBE_TANGENTS = new int[6]; + + @Unique + private static int[] CUBE_TANGENTS_MIRRORED = new int[6]; + + @Unique + private static final Vector2f[] MID_TEX_VALUES = new Vector2f[6]; + + static { + for (int i = 0; i < 6; i++) { + MID_TEX_VALUES[i] = new Vector2f(); + } + } + + private static final int + FACE_NEG_Y = 0, // DOWN + FACE_POS_Y = 1, // UP + FACE_NEG_X = 2, // WEST + FACE_NEG_Z = 3, // NORTH + FACE_POS_X = 4, // EAST + FACE_POS_Z = 5; // SOUTH + + + @Shadow + @Final + private static int[][] CUBE_VERTICES; + @Unique + private static final long SCRATCH_BUFFER_IRIS = MemoryUtil.nmemAlignedAlloc(64, NUM_CUBE_FACES * NUM_CUBE_VERTICES * IrisEntityVertex.STRIDE); + + @Inject(method = "renderCuboid", at = @At("HEAD"), cancellable = true) + private static void redirectToIris(PoseStack.Pose matrices, VertexBufferWriter writer, ModelCuboid cuboid, int light, int overlay, int color, CallbackInfo ci) { + if (Iris.isPackInUseQuick()) { + ci.cancel(); + renderCuboidIris(matrices, writer, cuboid, light, overlay, color); + } + } + private static void renderCuboidIris(PoseStack.Pose matrices, VertexBufferWriter writer, ModelCuboid cuboid, int light, int overlay, int color) { + prepareNormalsIfChanged(matrices); + + prepareVertices(matrices, cuboid); + prepareMidCoords(cuboid); + prepareTangentsIfChanged(matrices); + + var vertexCount = emitQuadsIris(cuboid, color, overlay, light); + + try (MemoryStack stack = MemoryStack.stackPush()) { + writer.push(stack, SCRATCH_BUFFER_IRIS, vertexCount, IrisEntityVertex.FORMAT); + } + } + + private static void prepareMidCoords(ModelCuboid cuboid) { + buildVertexMidTexCoord(MID_TEX_VALUES[FACE_NEG_Y], cuboid.u1, cuboid.v0, cuboid.u2, cuboid.v1); + buildVertexMidTexCoord(MID_TEX_VALUES[FACE_POS_Y], cuboid.u2, cuboid.v1, cuboid.u3, cuboid.v0); + buildVertexMidTexCoord(MID_TEX_VALUES[FACE_NEG_Z], cuboid.u1, cuboid.v1, cuboid.u2, cuboid.v2); + buildVertexMidTexCoord(MID_TEX_VALUES[FACE_POS_Z], cuboid.u4, cuboid.v1, cuboid.u5, cuboid.v2); + buildVertexMidTexCoord(MID_TEX_VALUES[FACE_NEG_X], cuboid.u2, cuboid.v1, cuboid.u4, cuboid.v2); + buildVertexMidTexCoord(MID_TEX_VALUES[FACE_POS_X], cuboid.u0, cuboid.v1, cuboid.u1, cuboid.v2); + } + + private static void buildVertexMidTexCoord(Vector2f midTexValue, float u1, float v1, float u2, float v2) { + midTexValue.set((u1 + u2) * 0.5f, (v1 + v2) * 0.5f); + } + + private static Matrix3f lastMatrix2 = new Matrix3f(); + + private static final Vector4f TANGENT_STORAGE = new Vector4f(); + + private static void prepareTangentsIfChanged(PoseStack.Pose matrices) { + if (!matrices.normal().equals(lastMatrix2)) { + lastMatrix2.set(matrices.normal()); + + for (int i = 0; i < 6; i++) { + CUBE_TANGENTS[i] = NormalHelper.computeTangent(TANGENT_STORAGE, NormI8.unpackX(CUBE_NORMALS[i]), NormI8.unpackY(CUBE_NORMALS[i]), NormI8.unpackZ(CUBE_NORMALS[i]), + VERTEX_POSITIONS[i][0].x, VERTEX_POSITIONS[i][0].y, VERTEX_POSITIONS[i][0].z, VERTEX_TEXTURES[i][0].x, VERTEX_TEXTURES[i][0].y, + VERTEX_POSITIONS[i][1].x, VERTEX_POSITIONS[i][1].y, VERTEX_POSITIONS[i][1].z, VERTEX_TEXTURES[i][1].x, VERTEX_TEXTURES[i][1].y, + VERTEX_POSITIONS[i][2].x, VERTEX_POSITIONS[i][2].y, VERTEX_POSITIONS[i][2].z, VERTEX_TEXTURES[i][2].x, VERTEX_TEXTURES[i][2].y); + } + + // When mirroring is used, the normals for EAST and WEST are swapped. + CUBE_TANGENTS_MIRRORED[FACE_NEG_Y] = CUBE_TANGENTS[FACE_NEG_Y]; + CUBE_TANGENTS_MIRRORED[FACE_POS_Y] = CUBE_TANGENTS[FACE_POS_Y]; + CUBE_TANGENTS_MIRRORED[FACE_NEG_Z] = CUBE_TANGENTS[FACE_NEG_Z]; + CUBE_TANGENTS_MIRRORED[FACE_POS_Z] = CUBE_TANGENTS[FACE_POS_Z]; + CUBE_TANGENTS_MIRRORED[FACE_POS_X] = CUBE_TANGENTS[FACE_NEG_X]; // mirrored + CUBE_TANGENTS_MIRRORED[FACE_NEG_X] = CUBE_TANGENTS[FACE_POS_X]; // mirrored + } + } + + private static int emitQuadsIris(ModelCuboid cuboid, int color, int overlay, int light) { + final var positions = cuboid.mirror ? VERTEX_POSITIONS_MIRRORED : VERTEX_POSITIONS; + final var textures = cuboid.mirror ? VERTEX_TEXTURES_MIRRORED : VERTEX_TEXTURES; + final var normals = cuboid.mirror ? CUBE_NORMALS_MIRRORED : CUBE_NORMALS; + final var tangents = cuboid.mirror ? CUBE_TANGENTS_MIRRORED : CUBE_TANGENTS; + + CubePositions velocity = ((ModelPartAccess) cuboid).getCubePosition(CapturedRenderingState.INSTANCE.getEntityRollingId()); + + var vertexCount = 0; + + long ptr = SCRATCH_BUFFER_IRIS; + + for (int quadIndex = 0; quadIndex < NUM_CUBE_FACES; quadIndex++) { + if (!cuboid.shouldDrawFace(quadIndex)) { + continue; + } + + float midU = MID_TEX_VALUES[quadIndex].x; + float midV = MID_TEX_VALUES[quadIndex].y; + + velocity.setAndUpdate(SystemTimeUniforms.COUNTER.getAsInt(), CUBE_VERTICES[quadIndex][0], positions[quadIndex][0].x, positions[quadIndex][0].y, positions[quadIndex][0].z); + emitIris(ptr, positions[quadIndex][0], color, textures[quadIndex][0], overlay, light, normals[quadIndex], tangents[quadIndex], velocity.velocityX[CUBE_VERTICES[quadIndex][0]], velocity.velocityY[CUBE_VERTICES[quadIndex][0]], velocity.velocityZ[CUBE_VERTICES[quadIndex][0]], midU, midV); + ptr += IrisEntityVertex.STRIDE; + + velocity.setAndUpdate(SystemTimeUniforms.COUNTER.getAsInt(), CUBE_VERTICES[quadIndex][1], positions[quadIndex][1].x, positions[quadIndex][1].y, positions[quadIndex][1].z); + emitIris(ptr, positions[quadIndex][1], color, textures[quadIndex][1], overlay, light, normals[quadIndex], tangents[quadIndex], velocity.velocityX[CUBE_VERTICES[quadIndex][1]], velocity.velocityY[CUBE_VERTICES[quadIndex][1]], velocity.velocityZ[CUBE_VERTICES[quadIndex][1]], midU, midV); + ptr += IrisEntityVertex.STRIDE; + + velocity.setAndUpdate(SystemTimeUniforms.COUNTER.getAsInt(), CUBE_VERTICES[quadIndex][2], positions[quadIndex][2].x, positions[quadIndex][2].y, positions[quadIndex][2].z); + emitIris(ptr, positions[quadIndex][2], color, textures[quadIndex][2], overlay, light, normals[quadIndex], tangents[quadIndex], velocity.velocityX[CUBE_VERTICES[quadIndex][2]], velocity.velocityY[CUBE_VERTICES[quadIndex][2]], velocity.velocityZ[CUBE_VERTICES[quadIndex][2]], midU, midV); + ptr += IrisEntityVertex.STRIDE; + + velocity.setAndUpdate(SystemTimeUniforms.COUNTER.getAsInt(), CUBE_VERTICES[quadIndex][3], positions[quadIndex][3].x, positions[quadIndex][3].y, positions[quadIndex][3].z); + emitIris(ptr, positions[quadIndex][3], color, textures[quadIndex][3], overlay, light, normals[quadIndex], tangents[quadIndex], velocity.velocityX[CUBE_VERTICES[quadIndex][3]], velocity.velocityY[CUBE_VERTICES[quadIndex][3]], velocity.velocityZ[CUBE_VERTICES[quadIndex][3]], midU, midV); + ptr += IrisEntityVertex.STRIDE; + + vertexCount += 4; + } + + return vertexCount; + } + + private static void emitIris(long ptr, Vector3f pos, int color, Vector2f tex, int overlay, int light, int normal, int tangent, + float prevX, float prevY, float prevZ, float midU, float midV) { + IrisEntityVertex.write(ptr, pos.x, pos.y, pos.z, prevX, prevY, prevZ, color, tex.x, tex.y, overlay, light, normal, tangent, midU, midV); + } +} diff --git a/common/src/main/java/net/irisshaders/iris/compat/sodium/mixin/MixinSingleQuadParticle.java b/common/src/main/java/net/irisshaders/iris/compat/sodium/mixin/MixinSingleQuadParticle.java new file mode 100644 index 0000000000..3d96ac5d5f --- /dev/null +++ b/common/src/main/java/net/irisshaders/iris/compat/sodium/mixin/MixinSingleQuadParticle.java @@ -0,0 +1,126 @@ +package net.irisshaders.iris.compat.sodium.mixin; + +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.irisshaders.iris.Iris; +import net.irisshaders.iris.pipeline.QuadPositions; +import net.irisshaders.iris.uniforms.SystemTimeUniforms; +import net.irisshaders.iris.vertices.sodium.IrisParticleVertex; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.particle.Particle; +import net.minecraft.client.particle.SingleQuadParticle; +import org.joml.Quaternionf; +import org.joml.Vector3f; +import org.lwjgl.system.MemoryStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; + +@Mixin(SingleQuadParticle.class) +public abstract class MixinSingleQuadParticle extends Particle { + @Shadow + public abstract float getQuadSize(float tickDelta); + + @Shadow + protected abstract float getU0(); + + @Shadow + protected abstract float getU1(); + + @Shadow + protected abstract float getV0(); + + @Shadow + protected abstract float getV1(); + + @Unique + private Vector3f transferVector = new Vector3f(); + + protected MixinSingleQuadParticle(ClientLevel level, double x, double y, double z) { + super(level, x, y, z); + } + + /** + * @reason Optimize function + * @author JellySquid + */ + @Overwrite + public void renderRotatedQuad(VertexConsumer vertexConsumer, Quaternionf quaternionf, float x, float y, float z, float tickDelta) { + float size = this.getQuadSize(tickDelta); + float minU = this.getU0(); + float maxU = this.getU1(); + float minV = this.getV0(); + float maxV = this.getV1(); + int light = this.getLightColor(tickDelta); + + var writer = VertexBufferWriter.of(vertexConsumer); + + int color = ColorABGR.pack(this.rCol, this.gCol, this.bCol, this.alpha); + + try (MemoryStack stack = MemoryStack.stackPush()) { + if (Iris.isPackInUseQuick()) { + long buffer = stack.nmalloc(4 * IrisParticleVertex.STRIDE); + long ptr = buffer; + + this.writeVertexIris(ptr, 0, quaternionf, x, y, z, 1.0F, -1.0F, size, maxU, maxV, color, light); + ptr += IrisParticleVertex.STRIDE; + + this.writeVertexIris(ptr, 1, quaternionf, x, y, z, 1.0F, 1.0F, size, maxU, minV, color, light); + ptr += IrisParticleVertex.STRIDE; + + this.writeVertexIris(ptr, 2, quaternionf, x, y, z, -1.0F, 1.0F, size, minU, minV, color, light); + ptr += IrisParticleVertex.STRIDE; + + this.writeVertexIris(ptr, 3, quaternionf, x, y, z, -1.0F, -1.0F, size, minU, maxV, color, light); + ptr += IrisParticleVertex.STRIDE; + + writer.push(stack, buffer, 4, IrisParticleVertex.FORMAT); + } else { + long buffer = stack.nmalloc(4 * ParticleVertex.STRIDE); + long ptr = buffer; + + this.writeVertex(ptr, quaternionf, x, y, z, 1.0F, -1.0F, size, maxU, maxV, color, light); + ptr += ParticleVertex.STRIDE; + + this.writeVertex(ptr, quaternionf, x, y, z, 1.0F, 1.0F, size, maxU, minV, color, light); + ptr += ParticleVertex.STRIDE; + + this.writeVertex(ptr, quaternionf, x, y, z, -1.0F, 1.0F, size, minU, minV, color, light); + ptr += ParticleVertex.STRIDE; + + this.writeVertex(ptr, quaternionf, x, y, z, -1.0F, -1.0F, size, minU, maxV, color, light); + ptr += ParticleVertex.STRIDE; + + writer.push(stack, buffer, 4, ParticleVertex.FORMAT); + } + } + } + + @Unique + private QuadPositions quadPositions = new QuadPositions(); + + @Unique + private void writeVertex(long ptr, Quaternionf quaternionf, float originX, float originY, float originZ, float posX, float posY, float size, float u, float v, int color, int light) { + transferVector.set(posX, posY, 0.0f); + transferVector.rotate(quaternionf); + transferVector.mul(size); + transferVector.add(originX, originY, originZ); + + ParticleVertex.put(ptr, transferVector.x(), transferVector.y(), transferVector.z(), u, v, color, light); + } + + @Unique + private void writeVertexIris(long ptr, int index, Quaternionf quaternionf, float originX, float originY, float originZ, float posX, float posY, float size, float u, float v, int color, int light) { + transferVector.set(posX, posY, 0.0f); + transferVector.rotate(quaternionf); + transferVector.mul(size); + transferVector.add(originX, originY, originZ); + + quadPositions.setAndUpdate(SystemTimeUniforms.COUNTER.getAsInt(), index, transferVector.x, transferVector.y, transferVector.z); + + IrisParticleVertex.put(ptr, transferVector.x(), transferVector.y(), transferVector.z(), quadPositions.velocityX[index], quadPositions.velocityY[index], quadPositions.velocityZ[index], u, v, color, light); + } +} diff --git a/common/src/main/java/net/irisshaders/iris/gl/shader/ProgramCreator.java b/common/src/main/java/net/irisshaders/iris/gl/shader/ProgramCreator.java index d86989103c..d8f958cfd0 100644 --- a/common/src/main/java/net/irisshaders/iris/gl/shader/ProgramCreator.java +++ b/common/src/main/java/net/irisshaders/iris/gl/shader/ProgramCreator.java @@ -21,6 +21,7 @@ public static int create(String name, GlShader... shaders) { GlStateManager._glBindAttribLocation(program, 12, "mc_midTexCoord"); GlStateManager._glBindAttribLocation(program, 13, "at_tangent"); GlStateManager._glBindAttribLocation(program, 14, "at_midBlock"); + GlStateManager._glBindAttribLocation(program, 15, "at_velocity"); GlStateManager._glBindAttribLocation(program, 0, "Position"); GlStateManager._glBindAttribLocation(program, 1, "UV0"); diff --git a/common/src/main/java/net/irisshaders/iris/helpers/Float16.java b/common/src/main/java/net/irisshaders/iris/helpers/Float16.java new file mode 100644 index 0000000000..0471d6646d --- /dev/null +++ b/common/src/main/java/net/irisshaders/iris/helpers/Float16.java @@ -0,0 +1,256 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package net.irisshaders.iris.helpers; + +/** + * Lifted from Apache Parquet MR project: + * https://github.com/apache/parquet-mr/blob/e87b80308869b77f914fcfd04364686e11158950/parquet-column/src/main/java/org/apache/parquet/schema/Float16.java + * + * + * + * The class is a utility class to manipulate half-precision 16-bit IEEE 754 floating + * point data types (also called fp16 or binary16). A half-precision float can be created from or + * converted to single-precision floats, and is stored in a short data type. The IEEE 754 standard + * specifies an float16 as having the following format: + * + * + * + *

The format is laid out as follows: + * + *

+ * 1   11111   1111111111
+ * ^   --^--   -----^----
+ * sign  |          |_______ significand
+ *       |
+ *      -- exponent
+ * 
+ * + * Half-precision floating points can be useful to save memory and/or bandwidth at the expense of + * range and precision when compared to single-precision floating points (float32). Ref: + * https://android.googlesource.com/platform/libcore/+/master/luni/src/main/java/libcore/util/FP16.java + */ +public class Float16 { + // Positive infinity of type half-precision float. + public static final short POSITIVE_INFINITY = (short) 0x7c00; + // A Not-a-Number representation of a half-precision float. + public static final short NaN = (short) 0x7e00; + // The bitmask to and a number with to obtain the sign bit. + private static final int SIGN_MASK = 0x8000; + // The offset to shift by to obtain the exponent bits. + private static final int EXPONENT_SHIFT = 10; + // The bitmask to and a number shifted by EXPONENT_SHIFT right, to obtain exponent bits. + private static final int SHIFTED_EXPONENT_MASK = 0x1f; + // The bitmask to and a number with to obtain significand bits. + private static final int SIGNIFICAND_MASK = 0x3ff; + // The offset of the exponent from the actual value. + private static final int EXPONENT_BIAS = 15; + // The offset to shift by to obtain the sign bit. + private static final int SIGN_SHIFT = 15; + // The bitmask to AND with to obtain exponent and significand bits. + private static final int EXPONENT_SIGNIFICAND_MASK = 0x7fff; + + private static final int FP32_SIGN_SHIFT = 31; + private static final int FP32_EXPONENT_SHIFT = 23; + private static final int FP32_SHIFTED_EXPONENT_MASK = 0xff; + private static final int FP32_SIGNIFICAND_MASK = 0x7fffff; + private static final int FP32_EXPONENT_BIAS = 127; + private static final int FP32_QNAN_MASK = 0x400000; + private static final int FP32_DENORMAL_MAGIC = 126 << 23; + private static final float FP32_DENORMAL_FLOAT = Float.intBitsToFloat(FP32_DENORMAL_MAGIC); + + /** + * Returns true if the specified half-precision float value represents a Not-a-Number, false + * otherwise. + * + * @param h A half-precision float value + * @return True if the value is a NaN, false otherwise + */ + public static boolean isNaN(short h) { + return (h & EXPONENT_SIGNIFICAND_MASK) > POSITIVE_INFINITY; + } + + /** + * Compares the two specified half-precision float values. The following conditions apply during + * the comparison: + * + * + * + * @param x The first half-precision float value to compare. + * @param y The second half-precision float value to compare + * @return The value {@code 0} if {@code x} is numerically equal to {@code y}, a value less than + * {@code 0} if {@code x} is numerically less than {@code y}, and a value greater than {@code + * 0} if {@code x} is numerically greater than {@code y} + */ + public static int compare(short x, short y) { + boolean xIsNaN = isNaN(x); + boolean yIsNaN = isNaN(y); + + if (!xIsNaN && !yIsNaN) { + int first = ((x & SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff); + int second = ((y & SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff); + // Returns true if the first half-precision float value is less + // (smaller toward negative infinity) than the second half-precision float value. + if (first < second) { + return -1; + } + + // Returns true if the first half-precision float value is greater + // (larger toward positive infinity) than the second half-precision float value. + if (first > second) { + return 1; + } + } + + // Collapse NaNs, akin to halfToIntBits(), but we want to keep + // (signed) short value types to preserve the ordering of -0.0 + // and +0.0 + short xBits = xIsNaN ? NaN : x; + short yBits = yIsNaN ? NaN : y; + return (xBits == yBits ? 0 : (xBits < yBits ? -1 : 1)); + } + + /** + * Converts the specified half-precision float value into a single-precision float value. The + * following special cases are handled: If the input is NaN, the returned value is Float NaN. If + * the input is POSITIVE_INFINITY or NEGATIVE_INFINITY, the returned value is respectively Float + * POSITIVE_INFINITY or Float NEGATIVE_INFINITY. If the input is 0 (positive or negative), the + * returned value is +/-0.0f. Otherwise, the returned value is a normalized single-precision float + * value. + * + * @param b The half-precision float value to convert to single-precision + * @return A normalized single-precision float value + */ + public static float toFloat(short b) { + int bits = b & 0xffff; + int s = bits & SIGN_MASK; + int e = (bits >>> EXPONENT_SHIFT) & SHIFTED_EXPONENT_MASK; + int m = bits & SIGNIFICAND_MASK; + int outE = 0; + int outM = 0; + if (e == 0) { // Denormal or 0 + if (m != 0) { + // Convert denorm fp16 into normalized fp32 + float o = Float.intBitsToFloat(FP32_DENORMAL_MAGIC + m); + o -= FP32_DENORMAL_FLOAT; + return s == 0 ? o : -o; + } + } else { + outM = m << 13; + if (e == 0x1f) { // Infinite or NaN + outE = 0xff; + if (outM != 0) { // SNaNs are quieted + outM |= FP32_QNAN_MASK; + } + } else { + outE = e - EXPONENT_BIAS + FP32_EXPONENT_BIAS; + } + } + int out = (s << 16) | (outE << FP32_EXPONENT_SHIFT) | outM; + return Float.intBitsToFloat(out); + } + + /** + * Converts the specified single-precision float value into a half-precision float value. The + * following special cases are handled: + * + *

If the input is NaN, the returned value is NaN. If the input is Float POSITIVE_INFINITY or + * Float NEGATIVE_INFINITY, the returned value is respectively POSITIVE_INFINITY or + * NEGATIVE_INFINITY. If the input is 0 (positive or negative), the returned value is + * POSITIVE_ZERO or NEGATIVE_ZERO. If the input is a less than MIN_VALUE, the returned value is + * flushed to POSITIVE_ZERO or NEGATIVE_ZERO. If the input is a less than MIN_NORMAL, the returned + * value is a denorm half-precision float. Otherwise, the returned value is rounded to the nearest + * representable half-precision float value. + * + * @param f The single-precision float value to convert to half-precision + * @return A half-precision float value + */ + public static short toFloat16(float f) { + int bits = Float.floatToRawIntBits(f); + int s = (bits >>> FP32_SIGN_SHIFT); + int e = (bits >>> FP32_EXPONENT_SHIFT) & FP32_SHIFTED_EXPONENT_MASK; + int m = bits & FP32_SIGNIFICAND_MASK; + int outE = 0; + int outM = 0; + if (e == 0xff) { // Infinite or NaN + outE = 0x1f; + outM = m != 0 ? 0x200 : 0; + } else { + e = e - FP32_EXPONENT_BIAS + EXPONENT_BIAS; + if (e >= 0x1f) { // Overflow + outE = 0x1f; + } else if (e <= 0) { // Underflow + if (e < -10) { + // The absolute fp32 value is less than MIN_VALUE, flush to +/-0 + } else { + // The fp32 value is a normalized float less than MIN_NORMAL, + // we convert to a denorm fp16 + m = m | 0x800000; + int shift = 14 - e; + outM = m >> shift; + int lowm = m & ((1 << shift) - 1); + int hway = 1 << (shift - 1); + // if above halfway or exactly halfway and outM is odd + if (lowm + (outM & 1) > hway) { + // Round to nearest even + // Can overflow into exponent bit, which surprisingly is OK. + // This increment relies on the +outM in the return statement below + outM++; + } + } + } else { + outE = e; + outM = m >> 13; + // if above halfway or exactly halfway and outM is odd + if ((m & 0x1fff) + (outM & 0x1) > 0x1000) { + // Round to nearest even + // Can overflow into exponent bit, which surprisingly is OK. + // This increment relies on the +outM in the return statement below + outM++; + } + } + } + // The outM is added here as the +1 increments for outM above can + // cause an overflow in the exponent bit which is OK. + return (short) ((s << SIGN_SHIFT) | (outE << EXPONENT_SHIFT) + outM); + } + + /** + * Returns a string representation of the specified half-precision float value. Calling this + * method is equivalent to calling Float.toString(toFloat(h)). See {@link + * Float#toString(float)} for more information on the format of the string representation. + * + * @param h A half-precision float value in binary little-endian format + * @return A string representation of the specified value + */ + public static String toFloatString(short h) { + return Float.toString(Float16.toFloat(h)); + } +} diff --git a/common/src/main/java/net/irisshaders/iris/mixin/MixinBakedQuad.java b/common/src/main/java/net/irisshaders/iris/mixin/MixinBakedQuad.java new file mode 100644 index 0000000000..420578989b --- /dev/null +++ b/common/src/main/java/net/irisshaders/iris/mixin/MixinBakedQuad.java @@ -0,0 +1,38 @@ +package net.irisshaders.iris.mixin; + +import net.irisshaders.iris.mixinterface.QuadPositionAccess; +import net.irisshaders.iris.pathways.EntityIdStorage; +import net.irisshaders.iris.pipeline.QuadPositions; +import net.minecraft.client.renderer.block.model.BakedQuad; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; + +@Mixin(BakedQuad.class) +public class MixinBakedQuad implements QuadPositionAccess { + private static final QuadPositions INVALID_VALUE = new QuadPositions(); + @Unique + private QuadPositions[] quadPositions = null; + + @Override + public QuadPositions getQuadPosition(int entityId) { + if (entityId == -1) return INVALID_VALUE; + + if (quadPositions == null) { + quadPositions = new QuadPositions[EntityIdStorage.ENTITY_ID_STORAGE.size()]; + } + + if (entityId >= quadPositions.length) { + QuadPositions[] newArray = new QuadPositions[EntityIdStorage.ENTITY_ID_STORAGE.size()]; + + System.arraycopy(quadPositions, 0, newArray, 0, quadPositions.length); + + this.quadPositions = newArray; + } + + if (quadPositions[entityId] == null) { + quadPositions[entityId] = new QuadPositions(); + } + + return quadPositions[entityId]; + } +} diff --git a/common/src/main/java/net/irisshaders/iris/mixin/MixinEntity.java b/common/src/main/java/net/irisshaders/iris/mixin/MixinEntity.java new file mode 100644 index 0000000000..b29cab05d6 --- /dev/null +++ b/common/src/main/java/net/irisshaders/iris/mixin/MixinEntity.java @@ -0,0 +1,41 @@ +package net.irisshaders.iris.mixin; + +import net.irisshaders.iris.mixinterface.EntityUniqueId; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +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 org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.BitSet; + +import static net.irisshaders.iris.pathways.EntityIdStorage.ENTITY_ID_STORAGE; + +@Mixin(Entity.class) +public abstract class MixinEntity implements EntityUniqueId { + @Unique + private int rollingId = -1; + + @Override + public int iris$getRollingId() { + if (rollingId == -1) { + int newId = ENTITY_ID_STORAGE.nextClearBit(0); + rollingId = newId; + ENTITY_ID_STORAGE.set(newId); + } + + return rollingId; + } + + @Inject(method = "setRemoved", at = @At("HEAD")) + private void iris$clearId(Entity.RemovalReason removalReason, CallbackInfo ci) { + if (rollingId == -1) return; + + ENTITY_ID_STORAGE.clear(rollingId); + rollingId = -1; + } +} diff --git a/common/src/main/java/net/irisshaders/iris/mixin/MixinModelCuboid.java b/common/src/main/java/net/irisshaders/iris/mixin/MixinModelCuboid.java new file mode 100644 index 0000000000..45063686e2 --- /dev/null +++ b/common/src/main/java/net/irisshaders/iris/mixin/MixinModelCuboid.java @@ -0,0 +1,34 @@ +package net.irisshaders.iris.mixin; + +import net.caffeinemc.mods.sodium.client.render.immediate.model.ModelCuboid; +import net.irisshaders.iris.mixinterface.ModelPartAccess; +import net.irisshaders.iris.pathways.EntityIdStorage; +import net.irisshaders.iris.pipeline.CubePositions; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; + +@Mixin(ModelCuboid.class) +public class MixinModelCuboid implements ModelPartAccess { + private static final CubePositions INVALID_VALUE = new CubePositions(); + @Unique + private CubePositions[] cubePositions = new CubePositions[EntityIdStorage.ENTITY_ID_STORAGE.size()]; + + @Override + public CubePositions getCubePosition(int entityId) { + if (entityId == -1) return INVALID_VALUE; + + if (entityId >= cubePositions.length) { + CubePositions[] newArray = new CubePositions[EntityIdStorage.ENTITY_ID_STORAGE.size()]; + + System.arraycopy(cubePositions, 0, newArray, 0, cubePositions.length); + + this.cubePositions = newArray; + } + + if (cubePositions[entityId] == null) { + cubePositions[entityId] = new CubePositions(); + } + + return cubePositions[entityId]; + } +} diff --git a/common/src/main/java/net/irisshaders/iris/mixin/MixinVertexFormatType.java b/common/src/main/java/net/irisshaders/iris/mixin/MixinVertexFormatType.java new file mode 100644 index 0000000000..33d9950c79 --- /dev/null +++ b/common/src/main/java/net/irisshaders/iris/mixin/MixinVertexFormatType.java @@ -0,0 +1,31 @@ +package net.irisshaders.iris.mixin; + +import com.mojang.blaze3d.shaders.Program; +import com.mojang.blaze3d.vertex.VertexFormatElement; +import net.irisshaders.iris.gl.program.IrisProgramTypes; +import net.irisshaders.iris.vertices.IrisFormatTypes; +import org.apache.commons.lang3.ArrayUtils; +import org.lwjgl.opengl.GL32C; +import org.lwjgl.opengl.GL42C; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(VertexFormatElement.Type.class) +public class MixinVertexFormatType { + @SuppressWarnings("target") + @Shadow + @Final + @Mutable + private static VertexFormatElement.Type[] $VALUES; + + static { + int baseOrdinal = $VALUES.length; + + IrisFormatTypes.HALF_FLOAT + = VertexTypeAccessor.createFormatType("HALF_FLOAT", baseOrdinal, 2, "Half Float", GL32C.GL_HALF_FLOAT); + + $VALUES = ArrayUtils.addAll($VALUES, IrisFormatTypes.HALF_FLOAT); + } +} diff --git a/common/src/main/java/net/irisshaders/iris/mixin/VertexTypeAccessor.java b/common/src/main/java/net/irisshaders/iris/mixin/VertexTypeAccessor.java new file mode 100644 index 0000000000..16c788e85c --- /dev/null +++ b/common/src/main/java/net/irisshaders/iris/mixin/VertexTypeAccessor.java @@ -0,0 +1,14 @@ +package net.irisshaders.iris.mixin; + +import com.mojang.blaze3d.shaders.Program; +import com.mojang.blaze3d.vertex.VertexFormatElement; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(VertexFormatElement.Type.class) +public interface VertexTypeAccessor { + @Invoker(value = "") + static VertexFormatElement.Type createFormatType(String name, int ordinal, int size, String name2, int glType) { + throw new AssertionError(); + } +} diff --git a/common/src/main/java/net/irisshaders/iris/mixin/entity_render_context/MixinEntityRenderDispatcher.java b/common/src/main/java/net/irisshaders/iris/mixin/entity_render_context/MixinEntityRenderDispatcher.java index b8e16e3ad4..33b6cbc721 100644 --- a/common/src/main/java/net/irisshaders/iris/mixin/entity_render_context/MixinEntityRenderDispatcher.java +++ b/common/src/main/java/net/irisshaders/iris/mixin/entity_render_context/MixinEntityRenderDispatcher.java @@ -5,6 +5,7 @@ import net.irisshaders.iris.layer.BufferSourceWrapper; import net.irisshaders.iris.layer.EntityRenderStateShard; import net.irisshaders.iris.layer.OuterWrappedRenderType; +import net.irisshaders.iris.mixinterface.EntityUniqueId; import net.irisshaders.iris.shaderpack.materialmap.NamespacedId; import net.irisshaders.iris.shaderpack.materialmap.WorldRenderingSettings; import net.irisshaders.iris.uniforms.CapturedRenderingState; @@ -15,6 +16,7 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.monster.ZombieVillager; +import net.minecraft.world.level.entity.EntityAccess; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -48,6 +50,7 @@ public class MixinEntityRenderDispatcher { } CapturedRenderingState.INSTANCE.setCurrentEntity(intId); + CapturedRenderingState.INSTANCE.setEntityRollingId(((EntityUniqueId) entity).iris$getRollingId()); return new BufferSourceWrapper(bufferSource, (renderType) -> OuterWrappedRenderType.wrapExactlyOnce("iris:entity", renderType, EntityRenderStateShard.INSTANCE)); } @@ -59,6 +62,7 @@ public class MixinEntityRenderDispatcher { PoseStack poseStack, MultiBufferSource bufferSource, int light, CallbackInfo ci) { CapturedRenderingState.INSTANCE.setCurrentEntity(0); + CapturedRenderingState.INSTANCE.setEntityRollingId(-1); CapturedRenderingState.INSTANCE.setCurrentRenderedItem(0); } } diff --git a/common/src/main/java/net/irisshaders/iris/mixin/vertices/MixinBufferBuilder.java b/common/src/main/java/net/irisshaders/iris/mixin/vertices/MixinBufferBuilder.java index 0ad4b56394..f42a3e5ee6 100644 --- a/common/src/main/java/net/irisshaders/iris/mixin/vertices/MixinBufferBuilder.java +++ b/common/src/main/java/net/irisshaders/iris/mixin/vertices/MixinBufferBuilder.java @@ -108,6 +108,11 @@ public abstract class MixinBufferBuilder implements VertexConsumer, BlockSensiti iris$isTerrain = false; injectNormalAndUV1 = false; return IrisVertexFormats.ENTITY; + } else if (format == DefaultVertexFormat.PARTICLE || format == IrisVertexFormats.PARTICLE) { + extending = true; + iris$isTerrain = false; + injectNormalAndUV1 = false; + return IrisVertexFormats.PARTICLE; } else if (format == DefaultVertexFormat.POSITION_COLOR_TEX_LIGHTMAP || format == IrisVertexFormats.GLYPH) { extending = true; iris$isTerrain = false; @@ -162,6 +167,9 @@ private void injectMidBlock(float x, float y, float z, CallbackInfoReturnable 3) { + // Reset it all. + currentX[index] = x; + currentY[index] = y; + currentZ[index] = z; + + velocityX[index] = 0; + velocityY[index] = 0; + velocityZ[index] = 0; + } + + this.lastFrameUpdate[index] = frame; + + velocityX[index] = x - currentX[index]; + velocityY[index] = y - currentY[index]; + velocityZ[index] = z - currentZ[index]; + + currentX[index] = x; + currentY[index] = y; + currentZ[index] = z; + } +} diff --git a/common/src/main/java/net/irisshaders/iris/pipeline/QuadPositions.java b/common/src/main/java/net/irisshaders/iris/pipeline/QuadPositions.java new file mode 100644 index 0000000000..0a68bb68fb --- /dev/null +++ b/common/src/main/java/net/irisshaders/iris/pipeline/QuadPositions.java @@ -0,0 +1,40 @@ +package net.irisshaders.iris.pipeline; + +import net.irisshaders.iris.shadows.ShadowRenderingState; + +public class QuadPositions { + public final float[] currentX = new float[4]; + public final float[] currentY = new float[4]; + public final float[] currentZ = new float[4]; + + public final float[] velocityX = new float[4]; + public final float[] velocityY = new float[4]; + public final float[] velocityZ = new float[4]; + + public int[] lastFrameUpdate = new int[4]; + + public void setAndUpdate(int frame, int index, float x, float y, float z) { + if (ShadowRenderingState.areShadowsCurrentlyBeingRendered() || frame == lastFrameUpdate[index]) return; + + if (frame - lastFrameUpdate[index] > 3) { + // Reset it all. + currentX[index] = x; + currentY[index] = y; + currentZ[index] = z; + + velocityX[index] = 0; + velocityY[index] = 0; + velocityZ[index] = 0; + } + + this.lastFrameUpdate[index] = frame; + + velocityX[index] = x - currentX[index]; + velocityY[index] = y - currentY[index]; + velocityZ[index] = z - currentZ[index]; + + currentX[index] = x; + currentY[index] = y; + currentZ[index] = z; + } +} diff --git a/common/src/main/java/net/irisshaders/iris/pipeline/programs/ShaderKey.java b/common/src/main/java/net/irisshaders/iris/pipeline/programs/ShaderKey.java index 06390f5420..2f0eff0ff2 100644 --- a/common/src/main/java/net/irisshaders/iris/pipeline/programs/ShaderKey.java +++ b/common/src/main/java/net/irisshaders/iris/pipeline/programs/ShaderKey.java @@ -48,9 +48,9 @@ public enum ShaderKey { LIGHTNING(ProgramId.Lightning, AlphaTests.OFF, DefaultVertexFormat.POSITION_COLOR, FogMode.PER_VERTEX, LightingModel.FULLBRIGHT), LEASH(ProgramId.Basic, AlphaTests.OFF, DefaultVertexFormat.POSITION_COLOR_LIGHTMAP, FogMode.PER_VERTEX, LightingModel.LIGHTMAP), TEXT_BG(ProgramId.EntitiesTrans, AlphaTests.ONE_TENTH_ALPHA, DefaultVertexFormat.POSITION_COLOR_LIGHTMAP, FogMode.PER_VERTEX, LightingModel.LIGHTMAP), - PARTICLES(ProgramId.Particles, AlphaTests.ONE_TENTH_ALPHA, DefaultVertexFormat.PARTICLE, FogMode.PER_VERTEX, LightingModel.LIGHTMAP), - PARTICLES_TRANS(ProgramId.ParticlesTrans, AlphaTests.ONE_TENTH_ALPHA, DefaultVertexFormat.PARTICLE, FogMode.PER_VERTEX, LightingModel.LIGHTMAP), - WEATHER(ProgramId.Weather, AlphaTests.ONE_TENTH_ALPHA, DefaultVertexFormat.PARTICLE, FogMode.PER_VERTEX, LightingModel.LIGHTMAP), + PARTICLES(ProgramId.Particles, AlphaTests.ONE_TENTH_ALPHA, IrisVertexFormats.PARTICLE, FogMode.PER_VERTEX, LightingModel.LIGHTMAP), + PARTICLES_TRANS(ProgramId.ParticlesTrans, AlphaTests.ONE_TENTH_ALPHA, IrisVertexFormats.PARTICLE, FogMode.PER_VERTEX, LightingModel.LIGHTMAP), + WEATHER(ProgramId.Weather, AlphaTests.ONE_TENTH_ALPHA, IrisVertexFormats.PARTICLE, FogMode.PER_VERTEX, LightingModel.LIGHTMAP), CRUMBLING(ProgramId.DamagedBlock, AlphaTests.ONE_TENTH_ALPHA, IrisVertexFormats.TERRAIN, FogMode.OFF, LightingModel.FULLBRIGHT), TEXT(ProgramId.EntitiesTrans, AlphaTests.ONE_TENTH_ALPHA, IrisVertexFormats.GLYPH, FogMode.PER_VERTEX, LightingModel.LIGHTMAP), TEXT_INTENSITY(ProgramId.EntitiesTrans, AlphaTests.ONE_TENTH_ALPHA, IrisVertexFormats.GLYPH, FogMode.PER_VERTEX, LightingModel.LIGHTMAP), @@ -80,7 +80,7 @@ public enum ShaderKey { SHADOW_LINES(ProgramId.Shadow, AlphaTests.OFF, DefaultVertexFormat.POSITION_COLOR_NORMAL, FogMode.OFF, LightingModel.LIGHTMAP), SHADOW_LEASH(ProgramId.Shadow, AlphaTests.OFF, DefaultVertexFormat.POSITION_COLOR_LIGHTMAP, FogMode.OFF, LightingModel.LIGHTMAP), SHADOW_LIGHTNING(ProgramId.ShadowLightning, AlphaTests.OFF, DefaultVertexFormat.POSITION_COLOR, FogMode.OFF, LightingModel.FULLBRIGHT), - SHADOW_PARTICLES(ProgramId.Shadow, AlphaTests.ONE_TENTH_ALPHA, DefaultVertexFormat.PARTICLE, FogMode.OFF, LightingModel.LIGHTMAP), + SHADOW_PARTICLES(ProgramId.Shadow, AlphaTests.ONE_TENTH_ALPHA, IrisVertexFormats.PARTICLE, FogMode.OFF, LightingModel.LIGHTMAP), SHADOW_TEXT(ProgramId.ShadowEntities, AlphaTests.NON_ZERO_ALPHA, IrisVertexFormats.GLYPH, FogMode.OFF, LightingModel.LIGHTMAP), SHADOW_TEXT_BG(ProgramId.ShadowEntities, AlphaTests.NON_ZERO_ALPHA, DefaultVertexFormat.POSITION_COLOR_LIGHTMAP, FogMode.OFF, LightingModel.LIGHTMAP), SHADOW_TEXT_INTENSITY(ProgramId.ShadowEntities, AlphaTests.NON_ZERO_ALPHA, IrisVertexFormats.GLYPH, FogMode.OFF, LightingModel.LIGHTMAP), diff --git a/common/src/main/java/net/irisshaders/iris/uniforms/CapturedRenderingState.java b/common/src/main/java/net/irisshaders/iris/uniforms/CapturedRenderingState.java index ec360239ec..a3c7bdca68 100644 --- a/common/src/main/java/net/irisshaders/iris/uniforms/CapturedRenderingState.java +++ b/common/src/main/java/net/irisshaders/iris/uniforms/CapturedRenderingState.java @@ -20,6 +20,7 @@ public class CapturedRenderingState { private int currentRenderedBlockEntity; private int currentRenderedEntity = -1; + private int rollingId = -1; private int currentRenderedItem = -1; private float currentAlphaTest; @@ -127,4 +128,12 @@ public float getCloudTime() { public void setCloudTime(float cloudTime) { this.cloudTime = cloudTime; } + + public void setEntityRollingId(int i) { + this.rollingId = i; + } + + public int getEntityRollingId() { + return this.rollingId; + } } diff --git a/common/src/main/java/net/irisshaders/iris/vertices/IrisFormatTypes.java b/common/src/main/java/net/irisshaders/iris/vertices/IrisFormatTypes.java new file mode 100644 index 0000000000..84228901b2 --- /dev/null +++ b/common/src/main/java/net/irisshaders/iris/vertices/IrisFormatTypes.java @@ -0,0 +1,7 @@ +package net.irisshaders.iris.vertices; + +import com.mojang.blaze3d.vertex.VertexFormatElement; + +public class IrisFormatTypes { + public static VertexFormatElement.Type HALF_FLOAT; +} diff --git a/common/src/main/java/net/irisshaders/iris/vertices/IrisVertexFormats.java b/common/src/main/java/net/irisshaders/iris/vertices/IrisVertexFormats.java index d17096b424..112009e177 100644 --- a/common/src/main/java/net/irisshaders/iris/vertices/IrisVertexFormats.java +++ b/common/src/main/java/net/irisshaders/iris/vertices/IrisVertexFormats.java @@ -10,9 +10,11 @@ public class IrisVertexFormats { public static final VertexFormatElement MID_TEXTURE_ELEMENT; public static final VertexFormatElement TANGENT_ELEMENT; public static final VertexFormatElement MID_BLOCK_ELEMENT; + public static final VertexFormatElement VELOCITY_ELEMENT; public static final VertexFormat TERRAIN; public static final VertexFormat ENTITY; + public static final VertexFormat PARTICLE; public static final VertexFormat GLYPH; public static final VertexFormat CLOUDS; @@ -22,6 +24,7 @@ public class IrisVertexFormats { MID_TEXTURE_ELEMENT = VertexFormatElement.register(12, 12, VertexFormatElement.Type.FLOAT, VertexFormatElement.Usage.GENERIC, 2); TANGENT_ELEMENT = VertexFormatElement.register(13, 13, VertexFormatElement.Type.BYTE, VertexFormatElement.Usage.GENERIC, 4); MID_BLOCK_ELEMENT = VertexFormatElement.register(14, 14, VertexFormatElement.Type.BYTE, VertexFormatElement.Usage.GENERIC, 3); + VELOCITY_ELEMENT = VertexFormatElement.register(15, 15, VertexFormatElement.Type.FLOAT, VertexFormatElement.Usage.GENERIC, 3); TERRAIN = VertexFormat.builder() .add("Position", VertexFormatElement.POSITION) @@ -37,6 +40,14 @@ public class IrisVertexFormats { .padding(1) .build(); + PARTICLE = VertexFormat.builder() + .add("Position", VertexFormatElement.POSITION) + .add("UV0", VertexFormatElement.UV0) + .add("Color", VertexFormatElement.COLOR) + .add("UV2", VertexFormatElement.UV2) + .add("at_velocity", VELOCITY_ELEMENT) + .build(); + ENTITY = VertexFormat.builder() .add("Position", VertexFormatElement.POSITION) .add("Color", VertexFormatElement.COLOR) @@ -48,6 +59,7 @@ public class IrisVertexFormats { .add("iris_Entity", ENTITY_ID_ELEMENT) .add("mc_midTexCoord", MID_TEXTURE_ELEMENT) .add("at_tangent", TANGENT_ELEMENT) + .add("at_velocity", VELOCITY_ELEMENT) .build(); GLYPH = VertexFormat.builder() @@ -69,6 +81,8 @@ public class IrisVertexFormats { .add("Normal", VertexFormatElement.NORMAL) .padding(1) .build(); + + debug(ENTITY); } private static void debug(VertexFormat format) { diff --git a/common/src/main/java/net/irisshaders/iris/vertices/sodium/IrisEntityVertex.java b/common/src/main/java/net/irisshaders/iris/vertices/sodium/IrisEntityVertex.java new file mode 100644 index 0000000000..11bfbcc1da --- /dev/null +++ b/common/src/main/java/net/irisshaders/iris/vertices/sodium/IrisEntityVertex.java @@ -0,0 +1,48 @@ +package net.irisshaders.iris.vertices.sodium; + +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.VertexFormat; +import com.mojang.blaze3d.vertex.VertexFormatElement; +import net.caffeinemc.mods.sodium.api.vertex.attributes.common.*; +import net.irisshaders.iris.uniforms.CapturedRenderingState; +import net.irisshaders.iris.vertices.IrisVertexFormats; +import org.lwjgl.system.MemoryUtil; + +public final class IrisEntityVertex { + public static final VertexFormat FORMAT = IrisVertexFormats.ENTITY; + + public static final int STRIDE = IrisVertexFormats.ENTITY.getVertexSize(); + + private static final int OFFSET_POSITION = 0; + private static final int OFFSET_COLOR = IrisVertexFormats.ENTITY.getOffset(VertexFormatElement.COLOR); + private static final int OFFSET_TEXTURE = IrisVertexFormats.ENTITY.getOffset(VertexFormatElement.UV0); + private static final int OFFSET_OVERLAY = IrisVertexFormats.ENTITY.getOffset(VertexFormatElement.UV1); + private static final int OFFSET_LIGHT = IrisVertexFormats.ENTITY.getOffset(VertexFormatElement.UV2); + private static final int OFFSET_NORMAL = IrisVertexFormats.ENTITY.getOffset(VertexFormatElement.NORMAL); + private static final int OFFSET_TANGENT = IrisVertexFormats.ENTITY.getOffset(IrisVertexFormats.TANGENT_ELEMENT); + private static final int OFFSET_MID_COORD = IrisVertexFormats.ENTITY.getOffset(IrisVertexFormats.MID_TEXTURE_ELEMENT); + private static final int OFFSET_ENTITY_ID = IrisVertexFormats.ENTITY.getOffset(IrisVertexFormats.ENTITY_ID_ELEMENT); + private static final int OFFSET_VELOCITY = IrisVertexFormats.ENTITY.getOffset(IrisVertexFormats.VELOCITY_ELEMENT); + + public static void write(long ptr, + float x, float y, float z, float velocityX, float velocityY, float velocityZ, int color, float u, float v, int overlay, int light, int normal, int tangent, + float midU, float midV) { + PositionAttribute.put(ptr + OFFSET_POSITION, x, y, z); + ColorAttribute.set(ptr + OFFSET_COLOR, color); + TextureAttribute.put(ptr + OFFSET_TEXTURE, u, v); + OverlayAttribute.set(ptr + OFFSET_OVERLAY, overlay); + LightAttribute.set(ptr + OFFSET_LIGHT, light); + NormalAttribute.set(ptr + OFFSET_NORMAL, normal); + + MemoryUtil.memPutInt(ptr + OFFSET_TANGENT, tangent); + MemoryUtil.memPutFloat(ptr + OFFSET_MID_COORD, midU); + MemoryUtil.memPutFloat(ptr + OFFSET_MID_COORD + 4, midV); + MemoryUtil.memPutShort(ptr + OFFSET_ENTITY_ID, (short) CapturedRenderingState.INSTANCE.getCurrentRenderedEntity()); + MemoryUtil.memPutShort(ptr + OFFSET_ENTITY_ID + 2, (short) CapturedRenderingState.INSTANCE.getCurrentRenderedBlockEntity()); + MemoryUtil.memPutShort(ptr + OFFSET_ENTITY_ID + 4, (short) CapturedRenderingState.INSTANCE.getCurrentRenderedItem()); + + MemoryUtil.memPutFloat(ptr + OFFSET_VELOCITY, velocityX); + MemoryUtil.memPutFloat(ptr + OFFSET_VELOCITY + 4, velocityY); + MemoryUtil.memPutFloat(ptr + OFFSET_VELOCITY + 8, velocityZ); + } +} diff --git a/common/src/main/java/net/irisshaders/iris/vertices/sodium/IrisParticleVertex.java b/common/src/main/java/net/irisshaders/iris/vertices/sodium/IrisParticleVertex.java new file mode 100644 index 0000000000..f3660f9ec0 --- /dev/null +++ b/common/src/main/java/net/irisshaders/iris/vertices/sodium/IrisParticleVertex.java @@ -0,0 +1,31 @@ +package net.irisshaders.iris.vertices.sodium; + +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.VertexFormat; +import com.mojang.blaze3d.vertex.VertexFormatElement; +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.attributes.common.TextureAttribute; +import net.irisshaders.iris.vertices.IrisVertexFormats; + +public final class IrisParticleVertex { + public static final VertexFormat FORMAT = IrisVertexFormats.PARTICLE; + + public static final int STRIDE = IrisVertexFormats.PARTICLE.getVertexSize(); + + private static final int OFFSET_POSITION = IrisVertexFormats.PARTICLE.getOffset(VertexFormatElement.POSITION); + private static final int OFFSET_TEXTURE = IrisVertexFormats.PARTICLE.getOffset(VertexFormatElement.UV0); + private static final int OFFSET_COLOR = IrisVertexFormats.PARTICLE.getOffset(VertexFormatElement.COLOR); + private static final int OFFSET_LIGHT = IrisVertexFormats.PARTICLE.getOffset(VertexFormatElement.UV2); + private static final int OFFSET_VELOCITY = IrisVertexFormats.PARTICLE.getOffset(IrisVertexFormats.VELOCITY_ELEMENT); + + public static void put(long ptr, + float x, float y, float z, float velX, float velY, float velZ, float u, float v, int color, int light) { + PositionAttribute.put(ptr + OFFSET_POSITION, x, y, z); + TextureAttribute.put(ptr + OFFSET_TEXTURE, u, v); + ColorAttribute.set(ptr + OFFSET_COLOR, color); + LightAttribute.set(ptr + OFFSET_LIGHT, light); + PositionAttribute.put(ptr + OFFSET_VELOCITY, velX, velY, velZ); + } +} diff --git a/common/src/main/resources/mixins.iris.compat.sodium.json b/common/src/main/resources/mixins.iris.compat.sodium.json index 27ffdb1688..dd0dea3692 100644 --- a/common/src/main/resources/mixins.iris.compat.sodium.json +++ b/common/src/main/resources/mixins.iris.compat.sodium.json @@ -5,17 +5,20 @@ "refmap": "iris.refmap.json", "compatibilityLevel": "JAVA_8", "client": [ + "MixinBakedModel", "MixinBlockRenderer", "MixinChunkBuildBuffers", "MixinChunkMeshBufferBuilder", "MixinChunkMeshBuildTask", "MixinCloudRenderer", "MixinDefaultChunkRenderer", + "MixinEntityRenderer", "MixinGlRenderDevice", "MixinRenderRegionArenas", "MixinRenderSectionManager", "MixinRenderSectionManagerShadow", "MixinShaderChunkRenderer", + "MixinSingleQuadParticle", "MixinSodiumGameOptionPages", "MixinSodiumGameOptions", "MixinSodiumOptionsGUI", diff --git a/common/src/main/resources/mixins.iris.json b/common/src/main/resources/mixins.iris.json index 79ff9c87eb..dcb268252a 100644 --- a/common/src/main/resources/mixins.iris.json +++ b/common/src/main/resources/mixins.iris.json @@ -21,6 +21,8 @@ "MixinClientLanguage", "MixinClientPacketListener", "MixinDebugScreenOverlay", + "MixinEntity", + "MixinModelCuboid", "MixinEntityRenderDispatcher", "MixinFogRenderer", "MixinGameRenderer", @@ -41,6 +43,7 @@ "MixinMinecraft_Images", "MixinMinecraft_Keybinds", "MixinMinecraft_PipelineManagement", + "MixinBakedQuad", "MixinModelViewBobbing", "MixinOptions_Entrypoint", "MixinParticleEngine", @@ -57,6 +60,8 @@ "MixinTitleScreen", "MixinUniform", "MixinVertexBuffer", + "MixinVertexFormatType", + "VertexTypeAccessor", "MixinWindow", "ProgramTypeAccessor", "entity_render_context.MixinBlockEntityRenderDispatcher", diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json index 5b7b0d5f21..378b3edeac 100644 --- a/fabric/src/main/resources/fabric.mod.json +++ b/fabric/src/main/resources/fabric.mod.json @@ -60,7 +60,8 @@ }, "custom": { "sodium:options": { - "mixin.features.render.world.sky": false + "mixin.features.render.world.sky": false, + "mixin.features.render.particle": false }, "mc-publish": { "loaders": [