From b24e87262b189cd568ba5fb4926851490f8d6604 Mon Sep 17 00:00:00 2001 From: PepperCode1 <44146161+PepperCode1@users.noreply.github.com> Date: Sat, 14 Sep 2024 22:37:48 -0700 Subject: [PATCH] Stackless - Store a pose matrix in each InstanceTree, equivalent to its instance's pose matrix if the instance exists - Directly transform the current InstanceTree's pose matrix instead of transforming a PoseStack and copying its matrix to the instance, eliminating the need to push and pop stack entries - Remove InstanceTree.rotation - Add more InstanceTree methods to allow full inspection of children --- .../flywheel/lib/instance/InstanceTypes.java | 4 +- .../flywheel/lib/instance/PosedInstance.java | 18 ++-- .../lib/instance/TransformedInstance.java | 17 ++-- .../flywheel/lib/model/part/InstanceTree.java | 97 +++++++++++++------ .../flywheel/lib/model/part/MeshTree.java | 22 ++--- .../flywheel/vanilla/ChestVisual.java | 11 ++- .../flywheel/vanilla/MinecartVisual.java | 2 +- .../flywheel/vanilla/ShulkerBoxVisual.java | 3 +- 8 files changed, 108 insertions(+), 66 deletions(-) diff --git a/common/src/lib/java/dev/engine_room/flywheel/lib/instance/InstanceTypes.java b/common/src/lib/java/dev/engine_room/flywheel/lib/instance/InstanceTypes.java index 433eb5445..ffb0d4f0a 100644 --- a/common/src/lib/java/dev/engine_room/flywheel/lib/instance/InstanceTypes.java +++ b/common/src/lib/java/dev/engine_room/flywheel/lib/instance/InstanceTypes.java @@ -25,7 +25,7 @@ public final class InstanceTypes { MemoryUtil.memPutByte(ptr + 3, instance.alpha); ExtraMemoryOps.put2x16(ptr + 4, instance.overlay); ExtraMemoryOps.put2x16(ptr + 8, instance.light); - ExtraMemoryOps.putMatrix4f(ptr + 12, instance.model); + ExtraMemoryOps.putMatrix4f(ptr + 12, instance.pose); }) .vertexShader(Flywheel.rl("instance/transformed.vert")) .cullShader(Flywheel.rl("instance/cull/transformed.glsl")) @@ -46,7 +46,7 @@ public final class InstanceTypes { MemoryUtil.memPutByte(ptr + 3, instance.alpha); ExtraMemoryOps.put2x16(ptr + 4, instance.overlay); ExtraMemoryOps.put2x16(ptr + 8, instance.light); - ExtraMemoryOps.putMatrix4f(ptr + 12, instance.model); + ExtraMemoryOps.putMatrix4f(ptr + 12, instance.pose); ExtraMemoryOps.putMatrix3f(ptr + 76, instance.normal); }) .vertexShader(Flywheel.rl("instance/posed.vert")) diff --git a/common/src/lib/java/dev/engine_room/flywheel/lib/instance/PosedInstance.java b/common/src/lib/java/dev/engine_room/flywheel/lib/instance/PosedInstance.java index d21b5e17f..365450acf 100644 --- a/common/src/lib/java/dev/engine_room/flywheel/lib/instance/PosedInstance.java +++ b/common/src/lib/java/dev/engine_room/flywheel/lib/instance/PosedInstance.java @@ -14,7 +14,7 @@ import net.minecraft.util.Mth; public class PosedInstance extends ColoredLitInstance implements Transform { - public final Matrix4f model = new Matrix4f(); + public final Matrix4f pose = new Matrix4f(); public final Matrix3f normal = new Matrix3f(); public PosedInstance(InstanceType type, InstanceHandle handle) { @@ -23,7 +23,7 @@ public PosedInstance(InstanceType type, InstanceHandle @Override public PosedInstance mulPose(Matrix4fc pose) { - this.model.mul(pose); + this.pose.mul(pose); return this; } @@ -35,27 +35,27 @@ public PosedInstance mulNormal(Matrix3fc normal) { @Override public PosedInstance rotateAround(Quaternionfc quaternion, float x, float y, float z) { - model.rotateAround(quaternion, x, y, z); + pose.rotateAround(quaternion, x, y, z); normal.rotate(quaternion); return this; } @Override public PosedInstance translate(float x, float y, float z) { - model.translate(x, y, z); + pose.translate(x, y, z); return this; } @Override public PosedInstance rotate(Quaternionfc quaternion) { - model.rotate(quaternion); + pose.rotate(quaternion); normal.rotate(quaternion); return this; } @Override public PosedInstance scale(float x, float y, float z) { - model.scale(x, y, z); + pose.scale(x, y, z); if (x == y && y == z) { if (x < 0.0f) { @@ -74,7 +74,7 @@ public PosedInstance scale(float x, float y, float z) { } public PosedInstance setTransform(PoseStack.Pose pose) { - model.set(pose.pose()); + this.pose.set(pose.pose()); normal.set(pose.normal()); return this; } @@ -84,7 +84,7 @@ public PosedInstance setTransform(PoseStack stack) { } public PosedInstance setIdentityTransform() { - model.identity(); + pose.identity(); normal.identity(); return this; } @@ -97,7 +97,7 @@ public PosedInstance setIdentityTransform() { *

*/ public PosedInstance setZeroTransform() { - model.zero(); + pose.zero(); normal.zero(); return this; } diff --git a/common/src/lib/java/dev/engine_room/flywheel/lib/instance/TransformedInstance.java b/common/src/lib/java/dev/engine_room/flywheel/lib/instance/TransformedInstance.java index 73e57e4d0..70a382c5b 100644 --- a/common/src/lib/java/dev/engine_room/flywheel/lib/instance/TransformedInstance.java +++ b/common/src/lib/java/dev/engine_room/flywheel/lib/instance/TransformedInstance.java @@ -9,9 +9,8 @@ import dev.engine_room.flywheel.api.instance.InstanceType; import dev.engine_room.flywheel.lib.transform.Affine; - public class TransformedInstance extends ColoredLitInstance implements Affine { - public final Matrix4f model = new Matrix4f(); + public final Matrix4f pose = new Matrix4f(); public TransformedInstance(InstanceType type, InstanceHandle handle) { super(type, handle); @@ -19,30 +18,30 @@ public TransformedInstance(InstanceType type, Ins @Override public TransformedInstance rotateAround(Quaternionfc quaternion, float x, float y, float z) { - model.rotateAround(quaternion, x, y, z); + pose.rotateAround(quaternion, x, y, z); return this; } @Override public TransformedInstance translate(float x, float y, float z) { - model.translate(x, y, z); + pose.translate(x, y, z); return this; } @Override public TransformedInstance rotate(Quaternionfc quaternion) { - model.rotate(quaternion); + pose.rotate(quaternion); return this; } @Override public TransformedInstance scale(float x, float y, float z) { - model.scale(x, y, z); + pose.scale(x, y, z); return this; } public TransformedInstance setTransform(PoseStack.Pose pose) { - model.set(pose.pose()); + this.pose.set(pose.pose()); return this; } @@ -51,7 +50,7 @@ public TransformedInstance setTransform(PoseStack stack) { } public TransformedInstance setIdentityTransform() { - model.identity(); + pose.identity(); return this; } @@ -63,7 +62,7 @@ public TransformedInstance setIdentityTransform() { *

*/ public TransformedInstance setZeroTransform() { - model.zero(); + pose.zero(); return this; } } diff --git a/common/src/lib/java/dev/engine_room/flywheel/lib/model/part/InstanceTree.java b/common/src/lib/java/dev/engine_room/flywheel/lib/model/part/InstanceTree.java index cf8f22037..7f15dec1c 100644 --- a/common/src/lib/java/dev/engine_room/flywheel/lib/model/part/InstanceTree.java +++ b/common/src/lib/java/dev/engine_room/flywheel/lib/model/part/InstanceTree.java @@ -7,7 +7,8 @@ import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; -import org.jetbrains.annotations.Unmodifiable; +import org.joml.Matrix4f; +import org.joml.Matrix4fc; import org.joml.Quaternionf; import org.joml.Vector3fc; @@ -21,6 +22,8 @@ import dev.engine_room.flywheel.lib.instance.TransformedInstance; import dev.engine_room.flywheel.lib.model.ModelCache; import dev.engine_room.flywheel.lib.model.SingleMeshModel; +import dev.engine_room.flywheel.lib.transform.Affine; +import dev.engine_room.flywheel.lib.transform.TransformStack; import net.minecraft.client.model.geom.ModelLayerLocation; import net.minecraft.client.model.geom.ModelPart; import net.minecraft.client.model.geom.PartPose; @@ -32,10 +35,9 @@ public final class InstanceTree { @Nullable private final TransformedInstance instance; private final PartPose initialPose; - @Unmodifiable private final InstanceTree[] children; - private final Quaternionf rotation = new Quaternionf(); + private final Matrix4f poseMatrix; public float x; public float y; @@ -46,7 +48,9 @@ public final class InstanceTree { public float xScale; public float yScale; public float zScale; + @ApiStatus.Experimental public boolean visible = true; + @ApiStatus.Experimental public boolean skipDraw; private InstanceTree(MeshTree source, @Nullable TransformedInstance instance, PartPose initialPose, InstanceTree[] children) { @@ -54,6 +58,13 @@ private InstanceTree(MeshTree source, @Nullable TransformedInstance instance, Pa this.instance = instance; this.initialPose = initialPose; this.children = children; + + if (instance != null) { + poseMatrix = instance.pose; + } else { + poseMatrix = new Matrix4f(); + } + resetPose(); } @@ -64,8 +75,7 @@ private static InstanceTree create(InstancerProvider provider, MeshTree meshTree for (int i = 0; i < meshTree.childCount(); i++) { var meshTreeChild = meshTree.child(i); String name = meshTree.childName(i); - children[i] = InstanceTree.create(provider, meshTreeChild, meshFinalizerFunc, pathSlash + name); - + children[i] = create(provider, meshTreeChild, meshFinalizerFunc, pathSlash + name); } Mesh mesh = meshTree.mesh(); @@ -106,17 +116,35 @@ public PartPose initialPose() { return initialPose; } - @Nullable + public int childCount() { + return children.length; + } + public InstanceTree child(int index) { - if (index < 0 || index >= children.length) { - return null; - } return children[index]; } + public String childName(int index) { + return source.childName(index); + } + + public int childIndex(String name) { + return source.childIndex(name); + } + + public boolean hasChild(String name) { + return childIndex(name) >= 0; + } + @Nullable public InstanceTree child(String name) { - return child(source.childIndex(name)); + int index = childIndex(name); + + if (index < 0) { + return null; + } + + return child(index); } public InstanceTree childOrThrow(String name) { @@ -158,35 +186,48 @@ public void traverse(int i, int j, ObjIntIntConsumer affine, Quaternionf tempQuaternion) { + affine.translate(x / 16.0F, y / 16.0F, z / 16.0F); if (xRot != 0.0F || yRot != 0.0F || zRot != 0.0F) { - poseStack.mulPose(rotation.rotationZYX(zRot, yRot, xRot)); + affine.rotate(tempQuaternion.rotationZYX(zRot, yRot, xRot)); } if (xScale != 1.0F || yScale != 1.0F || zScale != 1.0F) { - poseStack.scale(xScale, yScale, zScale); + affine.scale(xScale, yScale, zScale); } } - public void updateInstances(PoseStack poseStack) { - if (visible) { - poseStack.pushPose(); - translateAndRotate(poseStack); + public void translateAndRotate(PoseStack poseStack, Quaternionf tempQuaternion) { + translateAndRotate(TransformStack.of(poseStack), tempQuaternion); + } - if (instance != null && !skipDraw) { - instance.setTransform(poseStack.last()) - .setChanged(); - } + public void translateAndRotate(Matrix4f pose) { + pose.translate(x / 16.0F, y / 16.0F, z / 16.0F); - // Use the bare HashMap.forEach because .values() always allocates a new collection. - // We also don't want to store an array of children because that would statically use a lot more memory. - for (InstanceTree child : children) { - child.updateInstances(poseStack); - } + if (xRot != 0.0F || yRot != 0.0F || zRot != 0.0F) { + pose.rotateZYX(zRot, yRot, xRot); + } - poseStack.popPose(); + if (xScale != ModelPart.DEFAULT_SCALE || yScale != ModelPart.DEFAULT_SCALE || zScale != ModelPart.DEFAULT_SCALE) { + pose.scale(xScale, yScale, zScale); + } + } + + public void updateInstances(Matrix4fc initialPose) { + if (!visible) { + return; + } + + poseMatrix.set(initialPose); + translateAndRotate(poseMatrix); + + if (instance != null && !skipDraw) { + instance.setChanged(); + } + + for (InstanceTree child : children) { + child.updateInstances(poseMatrix); } } diff --git a/common/src/lib/java/dev/engine_room/flywheel/lib/model/part/MeshTree.java b/common/src/lib/java/dev/engine_room/flywheel/lib/model/part/MeshTree.java index 60c0e8eba..6ec94921e 100644 --- a/common/src/lib/java/dev/engine_room/flywheel/lib/model/part/MeshTree.java +++ b/common/src/lib/java/dev/engine_room/flywheel/lib/model/part/MeshTree.java @@ -34,13 +34,13 @@ public final class MeshTree { private final Mesh mesh; private final PartPose initialPose; private final MeshTree[] children; - private final String[] childKeys; + private final String[] childNames; - private MeshTree(@Nullable Mesh mesh, PartPose initialPose, MeshTree[] children, String[] childKeys) { + private MeshTree(@Nullable Mesh mesh, PartPose initialPose, MeshTree[] children, String[] childNames) { this.mesh = mesh; this.initialPose = initialPose; - this.childKeys = childKeys; this.children = children; + this.childNames = childNames; } public static MeshTree of(ModelLayerLocation layer) { @@ -59,15 +59,15 @@ private static MeshTree convert(ModelPart modelPart, ThreadLocalObjects objects) var modelPartChildren = FlwLibLink.INSTANCE.getModelPartChildren(modelPart); // Freeze the ordering here. Maybe we want to sort this? - String[] childKeys = modelPartChildren.keySet() - .toArray(new String[0]); + String[] childNames = modelPartChildren.keySet() + .toArray(String[]::new); - MeshTree[] children = new MeshTree[modelPartChildren.size()]; - for (int i = 0; i < childKeys.length; i++) { - children[i] = convert(modelPartChildren.get(childKeys[i]), objects); + MeshTree[] children = new MeshTree[childNames.length]; + for (int i = 0; i < childNames.length; i++) { + children[i] = convert(modelPartChildren.get(childNames[i]), objects); } - return new MeshTree(compile(modelPart, objects), modelPart.getInitialPose(), children, childKeys); + return new MeshTree(compile(modelPart, objects), modelPart.getInitialPose(), children, childNames); } @Nullable @@ -103,11 +103,11 @@ public MeshTree child(int index) { } public String childName(int index) { - return childKeys[index]; + return childNames[index]; } public int childIndex(String name) { - return Arrays.binarySearch(childKeys, name); + return Arrays.binarySearch(childNames, name); } public boolean hasChild(String name) { diff --git a/common/src/main/java/dev/engine_room/flywheel/vanilla/ChestVisual.java b/common/src/main/java/dev/engine_room/flywheel/vanilla/ChestVisual.java index 9025f5d0a..7953d549e 100644 --- a/common/src/main/java/dev/engine_room/flywheel/vanilla/ChestVisual.java +++ b/common/src/main/java/dev/engine_room/flywheel/vanilla/ChestVisual.java @@ -6,6 +6,7 @@ import java.util.function.Consumer; import org.jetbrains.annotations.Nullable; +import org.joml.Matrix4fc; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Axis; @@ -18,7 +19,6 @@ import dev.engine_room.flywheel.lib.model.RetexturedMesh; import dev.engine_room.flywheel.lib.model.part.InstanceTree; import dev.engine_room.flywheel.lib.transform.TransformStack; -import dev.engine_room.flywheel.lib.util.RecyclingPoseStack; import dev.engine_room.flywheel.lib.visual.AbstractBlockEntityVisual; import dev.engine_room.flywheel.lib.visual.SimpleDynamicVisual; import it.unimi.dsi.fastutil.floats.Float2FloatFunction; @@ -60,7 +60,8 @@ public class ChestVisual extends Abstrac @Nullable private final InstanceTree lock; - private final PoseStack poseStack = new RecyclingPoseStack(); + @Nullable + private final Matrix4fc initialPose; private final BrightnessCombiner brightnessCombiner = new BrightnessCombiner(); @Nullable private final DoubleBlockCombiner.NeighborCombineResult neighborCombineResult; @@ -83,12 +84,13 @@ public ChestVisual(VisualizationContext ctx, T blockEntity, float partialTick) { lid = instances.childOrThrow("lid"); lock = instances.childOrThrow("lock"); - poseStack.pushPose(); + PoseStack poseStack = new PoseStack(); TransformStack.of(poseStack).translate(getVisualPosition()); float horizontalAngle = blockState.getValue(ChestBlock.FACING).toYRot(); poseStack.translate(0.5F, 0.5F, 0.5F); poseStack.mulPose(Axis.YP.rotationDegrees(-horizontalAngle)); poseStack.translate(-0.5F, -0.5F, -0.5F); + initialPose = poseStack.last().pose(); neighborCombineResult = chestBlock.combine(blockState, level, pos, true); lidProgress = neighborCombineResult.apply(ChestBlock.opennessCombiner(blockEntity)); @@ -99,6 +101,7 @@ public ChestVisual(VisualizationContext ctx, T blockEntity, float partialTick) { instances = null; lid = null; lock = null; + initialPose = null; neighborCombineResult = null; lidProgress = null; } @@ -145,7 +148,7 @@ private void applyLidTransform(float progress) { lid.xRot = -(progress * ((float) Math.PI / 2F)); lock.xRot = lid.xRot; - instances.updateInstances(poseStack); + instances.updateInstances(initialPose); } @Override diff --git a/common/src/main/java/dev/engine_room/flywheel/vanilla/MinecartVisual.java b/common/src/main/java/dev/engine_room/flywheel/vanilla/MinecartVisual.java index 0ba3efc60..50f8f0341 100644 --- a/common/src/main/java/dev/engine_room/flywheel/vanilla/MinecartVisual.java +++ b/common/src/main/java/dev/engine_room/flywheel/vanilla/MinecartVisual.java @@ -53,7 +53,7 @@ public class MinecartVisual extends ComponentEntityV private final ModelHolder bodyModel; - private final PoseStack stack = new RecyclingPoseStack(); + private final RecyclingPoseStack stack = new RecyclingPoseStack(); private BlockState blockState; private boolean active; diff --git a/common/src/main/java/dev/engine_room/flywheel/vanilla/ShulkerBoxVisual.java b/common/src/main/java/dev/engine_room/flywheel/vanilla/ShulkerBoxVisual.java index 084c5fb03..7e1a2f538 100644 --- a/common/src/main/java/dev/engine_room/flywheel/vanilla/ShulkerBoxVisual.java +++ b/common/src/main/java/dev/engine_room/flywheel/vanilla/ShulkerBoxVisual.java @@ -4,7 +4,6 @@ import org.joml.Quaternionf; -import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Axis; import dev.engine_room.flywheel.api.instance.Instance; @@ -46,7 +45,7 @@ public class ShulkerBoxVisual extends AbstractBlockEntityVisual