mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2024-12-26 15:06:28 +01:00
Shiver me timbers
- Use arrrays in the trees - MeshTree tracks parallel arrays of children and keys - InstanceTree tracks which mesh tree it came from for lookup purposes - Remove walker object - Make RecyclingPoseStack use add/removeLast instead of push/pop
This commit is contained in:
parent
5ffddeb221
commit
6f2b8fd3fb
3 changed files with 67 additions and 64 deletions
|
@ -1,10 +1,6 @@
|
||||||
package dev.engine_room.flywheel.lib.model.part;
|
package dev.engine_room.flywheel.lib.model.part;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
import java.util.function.BiConsumer;
|
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.ObjIntConsumer;
|
import java.util.function.ObjIntConsumer;
|
||||||
|
@ -32,11 +28,12 @@ import net.minecraft.client.model.geom.PartPose;
|
||||||
public final class InstanceTree {
|
public final class InstanceTree {
|
||||||
private static final ModelCache<Model.ConfiguredMesh> MODEL_CACHE = new ModelCache<>(entry -> new SingleMeshModel(entry.mesh(), entry.material()));
|
private static final ModelCache<Model.ConfiguredMesh> MODEL_CACHE = new ModelCache<>(entry -> new SingleMeshModel(entry.mesh(), entry.material()));
|
||||||
|
|
||||||
|
private final MeshTree source;
|
||||||
@Nullable
|
@Nullable
|
||||||
private final TransformedInstance instance;
|
private final TransformedInstance instance;
|
||||||
private final PartPose initialPose;
|
private final PartPose initialPose;
|
||||||
@Unmodifiable
|
@Unmodifiable
|
||||||
private final Map<String, InstanceTree> children;
|
private final InstanceTree[] children;
|
||||||
|
|
||||||
private final Quaternionf rotation = new Quaternionf();
|
private final Quaternionf rotation = new Quaternionf();
|
||||||
|
|
||||||
|
@ -52,7 +49,8 @@ public final class InstanceTree {
|
||||||
public boolean visible = true;
|
public boolean visible = true;
|
||||||
public boolean skipDraw;
|
public boolean skipDraw;
|
||||||
|
|
||||||
private InstanceTree(@Nullable TransformedInstance instance, PartPose initialPose, @Unmodifiable Map<String, InstanceTree> children) {
|
private InstanceTree(MeshTree source, @Nullable TransformedInstance instance, PartPose initialPose, InstanceTree[] children) {
|
||||||
|
this.source = source;
|
||||||
this.instance = instance;
|
this.instance = instance;
|
||||||
this.initialPose = initialPose;
|
this.initialPose = initialPose;
|
||||||
this.children = children;
|
this.children = children;
|
||||||
|
@ -60,12 +58,15 @@ public final class InstanceTree {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static InstanceTree create(InstancerProvider provider, MeshTree meshTree, BiFunction<String, Mesh, Model.ConfiguredMesh> meshFinalizerFunc, String path) {
|
private static InstanceTree create(InstancerProvider provider, MeshTree meshTree, BiFunction<String, Mesh, Model.ConfiguredMesh> meshFinalizerFunc, String path) {
|
||||||
Map<String, InstanceTree> children = new HashMap<>();
|
InstanceTree[] children = new InstanceTree[meshTree.childCount()];
|
||||||
String pathSlash = path + "/";
|
String pathSlash = path + "/";
|
||||||
|
|
||||||
meshTree.children().forEach((name, meshTreeChild) -> {
|
for (int i = 0; i < meshTree.childCount(); i++) {
|
||||||
children.put(name, InstanceTree.create(provider, meshTreeChild, meshFinalizerFunc, pathSlash + name));
|
var meshTreeChild = meshTree.child(i);
|
||||||
});
|
String name = meshTree.childName(i);
|
||||||
|
children[i] = InstanceTree.create(provider, meshTreeChild, meshFinalizerFunc, pathSlash + name);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
Mesh mesh = meshTree.mesh();
|
Mesh mesh = meshTree.mesh();
|
||||||
TransformedInstance instance;
|
TransformedInstance instance;
|
||||||
|
@ -77,7 +78,7 @@ public final class InstanceTree {
|
||||||
instance = null;
|
instance = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new InstanceTree(instance, meshTree.initialPose(), Collections.unmodifiableMap(children));
|
return new InstanceTree(meshTree, instance, meshTree.initialPose(), children);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static InstanceTree create(InstancerProvider provider, MeshTree meshTree, BiFunction<String, Mesh, Model.ConfiguredMesh> meshFinalizerFunc) {
|
public static InstanceTree create(InstancerProvider provider, MeshTree meshTree, BiFunction<String, Mesh, Model.ConfiguredMesh> meshFinalizerFunc) {
|
||||||
|
@ -105,18 +106,17 @@ public final class InstanceTree {
|
||||||
return initialPose;
|
return initialPose;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Unmodifiable
|
@Nullable
|
||||||
public Map<String, InstanceTree> children() {
|
public InstanceTree child(int index) {
|
||||||
return children;
|
if (index < 0 || index >= children.length) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
return children[index];
|
||||||
public boolean hasChild(String name) {
|
|
||||||
return children.containsKey(name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public InstanceTree child(String name) {
|
public InstanceTree child(String name) {
|
||||||
return children.get(name);
|
return child(source.childIndex(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
public InstanceTree childOrThrow(String name) {
|
public InstanceTree childOrThrow(String name) {
|
||||||
|
@ -133,7 +133,7 @@ public final class InstanceTree {
|
||||||
if (instance != null) {
|
if (instance != null) {
|
||||||
consumer.accept(instance);
|
consumer.accept(instance);
|
||||||
}
|
}
|
||||||
for (InstanceTree child : children.values()) {
|
for (InstanceTree child : children) {
|
||||||
child.traverse(consumer);
|
child.traverse(consumer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -143,7 +143,7 @@ public final class InstanceTree {
|
||||||
if (instance != null) {
|
if (instance != null) {
|
||||||
consumer.accept(instance, i);
|
consumer.accept(instance, i);
|
||||||
}
|
}
|
||||||
for (InstanceTree child : children.values()) {
|
for (InstanceTree child : children) {
|
||||||
child.traverse(i, consumer);
|
child.traverse(i, consumer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -153,7 +153,7 @@ public final class InstanceTree {
|
||||||
if (instance != null) {
|
if (instance != null) {
|
||||||
consumer.accept(instance, i, j);
|
consumer.accept(instance, i, j);
|
||||||
}
|
}
|
||||||
for (InstanceTree child : children.values()) {
|
for (InstanceTree child : children) {
|
||||||
child.traverse(i, j, consumer);
|
child.traverse(i, j, consumer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -171,16 +171,6 @@ public final class InstanceTree {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateInstances(PoseStack poseStack) {
|
public void updateInstances(PoseStack poseStack) {
|
||||||
// Need to use an anonymous class so it can reference this.
|
|
||||||
updateInstancesInner(poseStack, new Walker() {
|
|
||||||
@Override
|
|
||||||
public void accept(InstanceTree child) {
|
|
||||||
child.updateInstancesInner(poseStack, this);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateInstancesInner(PoseStack poseStack, Walker walker) {
|
|
||||||
if (visible) {
|
if (visible) {
|
||||||
poseStack.pushPose();
|
poseStack.pushPose();
|
||||||
translateAndRotate(poseStack);
|
translateAndRotate(poseStack);
|
||||||
|
@ -192,7 +182,9 @@ public final class InstanceTree {
|
||||||
|
|
||||||
// Use the bare HashMap.forEach because .values() always allocates a new collection.
|
// 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.
|
// We also don't want to store an array of children because that would statically use a lot more memory.
|
||||||
children.forEach(walker);
|
for (InstanceTree child : children) {
|
||||||
|
child.updateInstances(poseStack);
|
||||||
|
}
|
||||||
|
|
||||||
poseStack.popPose();
|
poseStack.popPose();
|
||||||
}
|
}
|
||||||
|
@ -294,8 +286,9 @@ public final class InstanceTree {
|
||||||
if (instance != null) {
|
if (instance != null) {
|
||||||
instance.delete();
|
instance.delete();
|
||||||
}
|
}
|
||||||
children.values()
|
for (InstanceTree child : children) {
|
||||||
.forEach(InstanceTree::delete);
|
child.delete();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiStatus.Experimental
|
@ApiStatus.Experimental
|
||||||
|
@ -303,14 +296,4 @@ public final class InstanceTree {
|
||||||
public interface ObjIntIntConsumer<T> {
|
public interface ObjIntIntConsumer<T> {
|
||||||
void accept(T t, int i, int j);
|
void accept(T t, int i, int j);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper interface for writing walking classes.
|
|
||||||
private interface Walker extends BiConsumer<String, InstanceTree> {
|
|
||||||
void accept(InstanceTree child);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
default void accept(String name, InstanceTree child) {
|
|
||||||
accept(child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package dev.engine_room.flywheel.lib.model.part;
|
package dev.engine_room.flywheel.lib.model.part;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
@ -9,7 +8,6 @@ import java.util.function.Consumer;
|
||||||
|
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.annotations.Unmodifiable;
|
|
||||||
|
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
|
||||||
|
@ -35,12 +33,13 @@ public final class MeshTree {
|
||||||
@Nullable
|
@Nullable
|
||||||
private final Mesh mesh;
|
private final Mesh mesh;
|
||||||
private final PartPose initialPose;
|
private final PartPose initialPose;
|
||||||
@Unmodifiable
|
private final MeshTree[] children;
|
||||||
private final Map<String, MeshTree> children;
|
private final String[] childKeys;
|
||||||
|
|
||||||
private MeshTree(@Nullable Mesh mesh, PartPose initialPose, @Unmodifiable Map<String, MeshTree> children) {
|
private MeshTree(@Nullable Mesh mesh, PartPose initialPose, MeshTree[] children, String[] childKeys) {
|
||||||
this.mesh = mesh;
|
this.mesh = mesh;
|
||||||
this.initialPose = initialPose;
|
this.initialPose = initialPose;
|
||||||
|
this.childKeys = childKeys;
|
||||||
this.children = children;
|
this.children = children;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,13 +57,17 @@ public final class MeshTree {
|
||||||
|
|
||||||
private static MeshTree convert(ModelPart modelPart, ThreadLocalObjects objects) {
|
private static MeshTree convert(ModelPart modelPart, ThreadLocalObjects objects) {
|
||||||
var modelPartChildren = FlwLibLink.INSTANCE.getModelPartChildren(modelPart);
|
var modelPartChildren = FlwLibLink.INSTANCE.getModelPartChildren(modelPart);
|
||||||
Map<String, MeshTree> children = new HashMap<>();
|
|
||||||
|
|
||||||
modelPartChildren.forEach((name, modelPartChild) -> {
|
// Freeze the ordering here. Maybe we want to sort this?
|
||||||
children.put(name, convert(modelPartChild, objects));
|
String[] childKeys = modelPartChildren.keySet()
|
||||||
});
|
.toArray(new String[0]);
|
||||||
|
|
||||||
return new MeshTree(compile(modelPart, objects), modelPart.getInitialPose(), Collections.unmodifiableMap(children));
|
MeshTree[] children = new MeshTree[modelPartChildren.size()];
|
||||||
|
for (int i = 0; i < childKeys.length; i++) {
|
||||||
|
children[i] = convert(modelPartChildren.get(childKeys[i]), objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new MeshTree(compile(modelPart, objects), modelPart.getInitialPose(), children, childKeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
@ -91,18 +94,35 @@ public final class MeshTree {
|
||||||
return initialPose;
|
return initialPose;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Unmodifiable
|
public int childCount() {
|
||||||
public Map<String, MeshTree> children() {
|
return children.length;
|
||||||
return children;
|
}
|
||||||
|
|
||||||
|
public MeshTree child(int index) {
|
||||||
|
return children[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
public String childName(int index) {
|
||||||
|
return childKeys[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int childIndex(String name) {
|
||||||
|
return Arrays.binarySearch(childKeys, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasChild(String name) {
|
public boolean hasChild(String name) {
|
||||||
return children.containsKey(name);
|
return childIndex(name) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public MeshTree child(String name) {
|
public MeshTree child(String name) {
|
||||||
return children.get(name);
|
int index = childIndex(name);
|
||||||
|
|
||||||
|
if (index < 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return child(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MeshTree childOrThrow(String name) {
|
public MeshTree childOrThrow(String name) {
|
||||||
|
@ -119,7 +139,7 @@ public final class MeshTree {
|
||||||
if (mesh != null) {
|
if (mesh != null) {
|
||||||
consumer.accept(mesh);
|
consumer.accept(mesh);
|
||||||
}
|
}
|
||||||
for (MeshTree child : children.values()) {
|
for (MeshTree child : children) {
|
||||||
child.traverse(consumer);
|
child.traverse(consumer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ public class RecyclingPoseStack extends PoseStack {
|
||||||
super.pushPose();
|
super.pushPose();
|
||||||
} else {
|
} else {
|
||||||
var last = last();
|
var last = last();
|
||||||
var recycle = recycleBin.pop();
|
var recycle = recycleBin.removeLast();
|
||||||
recycle.pose()
|
recycle.pose()
|
||||||
.set(last.pose());
|
.set(last.pose());
|
||||||
recycle.normal()
|
recycle.normal()
|
||||||
|
@ -36,7 +36,7 @@ public class RecyclingPoseStack extends PoseStack {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void popPose() {
|
public void popPose() {
|
||||||
recycleBin.push(FlwLibLink.INSTANCE.getPoseStack(this)
|
recycleBin.addLast(FlwLibLink.INSTANCE.getPoseStack(this)
|
||||||
.removeLast());
|
.removeLast());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue