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 extends PosedInstance> type, InstanceHandle handle) {
@@ -23,7 +23,7 @@ public PosedInstance(InstanceType extends PosedInstance> 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 extends TransformedInstance> type, InstanceHandle handle) {
super(type, handle);
@@ -19,30 +18,30 @@ public TransformedInstance(InstanceType extends TransformedInstance> 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 super TransformedInstance
}
}
- public void translateAndRotate(PoseStack poseStack) {
- poseStack.translate(x / 16.0F, y / 16.0F, z / 16.0F);
+ public void translateAndRotate(Affine> 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 extends ChestBlockEntity> 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